1 /* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. 2 * 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions are 5 * met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer in the documentation and/or other materials provided 11 * with the distribution. 12 * * Neither the name of The Linux Foundation nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30 #define ATRACE_TAG ATRACE_TAG_CAMERA 31 32 #include <pthread.h> 33 #include <errno.h> 34 #include <sys/ioctl.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <sys/prctl.h> 38 #include <fcntl.h> 39 #include <poll.h> 40 #include <cutils/trace.h> 41 #include <math.h> 42 43 #include "mm_jpeg_dbg.h" 44 #include "mm_jpeg_interface.h" 45 #include "mm_jpeg.h" 46 #include "mm_jpeg_inlines.h" 47 48 #ifdef LOAD_ADSP_RPC_LIB 49 #include <dlfcn.h> 50 #include <stdlib.h> 51 #endif 52 53 #define ENCODING_MODE_PARALLEL 1 54 55 #define META_KEYFILE QCAMERA_DUMP_FRM_LOCATION"metadata.key" 56 57 /** 58 * minimal resolution needed for normal mode of ops 59 */ 60 #define MM_JPEG_MIN_NOM_RESOLUTION 7680000 /*8MP*/ 61 62 #ifdef MM_JPEG_USE_PIPELINE 63 #undef MM_JPEG_CONCURRENT_SESSIONS_COUNT 64 #define MM_JPEG_CONCURRENT_SESSIONS_COUNT 1 65 #endif 66 67 OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent, 68 OMX_PTR pAppData, 69 OMX_BUFFERHEADERTYPE* pBuffer); 70 OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent, 71 OMX_PTR pAppData, 72 OMX_BUFFERHEADERTYPE* pBuffer); 73 OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent, 74 OMX_PTR pAppData, 75 OMX_EVENTTYPE eEvent, 76 OMX_U32 nData1, 77 OMX_U32 nData2, 78 OMX_PTR pEventData); 79 80 static int32_t mm_jpegenc_destroy_job(mm_jpeg_job_session_t *p_session); 81 static void mm_jpegenc_job_done(mm_jpeg_job_session_t *p_session); 82 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_dst_ptr( 83 mm_jpeg_queue_t* queue, void * dst_ptr); 84 static OMX_ERRORTYPE mm_jpeg_session_configure(mm_jpeg_job_session_t *p_session); 85 86 /** mm_jpeg_session_send_buffers: 87 * 88 * Arguments: 89 * @data: job session 90 * 91 * Return: 92 * OMX error values 93 * 94 * Description: 95 * Send the buffers to OMX layer 96 * 97 **/ 98 OMX_ERRORTYPE mm_jpeg_session_send_buffers(void *data) 99 { 100 uint32_t i = 0; 101 mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data; 102 OMX_ERRORTYPE ret = OMX_ErrorNone; 103 QOMX_BUFFER_INFO lbuffer_info; 104 mm_jpeg_encode_params_t *p_params = &p_session->params; 105 106 memset(&lbuffer_info, 0x0, sizeof(QOMX_BUFFER_INFO)); 107 for (i = 0; i < p_params->num_src_bufs; i++) { 108 CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i); 109 lbuffer_info.fd = (OMX_U32)p_params->src_main_buf[i].fd; 110 ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_in_omx_buf[i]), 0, 111 &lbuffer_info, p_params->src_main_buf[i].buf_size, 112 p_params->src_main_buf[i].buf_vaddr); 113 if (ret) { 114 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 115 return ret; 116 } 117 } 118 119 for (i = 0; i < p_params->num_tmb_bufs; i++) { 120 CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i); 121 lbuffer_info.fd = (OMX_U32)p_params->src_thumb_buf[i].fd; 122 ret = OMX_UseBuffer(p_session->omx_handle, 123 &(p_session->p_in_omx_thumb_buf[i]), 2, 124 &lbuffer_info, p_params->src_thumb_buf[i].buf_size, 125 p_params->src_thumb_buf[i].buf_vaddr); 126 if (ret) { 127 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 128 return ret; 129 } 130 } 131 132 for (i = 0; i < p_params->num_dst_bufs; i++) { 133 CDBG("%s:%d] Dest buffer %d", __func__, __LINE__, i); 134 ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_out_omx_buf[i]), 135 1, NULL, p_params->dest_buf[i].buf_size, 136 p_params->dest_buf[i].buf_vaddr); 137 if (ret) { 138 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 139 return ret; 140 } 141 } 142 CDBG("%s:%d]", __func__, __LINE__); 143 return ret; 144 } 145 146 147 /** mm_jpeg_session_free_buffers: 148 * 149 * Arguments: 150 * @data: job session 151 * 152 * Return: 153 * OMX error values 154 * 155 * Description: 156 * Free the buffers from OMX layer 157 * 158 **/ 159 OMX_ERRORTYPE mm_jpeg_session_free_buffers(void *data) 160 { 161 OMX_ERRORTYPE ret = OMX_ErrorNone; 162 uint32_t i = 0; 163 mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data; 164 mm_jpeg_encode_params_t *p_params = &p_session->params; 165 166 for (i = 0; i < p_params->num_src_bufs; i++) { 167 CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i); 168 ret = OMX_FreeBuffer(p_session->omx_handle, 0, p_session->p_in_omx_buf[i]); 169 if (ret) { 170 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 171 return ret; 172 } 173 } 174 175 for (i = 0; i < p_params->num_tmb_bufs; i++) { 176 CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i); 177 ret = OMX_FreeBuffer(p_session->omx_handle, 2, p_session->p_in_omx_thumb_buf[i]); 178 if (ret) { 179 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 180 return ret; 181 } 182 } 183 184 for (i = 0; i < p_params->num_dst_bufs; i++) { 185 CDBG("%s:%d] Dest buffer %d", __func__, __LINE__, i); 186 ret = OMX_FreeBuffer(p_session->omx_handle, 1, p_session->p_out_omx_buf[i]); 187 if (ret) { 188 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 189 return ret; 190 } 191 } 192 CDBG("%s:%d]", __func__, __LINE__); 193 return ret; 194 } 195 196 197 198 199 /** mm_jpeg_session_change_state: 200 * 201 * Arguments: 202 * @p_session: job session 203 * @new_state: new state to be transitioned to 204 * @p_exec: transition function 205 * 206 * Return: 207 * OMX error values 208 * 209 * Description: 210 * This method is used for state transition 211 * 212 **/ 213 OMX_ERRORTYPE mm_jpeg_session_change_state(mm_jpeg_job_session_t* p_session, 214 OMX_STATETYPE new_state, 215 mm_jpeg_transition_func_t p_exec) 216 { 217 OMX_ERRORTYPE ret = OMX_ErrorNone; 218 OMX_STATETYPE current_state; 219 CDBG("%s:%d] new_state %d p_exec %p", __func__, __LINE__, 220 new_state, p_exec); 221 222 223 pthread_mutex_lock(&p_session->lock); 224 225 ret = OMX_GetState(p_session->omx_handle, ¤t_state); 226 227 if (ret) { 228 pthread_mutex_unlock(&p_session->lock); 229 return ret; 230 } 231 232 if (current_state == new_state) { 233 pthread_mutex_unlock(&p_session->lock); 234 return OMX_ErrorNone; 235 } 236 237 p_session->state_change_pending = OMX_TRUE; 238 pthread_mutex_unlock(&p_session->lock); 239 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet, 240 new_state, NULL); 241 pthread_mutex_lock(&p_session->lock); 242 if (ret) { 243 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 244 pthread_mutex_unlock(&p_session->lock); 245 return OMX_ErrorIncorrectStateTransition; 246 } 247 CDBG("%s:%d] ", __func__, __LINE__); 248 if ((OMX_ErrorNone != p_session->error_flag) && 249 (OMX_ErrorOverflow != p_session->error_flag)) { 250 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, p_session->error_flag); 251 pthread_mutex_unlock(&p_session->lock); 252 return p_session->error_flag; 253 } 254 if (p_exec) { 255 ret = p_exec(p_session); 256 if (ret) { 257 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 258 pthread_mutex_unlock(&p_session->lock); 259 return ret; 260 } 261 } 262 CDBG("%s:%d] ", __func__, __LINE__); 263 if (p_session->state_change_pending) { 264 CDBG("%s:%d] before wait", __func__, __LINE__); 265 pthread_cond_wait(&p_session->cond, &p_session->lock); 266 CDBG("%s:%d] after wait", __func__, __LINE__); 267 } 268 pthread_mutex_unlock(&p_session->lock); 269 CDBG("%s:%d] ", __func__, __LINE__); 270 return ret; 271 } 272 273 /** mm_jpeg_session_create: 274 * 275 * Arguments: 276 * @p_session: job session 277 * 278 * Return: 279 * OMX error types 280 * 281 * Description: 282 * Create a jpeg encode session 283 * 284 **/ 285 OMX_ERRORTYPE mm_jpeg_session_create(mm_jpeg_job_session_t* p_session) 286 { 287 OMX_ERRORTYPE rc = OMX_ErrorNone; 288 mm_jpeg_obj *my_obj = (mm_jpeg_obj *) p_session->jpeg_obj; 289 char *omx_lib = "OMX.qcom.image.jpeg.encoder"; 290 291 pthread_mutex_init(&p_session->lock, NULL); 292 pthread_cond_init(&p_session->cond, NULL); 293 cirq_reset(&p_session->cb_q); 294 p_session->state_change_pending = OMX_FALSE; 295 p_session->abort_state = MM_JPEG_ABORT_NONE; 296 p_session->error_flag = OMX_ErrorNone; 297 p_session->ebd_count = 0; 298 p_session->fbd_count = 0; 299 p_session->encode_pid = -1; 300 p_session->config = OMX_FALSE; 301 p_session->exif_count_local = 0; 302 p_session->auto_out_buf = OMX_FALSE; 303 304 p_session->omx_callbacks.EmptyBufferDone = mm_jpeg_ebd; 305 p_session->omx_callbacks.FillBufferDone = mm_jpeg_fbd; 306 p_session->omx_callbacks.EventHandler = mm_jpeg_event_handler; 307 308 p_session->thumb_from_main = 0; 309 #ifdef MM_JPEG_USE_PIPELINE 310 p_session->thumb_from_main = 1; 311 omx_lib = "OMX.qcom.image.jpeg.encoder_pipeline"; 312 #endif 313 314 rc = OMX_GetHandle(&p_session->omx_handle, 315 omx_lib, 316 (void *)p_session, 317 &p_session->omx_callbacks); 318 if (OMX_ErrorNone != rc) { 319 CDBG_ERROR("%s:%d] OMX_GetHandle failed (%d)", __func__, __LINE__, rc); 320 return rc; 321 } 322 323 my_obj->num_sessions++; 324 325 return rc; 326 } 327 328 329 330 /** mm_jpeg_session_destroy: 331 * 332 * Arguments: 333 * @p_session: job session 334 * 335 * Return: 336 * none 337 * 338 * Description: 339 * Destroy a jpeg encode session 340 * 341 **/ 342 void mm_jpeg_session_destroy(mm_jpeg_job_session_t* p_session) 343 { 344 OMX_ERRORTYPE rc = OMX_ErrorNone; 345 OMX_STATETYPE state; 346 mm_jpeg_obj *my_obj = (mm_jpeg_obj *) p_session->jpeg_obj; 347 348 CDBG("%s:%d] E", __func__, __LINE__); 349 if (NULL == p_session->omx_handle) { 350 CDBG_ERROR("%s:%d] invalid handle", __func__, __LINE__); 351 return; 352 } 353 354 rc = OMX_GetState(p_session->omx_handle, &state); 355 356 //Check state before state transition 357 if ((state == OMX_StateExecuting) || (state == OMX_StatePause)) { 358 rc = mm_jpeg_session_change_state(p_session, OMX_StateIdle, NULL); 359 if (rc) { 360 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 361 } 362 } 363 364 rc = OMX_GetState(p_session->omx_handle, &state); 365 366 if (state == OMX_StateIdle) { 367 rc = mm_jpeg_session_change_state(p_session, OMX_StateLoaded, 368 mm_jpeg_session_free_buffers); 369 if (rc) { 370 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 371 } 372 } 373 374 rc = OMX_FreeHandle(p_session->omx_handle); 375 if (0 != rc) { 376 CDBG_ERROR("%s:%d] OMX_FreeHandle failed (%d)", __func__, __LINE__, rc); 377 } 378 p_session->omx_handle = NULL; 379 380 pthread_mutex_destroy(&p_session->lock); 381 pthread_cond_destroy(&p_session->cond); 382 383 if (NULL != p_session->meta_enc_key) { 384 free(p_session->meta_enc_key); 385 p_session->meta_enc_key = NULL; 386 } 387 388 my_obj->num_sessions--; 389 390 // Destroy next session 391 if (p_session->next_session) { 392 mm_jpeg_session_destroy(p_session->next_session); 393 } 394 395 CDBG_HIGH("%s:%d] Session destroy successful. X", __func__, __LINE__); 396 } 397 398 399 400 /** mm_jpeg_session_config_main_buffer_offset: 401 * 402 * Arguments: 403 * @p_session: job session 404 * 405 * Return: 406 * OMX error values 407 * 408 * Description: 409 * Configure the buffer offsets 410 * 411 **/ 412 OMX_ERRORTYPE mm_jpeg_session_config_main_buffer_offset( 413 mm_jpeg_job_session_t* p_session) 414 { 415 OMX_ERRORTYPE rc = 0; 416 OMX_INDEXTYPE buffer_index; 417 QOMX_YUV_FRAME_INFO frame_info; 418 size_t totalSize = 0; 419 mm_jpeg_encode_params_t *p_params = &p_session->params; 420 421 mm_jpeg_buf_t *p_src_buf = 422 &p_params->src_main_buf[0]; 423 424 memset(&frame_info, 0x0, sizeof(QOMX_YUV_FRAME_INFO)); 425 426 frame_info.cbcrStartOffset[0] = p_src_buf->offset.mp[0].len; 427 frame_info.cbcrStartOffset[1] = p_src_buf->offset.mp[1].len; 428 frame_info.yOffset = p_src_buf->offset.mp[0].offset; 429 frame_info.cbcrOffset[0] = p_src_buf->offset.mp[1].offset; 430 frame_info.cbcrOffset[1] = p_src_buf->offset.mp[2].offset; 431 totalSize = p_src_buf->buf_size; 432 433 rc = OMX_GetExtensionIndex(p_session->omx_handle, 434 QOMX_IMAGE_EXT_BUFFER_OFFSET_NAME, &buffer_index); 435 if (rc != OMX_ErrorNone) { 436 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 437 return rc; 438 } 439 440 CDBG_HIGH("%s:%d] yOffset = %d, cbcrOffset = (%d %d), totalSize = %zd," 441 "cbcrStartOffset = (%d %d)", __func__, __LINE__, 442 (int)frame_info.yOffset, 443 (int)frame_info.cbcrOffset[0], 444 (int)frame_info.cbcrOffset[1], 445 totalSize, 446 (int)frame_info.cbcrStartOffset[0], 447 (int)frame_info.cbcrStartOffset[1]); 448 449 rc = OMX_SetParameter(p_session->omx_handle, buffer_index, &frame_info); 450 if (rc != OMX_ErrorNone) { 451 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 452 return rc; 453 } 454 return rc; 455 } 456 457 /** mm_jpeg_encoding_mode: 458 * 459 * Arguments: 460 * @p_session: job session 461 * 462 * Return: 463 * OMX error values 464 * 465 * Description: 466 * Configure the serial or parallel encoding 467 * mode 468 * 469 **/ 470 OMX_ERRORTYPE mm_jpeg_encoding_mode( 471 mm_jpeg_job_session_t* p_session) 472 { 473 OMX_ERRORTYPE rc = 0; 474 OMX_INDEXTYPE indextype; 475 QOMX_ENCODING_MODE encoding_mode; 476 477 rc = OMX_GetExtensionIndex(p_session->omx_handle, 478 QOMX_IMAGE_EXT_ENCODING_MODE_NAME, &indextype); 479 if (rc != OMX_ErrorNone) { 480 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 481 return rc; 482 } 483 484 if (ENCODING_MODE_PARALLEL) { 485 encoding_mode = OMX_Parallel_Encoding; 486 } else { 487 encoding_mode = OMX_Serial_Encoding; 488 } 489 CDBG("%s:%d] encoding mode = %d ", __func__, __LINE__, 490 (int)encoding_mode); 491 rc = OMX_SetParameter(p_session->omx_handle, indextype, &encoding_mode); 492 if (rc != OMX_ErrorNone) { 493 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 494 return rc; 495 } 496 return rc; 497 } 498 499 /** mm_jpeg_get_speed: 500 * 501 * Arguments: 502 * @p_session: job session 503 * 504 * Return: 505 * ops speed type for jpeg 506 * 507 * Description: 508 * Configure normal or high speed jpeg 509 * 510 **/ 511 QOMX_JPEG_SPEED_MODE mm_jpeg_get_speed( 512 mm_jpeg_job_session_t* p_session) 513 { 514 mm_jpeg_encode_params_t *p_params = &p_session->params; 515 cam_dimension_t *p_dim = &p_params->main_dim.src_dim; 516 if (p_params->burst_mode || 517 (MM_JPEG_MIN_NOM_RESOLUTION < (p_dim->width * p_dim->height))) { 518 return QOMX_JPEG_SPEED_MODE_HIGH; 519 } 520 return QOMX_JPEG_SPEED_MODE_NORMAL; 521 } 522 523 /** mm_jpeg_speed_mode: 524 * 525 * Arguments: 526 * @p_session: job session 527 * 528 * Return: 529 * OMX error values 530 * 531 * Description: 532 * Configure normal or high speed jpeg 533 * 534 **/ 535 OMX_ERRORTYPE mm_jpeg_speed_mode( 536 mm_jpeg_job_session_t* p_session) 537 { 538 OMX_ERRORTYPE rc = 0; 539 OMX_INDEXTYPE indextype; 540 QOMX_JPEG_SPEED jpeg_speed; 541 542 rc = OMX_GetExtensionIndex(p_session->omx_handle, 543 QOMX_IMAGE_EXT_JPEG_SPEED_NAME, &indextype); 544 if (rc != OMX_ErrorNone) { 545 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 546 return rc; 547 } 548 549 jpeg_speed.speedMode = mm_jpeg_get_speed(p_session); 550 CDBG_HIGH("%s:%d] speed %d", __func__, __LINE__, jpeg_speed.speedMode); 551 552 rc = OMX_SetParameter(p_session->omx_handle, indextype, &jpeg_speed); 553 if (rc != OMX_ErrorNone) { 554 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 555 return rc; 556 } 557 return rc; 558 } 559 560 561 /** mm_jpeg_mem_ops: 562 * 563 * Arguments: 564 * @p_session: job session 565 * 566 * Return: 567 * OMX error values 568 * 569 * Description: 570 * Configure the serial or parallel encoding 571 * mode 572 * 573 **/ 574 OMX_ERRORTYPE mm_jpeg_mem_ops( 575 mm_jpeg_job_session_t* p_session) 576 { 577 OMX_ERRORTYPE rc = 0; 578 OMX_INDEXTYPE indextype; 579 QOMX_MEM_OPS mem_ops; 580 mm_jpeg_encode_params_t *p_params = &p_session->params; 581 582 mem_ops.get_memory = p_params->get_memory; 583 584 rc = OMX_GetExtensionIndex(p_session->omx_handle, 585 QOMX_IMAGE_EXT_MEM_OPS_NAME, &indextype); 586 if (rc != OMX_ErrorNone) { 587 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 588 return rc; 589 } 590 591 rc = OMX_SetParameter(p_session->omx_handle, indextype, &mem_ops); 592 if (rc != OMX_ErrorNone) { 593 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 594 return rc; 595 } 596 return rc; 597 } 598 599 /** mm_jpeg_metadata: 600 * 601 * Arguments: 602 * @p_session: job session 603 * 604 * Return: 605 * OMX error values 606 * 607 * Description: 608 * Pass meta data 609 * 610 **/ 611 OMX_ERRORTYPE mm_jpeg_metadata( 612 mm_jpeg_job_session_t* p_session) 613 { 614 OMX_ERRORTYPE rc = OMX_ErrorNone; 615 OMX_INDEXTYPE indexType; 616 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 617 QOMX_METADATA lMeta; 618 619 rc = OMX_GetExtensionIndex(p_session->omx_handle, 620 QOMX_IMAGE_EXT_METADATA_NAME, &indexType); 621 622 if (rc != OMX_ErrorNone) { 623 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 624 return rc; 625 } 626 627 lMeta.metadata = (OMX_U8 *)p_jobparams->p_metadata; 628 lMeta.metaPayloadSize = sizeof(*p_jobparams->p_metadata); 629 lMeta.mobicat_mask = p_jobparams->mobicat_mask; 630 631 rc = OMX_SetConfig(p_session->omx_handle, indexType, &lMeta); 632 if (rc != OMX_ErrorNone) { 633 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 634 return rc; 635 } 636 return OMX_ErrorNone; 637 } 638 639 /** mm_jpeg_meta_enc_key: 640 * 641 * Arguments: 642 * @p_session: job session 643 * 644 * Return: 645 * OMX error values 646 * 647 * Description: 648 * Pass metadata encrypt key 649 * 650 **/ 651 OMX_ERRORTYPE mm_jpeg_meta_enc_key( 652 mm_jpeg_job_session_t* p_session) 653 { 654 OMX_ERRORTYPE rc = OMX_ErrorNone; 655 OMX_INDEXTYPE indexType; 656 QOMX_META_ENC_KEY lKey; 657 658 lKey.metaKey = p_session->meta_enc_key; 659 lKey.keyLen = p_session->meta_enc_keylen; 660 661 if ((!lKey.metaKey) || (!lKey.keyLen)){ 662 CDBG_ERROR("%s:%d] Key is invalid", __func__, __LINE__); 663 return OMX_ErrorNone; 664 } 665 666 rc = OMX_GetExtensionIndex(p_session->omx_handle, 667 QOMX_IMAGE_EXT_META_ENC_KEY_NAME, &indexType); 668 669 if (rc != OMX_ErrorNone) { 670 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 671 return rc; 672 } 673 674 rc = OMX_SetConfig(p_session->omx_handle, indexType, &lKey); 675 if (rc != OMX_ErrorNone) { 676 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 677 return rc; 678 } 679 return OMX_ErrorNone; 680 } 681 682 /** map_jpeg_format: 683 * 684 * Arguments: 685 * @color_fmt: color format 686 * 687 * Return: 688 * OMX color format 689 * 690 * Description: 691 * Map mmjpeg color format to OMX color format 692 * 693 **/ 694 int map_jpeg_format(mm_jpeg_color_format color_fmt) 695 { 696 switch (color_fmt) { 697 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2: 698 return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar; 699 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2: 700 return (int)OMX_COLOR_FormatYUV420SemiPlanar; 701 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1: 702 return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar; 703 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1: 704 return (int)OMX_COLOR_FormatYUV422SemiPlanar; 705 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V2: 706 return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar_h1v2; 707 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V2: 708 return (int)OMX_QCOM_IMG_COLOR_FormatYUV422SemiPlanar_h1v2; 709 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V1: 710 return (int)OMX_QCOM_IMG_COLOR_FormatYVU444SemiPlanar; 711 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V1: 712 return (int)OMX_QCOM_IMG_COLOR_FormatYUV444SemiPlanar; 713 case MM_JPEG_COLOR_FORMAT_MONOCHROME: 714 return (int)OMX_COLOR_FormatMonochrome; 715 default: 716 CDBG_ERROR("%s:%d] invalid format %d", __func__, __LINE__, color_fmt); 717 return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar; 718 } 719 } 720 721 /** mm_jpeg_session_config_port: 722 * 723 * Arguments: 724 * @p_session: job session 725 * 726 * Return: 727 * OMX error values 728 * 729 * Description: 730 * Configure OMX ports 731 * 732 **/ 733 OMX_ERRORTYPE mm_jpeg_session_config_ports(mm_jpeg_job_session_t* p_session) 734 { 735 OMX_ERRORTYPE ret = OMX_ErrorNone; 736 mm_jpeg_encode_params_t *p_params = &p_session->params; 737 OMX_CONFIG_ROTATIONTYPE rotate; 738 739 mm_jpeg_buf_t *p_src_buf = 740 &p_params->src_main_buf[0]; 741 742 p_session->inputPort.nPortIndex = 0; 743 p_session->outputPort.nPortIndex = 1; 744 p_session->inputTmbPort.nPortIndex = 2; 745 746 ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 747 &p_session->inputPort); 748 if (ret) { 749 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 750 return ret; 751 } 752 753 ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 754 &p_session->inputTmbPort); 755 if (ret) { 756 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 757 return ret; 758 } 759 760 ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 761 &p_session->outputPort); 762 if (ret) { 763 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 764 return ret; 765 } 766 767 p_session->inputPort.format.image.nFrameWidth = 768 (OMX_U32)p_params->main_dim.src_dim.width; 769 p_session->inputPort.format.image.nFrameHeight = 770 (OMX_U32)p_params->main_dim.src_dim.height; 771 p_session->inputPort.format.image.nStride = 772 p_src_buf->offset.mp[0].stride; 773 p_session->inputPort.format.image.nSliceHeight = 774 (OMX_U32)p_src_buf->offset.mp[0].scanline; 775 p_session->inputPort.format.image.eColorFormat = 776 map_jpeg_format(p_params->color_format); 777 p_session->inputPort.nBufferSize = 778 p_params->src_main_buf[0/*p_jobparams->src_index*/].buf_size; 779 p_session->inputPort.nBufferCountActual = (OMX_U32)p_params->num_src_bufs; 780 ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 781 &p_session->inputPort); 782 if (ret) { 783 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 784 return ret; 785 } 786 787 if (p_session->params.encode_thumbnail) { 788 mm_jpeg_buf_t *p_tmb_buf = 789 &p_params->src_thumb_buf[0]; 790 p_session->inputTmbPort.format.image.nFrameWidth = 791 (OMX_U32)p_params->thumb_dim.src_dim.width; 792 p_session->inputTmbPort.format.image.nFrameHeight = 793 (OMX_U32)p_params->thumb_dim.src_dim.height; 794 p_session->inputTmbPort.format.image.nStride = 795 p_tmb_buf->offset.mp[0].stride; 796 p_session->inputTmbPort.format.image.nSliceHeight = 797 (OMX_U32)p_tmb_buf->offset.mp[0].scanline; 798 p_session->inputTmbPort.format.image.eColorFormat = 799 map_jpeg_format(p_params->thumb_color_format); 800 p_session->inputTmbPort.nBufferSize = 801 p_params->src_thumb_buf[0].buf_size; 802 p_session->inputTmbPort.nBufferCountActual = (OMX_U32)p_params->num_tmb_bufs; 803 804 ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 805 &p_session->inputTmbPort); 806 807 if (ret) { 808 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 809 return ret; 810 } 811 812 // Enable thumbnail port 813 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortEnable, 814 p_session->inputTmbPort.nPortIndex, NULL); 815 816 if (ret) { 817 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 818 return ret; 819 } 820 } else { 821 // Disable thumbnail port 822 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortDisable, 823 p_session->inputTmbPort.nPortIndex, NULL); 824 825 if (ret) { 826 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 827 return ret; 828 } 829 } 830 831 p_session->outputPort.nBufferSize = 832 p_params->dest_buf[0].buf_size; 833 p_session->outputPort.nBufferCountActual = (OMX_U32)p_params->num_dst_bufs; 834 ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 835 &p_session->outputPort); 836 if (ret) { 837 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 838 return ret; 839 } 840 841 /* set rotation */ 842 memset(&rotate, 0, sizeof(rotate)); 843 rotate.nPortIndex = 1; 844 rotate.nRotation = (OMX_S32)p_params->rotation; 845 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonRotate, 846 &rotate); 847 if (OMX_ErrorNone != ret) { 848 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 849 return ret; 850 } 851 CDBG("%s:%d] Set rotation to %d at port_idx = %d", __func__, __LINE__, 852 (int)p_params->rotation, (int)rotate.nPortIndex); 853 854 return ret; 855 } 856 857 /** mm_jpeg_get_thumbnail_crop 858 * 859 * Arguments: 860 * @p_thumb_dim: thumbnail dimension 861 * @p_main_dim: main image dimension 862 * @crop_width : flag indicating if width needs to be cropped 863 * 864 * Return: 865 * OMX error values 866 * 867 * Description: 868 * If the main image and thumbnail ascpect ratios are differnt, 869 * re-calculate the thumbnail crop info to prevent distortion 870 * 871 */ 872 OMX_ERRORTYPE mm_jpeg_get_thumbnail_crop(mm_jpeg_dim_t *p_thumb_dim, 873 mm_jpeg_dim_t *p_main_dim, uint8_t crop_width) { 874 OMX_ERRORTYPE ret = OMX_ErrorNone; 875 int cropped_width = 0, cropped_height = 0; 876 877 if (crop_width) { 878 //Keep height constant 879 cropped_height = p_thumb_dim->src_dim.height; 880 cropped_width = floor((cropped_height * p_thumb_dim->dst_dim.width) / 881 p_thumb_dim->dst_dim.height); 882 } else { 883 //Keep width constant 884 cropped_width = p_thumb_dim->src_dim.width; 885 cropped_height = floor((cropped_width * p_thumb_dim->dst_dim.height) / 886 p_thumb_dim->dst_dim.width); 887 } 888 p_thumb_dim->crop.left = floor(p_thumb_dim->src_dim.width - cropped_width) / 2; 889 p_thumb_dim->crop.top = floor(p_thumb_dim->src_dim.height - cropped_height) / 2; 890 p_thumb_dim->crop.width = cropped_width; 891 p_thumb_dim->crop.height = cropped_height; 892 893 CDBG_HIGH("%s %d New thumbnail crop: left %d, top %d, crop width %d, crop height %d", 894 __func__, __LINE__, p_thumb_dim->crop.left, p_thumb_dim->crop.top, 895 p_thumb_dim->crop.width, p_thumb_dim->crop.height); 896 897 return ret; 898 } 899 900 /** mm_jpeg_omx_config_thumbnail: 901 * 902 * Arguments: 903 * @p_session: job session 904 * 905 * Return: 906 * OMX error values 907 * 908 * Description: 909 * Configure OMX ports 910 * 911 **/ 912 OMX_ERRORTYPE mm_jpeg_session_config_thumbnail(mm_jpeg_job_session_t* p_session) 913 { 914 OMX_ERRORTYPE ret = OMX_ErrorNone; 915 QOMX_THUMBNAIL_INFO thumbnail_info; 916 OMX_INDEXTYPE thumb_indextype; 917 mm_jpeg_encode_params_t *p_params = &p_session->params; 918 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 919 mm_jpeg_dim_t *p_thumb_dim = &p_jobparams->thumb_dim; 920 mm_jpeg_dim_t *p_main_dim = &p_jobparams->main_dim; 921 QOMX_YUV_FRAME_INFO *p_frame_info = &thumbnail_info.tmbOffset; 922 mm_jpeg_buf_t *p_tmb_buf = &p_params->src_thumb_buf[p_jobparams->thumb_index]; 923 924 CDBG_HIGH("%s:%d] encode_thumbnail %u", __func__, __LINE__, 925 p_params->encode_thumbnail); 926 if (OMX_FALSE == p_params->encode_thumbnail) { 927 return ret; 928 } 929 930 if ((p_thumb_dim->dst_dim.width == 0) || (p_thumb_dim->dst_dim.height == 0)) { 931 CDBG_ERROR("%s:%d] Error invalid output dim for thumbnail", 932 __func__, __LINE__); 933 return OMX_ErrorBadParameter; 934 } 935 936 if ((p_thumb_dim->src_dim.width == 0) || (p_thumb_dim->src_dim.height == 0)) { 937 CDBG_ERROR("%s:%d] Error invalid input dim for thumbnail", 938 __func__, __LINE__); 939 return OMX_ErrorBadParameter; 940 } 941 942 if ((p_thumb_dim->crop.width == 0) || (p_thumb_dim->crop.height == 0)) { 943 p_thumb_dim->crop.width = p_thumb_dim->src_dim.width; 944 p_thumb_dim->crop.height = p_thumb_dim->src_dim.height; 945 } 946 947 /* check crop boundary */ 948 if ((p_thumb_dim->crop.width + p_thumb_dim->crop.left > p_thumb_dim->src_dim.width) || 949 (p_thumb_dim->crop.height + p_thumb_dim->crop.top > p_thumb_dim->src_dim.height)) { 950 CDBG_ERROR("%s:%d] invalid crop boundary (%d, %d) offset (%d, %d) out of (%d, %d)", 951 __func__, __LINE__, 952 p_thumb_dim->crop.width, 953 p_thumb_dim->crop.height, 954 p_thumb_dim->crop.left, 955 p_thumb_dim->crop.top, 956 p_thumb_dim->src_dim.width, 957 p_thumb_dim->src_dim.height); 958 return OMX_ErrorBadParameter; 959 } 960 961 memset(&thumbnail_info, 0x0, sizeof(QOMX_THUMBNAIL_INFO)); 962 ret = OMX_GetExtensionIndex(p_session->omx_handle, 963 QOMX_IMAGE_EXT_THUMBNAIL_NAME, 964 &thumb_indextype); 965 if (ret) { 966 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 967 return ret; 968 } 969 970 /* fill thumbnail info */ 971 thumbnail_info.scaling_enabled = 1; 972 thumbnail_info.input_width = (OMX_U32)p_thumb_dim->src_dim.width; 973 thumbnail_info.input_height = (OMX_U32)p_thumb_dim->src_dim.height; 974 thumbnail_info.rotation = (OMX_U32)p_params->thumb_rotation; 975 thumbnail_info.quality = (OMX_U32)p_params->thumb_quality; 976 thumbnail_info.output_width = (OMX_U32)p_thumb_dim->dst_dim.width; 977 thumbnail_info.output_height = (OMX_U32)p_thumb_dim->dst_dim.height; 978 979 if (p_session->thumb_from_main) { 980 if ((p_session->params.thumb_rotation == 90 || 981 p_session->params.thumb_rotation == 270) && 982 (p_session->params.rotation == 0 || 983 p_session->params.rotation == 180)) { 984 985 thumbnail_info.output_width = (OMX_U32)p_thumb_dim->dst_dim.height; 986 thumbnail_info.output_height = (OMX_U32)p_thumb_dim->dst_dim.width; 987 thumbnail_info.rotation = p_session->params.rotation; 988 } 989 } else if ((p_thumb_dim->dst_dim.width > p_thumb_dim->src_dim.width) || 990 (p_thumb_dim->dst_dim.height > p_thumb_dim->src_dim.height)) { 991 CDBG_ERROR("%s:%d] Incorrect thumbnail dim %dx%d resetting to %dx%d", 992 __func__, __LINE__, p_thumb_dim->dst_dim.width, 993 p_thumb_dim->dst_dim.height, p_thumb_dim->src_dim.width, 994 p_thumb_dim->src_dim.height); 995 thumbnail_info.output_width = (OMX_U32)p_thumb_dim->src_dim.width; 996 thumbnail_info.output_height = (OMX_U32)p_thumb_dim->src_dim.height; 997 } 998 999 //If the main image and thumbnail aspect ratio are different, reset the 1000 // thumbnail crop info to avoid distortion 1001 double main_aspect_ratio = (double)p_main_dim->dst_dim.width / 1002 (double)p_main_dim->dst_dim.height; 1003 double thumb_aspect_ratio = (double)thumbnail_info.output_width / 1004 (double)thumbnail_info.output_height; 1005 1006 if ((thumb_aspect_ratio - main_aspect_ratio) > ASPECT_TOLERANCE) { 1007 mm_jpeg_get_thumbnail_crop(p_thumb_dim, p_main_dim, 0); 1008 } else if((main_aspect_ratio - thumb_aspect_ratio) > ASPECT_TOLERANCE){ 1009 mm_jpeg_get_thumbnail_crop(p_thumb_dim, p_main_dim, 1); 1010 } 1011 1012 //Fill thumbnail crop info 1013 thumbnail_info.crop_info.nWidth = (OMX_U32)p_thumb_dim->crop.width; 1014 thumbnail_info.crop_info.nHeight = (OMX_U32)p_thumb_dim->crop.height; 1015 thumbnail_info.crop_info.nLeft = p_thumb_dim->crop.left; 1016 thumbnail_info.crop_info.nTop = p_thumb_dim->crop.top; 1017 1018 //If main image cropping/scaling is enabled, thumb FOV should be within 1019 //main image FOV 1020 if ((p_main_dim->crop.width != p_main_dim->src_dim.width) || 1021 (p_main_dim->crop.height != p_main_dim->src_dim.height)) { 1022 if ((p_thumb_dim->crop.left < p_main_dim->crop.left) || 1023 ((p_thumb_dim->crop.left + p_thumb_dim->crop.width) > 1024 (p_main_dim->crop.left + p_main_dim->crop.width)) || 1025 (p_thumb_dim->crop.top < p_main_dim->crop.top) || 1026 ((p_thumb_dim->crop.top + p_thumb_dim->crop.height) > 1027 (p_main_dim->crop.top + p_main_dim->crop.height))) { 1028 //Reset the FOV for the thumbnail 1029 CDBG_HIGH("%s:%d] Resetting the thumbnail FOV wrt main image", 1030 __func__, __LINE__); 1031 thumbnail_info.crop_info.nLeft = p_main_dim->crop.left; 1032 thumbnail_info.crop_info.nTop = p_main_dim->crop.height; 1033 if ((p_thumb_dim->crop.width > p_main_dim->crop.width) || 1034 (p_thumb_dim->crop.height > p_main_dim->crop.height)) { 1035 thumbnail_info.crop_info.nWidth = p_main_dim->crop.width; 1036 thumbnail_info.crop_info.nHeight = p_main_dim->crop.height; 1037 } 1038 } 1039 } 1040 1041 memset(p_frame_info, 0x0, sizeof(*p_frame_info)); 1042 1043 p_frame_info->cbcrStartOffset[0] = p_tmb_buf->offset.mp[0].len; 1044 p_frame_info->cbcrStartOffset[1] = p_tmb_buf->offset.mp[1].len; 1045 p_frame_info->yOffset = p_tmb_buf->offset.mp[0].offset; 1046 p_frame_info->cbcrOffset[0] = p_tmb_buf->offset.mp[1].offset; 1047 p_frame_info->cbcrOffset[1] = p_tmb_buf->offset.mp[2].offset; 1048 1049 ret = OMX_SetConfig(p_session->omx_handle, thumb_indextype, 1050 &thumbnail_info); 1051 if (ret) { 1052 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1053 return ret; 1054 } 1055 1056 return ret; 1057 } 1058 1059 /** mm_jpeg_session_config_main_crop: 1060 * 1061 * Arguments: 1062 * @p_session: job session 1063 * 1064 * Return: 1065 * OMX error values 1066 * 1067 * Description: 1068 * Configure main image crop 1069 * 1070 **/ 1071 OMX_ERRORTYPE mm_jpeg_session_config_main_crop(mm_jpeg_job_session_t *p_session) 1072 { 1073 OMX_CONFIG_RECTTYPE rect_type_in, rect_type_out; 1074 OMX_ERRORTYPE ret = OMX_ErrorNone; 1075 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1076 mm_jpeg_dim_t *dim = &p_jobparams->main_dim; 1077 1078 if ((dim->crop.width == 0) || (dim->crop.height == 0)) { 1079 dim->crop.width = dim->src_dim.width; 1080 dim->crop.height = dim->src_dim.height; 1081 } 1082 /* error check first */ 1083 if ((dim->crop.width + dim->crop.left > dim->src_dim.width) || 1084 (dim->crop.height + dim->crop.top > dim->src_dim.height)) { 1085 CDBG_ERROR("%s:%d] invalid crop boundary (%d, %d) out of (%d, %d)", 1086 __func__, __LINE__, 1087 dim->crop.width + dim->crop.left, 1088 dim->crop.height + dim->crop.top, 1089 dim->src_dim.width, 1090 dim->src_dim.height); 1091 return OMX_ErrorBadParameter; 1092 } 1093 1094 memset(&rect_type_in, 0, sizeof(rect_type_in)); 1095 memset(&rect_type_out, 0, sizeof(rect_type_out)); 1096 rect_type_in.nPortIndex = 0; 1097 rect_type_out.nPortIndex = 0; 1098 1099 if ((dim->src_dim.width != dim->crop.width) || 1100 (dim->src_dim.height != dim->crop.height) || 1101 (dim->src_dim.width != dim->dst_dim.width) || 1102 (dim->src_dim.height != dim->dst_dim.height)) { 1103 /* Scaler information */ 1104 rect_type_in.nWidth = CEILING2(dim->crop.width); 1105 rect_type_in.nHeight = CEILING2(dim->crop.height); 1106 rect_type_in.nLeft = dim->crop.left; 1107 rect_type_in.nTop = dim->crop.top; 1108 1109 if (dim->dst_dim.width && dim->dst_dim.height) { 1110 rect_type_out.nWidth = (OMX_U32)dim->dst_dim.width; 1111 rect_type_out.nHeight = (OMX_U32)dim->dst_dim.height; 1112 } 1113 } 1114 1115 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonInputCrop, 1116 &rect_type_in); 1117 if (OMX_ErrorNone != ret) { 1118 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1119 return ret; 1120 } 1121 1122 CDBG_HIGH("%s:%d] OMX_IndexConfigCommonInputCrop w = %d, h = %d, l = %d, t = %d," 1123 " port_idx = %d", __func__, __LINE__, 1124 (int)rect_type_in.nWidth, (int)rect_type_in.nHeight, 1125 (int)rect_type_in.nLeft, (int)rect_type_in.nTop, 1126 (int)rect_type_in.nPortIndex); 1127 1128 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonOutputCrop, 1129 &rect_type_out); 1130 if (OMX_ErrorNone != ret) { 1131 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1132 return ret; 1133 } 1134 CDBG("%s:%d] OMX_IndexConfigCommonOutputCrop w = %d, h = %d," 1135 " port_idx = %d", __func__, __LINE__, 1136 (int)rect_type_out.nWidth, (int)rect_type_out.nHeight, 1137 (int)rect_type_out.nPortIndex); 1138 1139 return ret; 1140 } 1141 1142 /** mm_jpeg_session_config_main: 1143 * 1144 * Arguments: 1145 * @p_session: job session 1146 * 1147 * Return: 1148 * OMX error values 1149 * 1150 * Description: 1151 * Configure main image 1152 * 1153 **/ 1154 OMX_ERRORTYPE mm_jpeg_session_config_main(mm_jpeg_job_session_t *p_session) 1155 { 1156 OMX_ERRORTYPE rc = OMX_ErrorNone; 1157 1158 /* config port */ 1159 CDBG_HIGH("%s:%d] config port", __func__, __LINE__); 1160 rc = mm_jpeg_session_config_ports(p_session); 1161 if (OMX_ErrorNone != rc) { 1162 CDBG_ERROR("%s: config port failed", __func__); 1163 return rc; 1164 } 1165 1166 /* config buffer offset */ 1167 CDBG("%s:%d] config main buf offset", __func__, __LINE__); 1168 rc = mm_jpeg_session_config_main_buffer_offset(p_session); 1169 if (OMX_ErrorNone != rc) { 1170 CDBG_ERROR("%s: config buffer offset failed", __func__); 1171 return rc; 1172 } 1173 1174 /* set the encoding mode */ 1175 rc = mm_jpeg_encoding_mode(p_session); 1176 if (OMX_ErrorNone != rc) { 1177 CDBG_ERROR("%s: config encoding mode failed", __func__); 1178 return rc; 1179 } 1180 1181 /* set the metadata encrypt key */ 1182 rc = mm_jpeg_meta_enc_key(p_session); 1183 if (OMX_ErrorNone != rc) { 1184 CDBG_ERROR("%s: config session failed", __func__); 1185 return rc; 1186 } 1187 1188 /* set the mem ops */ 1189 rc = mm_jpeg_mem_ops(p_session); 1190 if (OMX_ErrorNone != rc) { 1191 CDBG_ERROR("%s: config mem ops failed", __func__); 1192 return rc; 1193 } 1194 /* set the jpeg speed mode */ 1195 rc = mm_jpeg_speed_mode(p_session); 1196 if (OMX_ErrorNone != rc) { 1197 CDBG_ERROR("%s: config speed mode failed", __func__); 1198 return rc; 1199 } 1200 1201 return rc; 1202 } 1203 1204 /** mm_jpeg_session_config_common: 1205 * 1206 * Arguments: 1207 * @p_session: job session 1208 * 1209 * Return: 1210 * OMX error values 1211 * 1212 * Description: 1213 * Configure common parameters 1214 * 1215 **/ 1216 OMX_ERRORTYPE mm_jpeg_session_config_common(mm_jpeg_job_session_t *p_session) 1217 { 1218 OMX_ERRORTYPE rc = OMX_ErrorNone; 1219 OMX_INDEXTYPE exif_idx; 1220 OMX_CONFIG_ROTATIONTYPE rotate; 1221 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1222 QOMX_EXIF_INFO exif_info; 1223 1224 /* set rotation */ 1225 memset(&rotate, 0, sizeof(rotate)); 1226 rotate.nPortIndex = 1; 1227 rotate.nRotation = (OMX_S32)p_jobparams->rotation; 1228 rc = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonRotate, 1229 &rotate); 1230 if (OMX_ErrorNone != rc) { 1231 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc); 1232 return rc; 1233 } 1234 CDBG("%s:%d] Set rotation to %d at port_idx = %d", __func__, __LINE__, 1235 (int)p_jobparams->rotation, (int)rotate.nPortIndex); 1236 1237 /* Set Exif data*/ 1238 memset(&p_session->exif_info_local[0], 0, sizeof(p_session->exif_info_local)); 1239 rc = OMX_GetExtensionIndex(p_session->omx_handle, QOMX_IMAGE_EXT_EXIF_NAME, 1240 &exif_idx); 1241 if (OMX_ErrorNone != rc) { 1242 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc); 1243 return rc; 1244 } 1245 1246 CDBG("%s:%d] Num of exif entries passed from HAL: %d", __func__, __LINE__, 1247 (int)p_jobparams->exif_info.numOfEntries); 1248 if (p_jobparams->exif_info.numOfEntries > 0) { 1249 rc = OMX_SetConfig(p_session->omx_handle, exif_idx, 1250 &p_jobparams->exif_info); 1251 if (OMX_ErrorNone != rc) { 1252 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc); 1253 return rc; 1254 } 1255 } 1256 /*parse aditional exif data from the metadata*/ 1257 exif_info.numOfEntries = 0; 1258 exif_info.exif_data = &p_session->exif_info_local[0]; 1259 process_meta_data(p_jobparams->p_metadata, &exif_info, 1260 &p_jobparams->cam_exif_params, p_jobparams->hal_version); 1261 /* After Parse metadata */ 1262 p_session->exif_count_local = (int)exif_info.numOfEntries; 1263 1264 if (exif_info.numOfEntries > 0) { 1265 /* set exif tags */ 1266 CDBG("%s:%d] exif tags from metadata count %d", __func__, __LINE__, 1267 (int)exif_info.numOfEntries); 1268 1269 rc = OMX_SetConfig(p_session->omx_handle, exif_idx, 1270 &exif_info); 1271 if (OMX_ErrorNone != rc) { 1272 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc); 1273 return rc; 1274 } 1275 } 1276 1277 return rc; 1278 } 1279 1280 1281 1282 1283 /** mm_jpeg_session_abort: 1284 * 1285 * Arguments: 1286 * @p_session: jpeg session 1287 * 1288 * Return: 1289 * OMX_BOOL 1290 * 1291 * Description: 1292 * Abort ongoing job 1293 * 1294 **/ 1295 OMX_BOOL mm_jpeg_session_abort(mm_jpeg_job_session_t *p_session) 1296 { 1297 OMX_ERRORTYPE ret = OMX_ErrorNone; 1298 int rc = 0; 1299 1300 CDBG("%s:%d] E", __func__, __LINE__); 1301 pthread_mutex_lock(&p_session->lock); 1302 if (MM_JPEG_ABORT_NONE != p_session->abort_state) { 1303 pthread_mutex_unlock(&p_session->lock); 1304 CDBG_HIGH("%s:%d] **** ALREADY ABORTED", __func__, __LINE__); 1305 return 0; 1306 } 1307 p_session->abort_state = MM_JPEG_ABORT_INIT; 1308 if (OMX_TRUE == p_session->encoding) { 1309 p_session->state_change_pending = OMX_TRUE; 1310 1311 CDBG_HIGH("%s:%d] **** ABORTING", __func__, __LINE__); 1312 pthread_mutex_unlock(&p_session->lock); 1313 1314 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet, 1315 OMX_StateIdle, NULL); 1316 1317 if (ret != OMX_ErrorNone) { 1318 CDBG_ERROR("%s:%d] OMX_SendCommand returned error %d", __func__, __LINE__, ret); 1319 return 1; 1320 } 1321 rc = mm_jpegenc_destroy_job(p_session); 1322 if (rc != 0) { 1323 CDBG_ERROR("%s:%d] Destroy job returned error %d", __func__, __LINE__, rc); 1324 } 1325 1326 pthread_mutex_lock(&p_session->lock); 1327 if (MM_JPEG_ABORT_INIT == p_session->abort_state) { 1328 CDBG("%s:%d] before wait", __func__, __LINE__); 1329 pthread_cond_wait(&p_session->cond, &p_session->lock); 1330 } 1331 CDBG("%s:%d] after wait", __func__, __LINE__); 1332 } 1333 p_session->abort_state = MM_JPEG_ABORT_DONE; 1334 pthread_mutex_unlock(&p_session->lock); 1335 1336 1337 // Abort next session 1338 if (p_session->next_session) { 1339 mm_jpeg_session_abort(p_session->next_session); 1340 } 1341 1342 CDBG("%s:%d] X", __func__, __LINE__); 1343 return 0; 1344 } 1345 1346 1347 /** mm_jpeg_configure_params 1348 * 1349 * Arguments: 1350 * @p_session: encode session 1351 * 1352 * Return: 1353 * none 1354 * 1355 * Description: 1356 * Configure the job specific params 1357 * 1358 **/ 1359 static OMX_ERRORTYPE mm_jpeg_configure_job_params( 1360 mm_jpeg_job_session_t *p_session) 1361 { 1362 OMX_ERRORTYPE ret = OMX_ErrorNone; 1363 OMX_IMAGE_PARAM_QFACTORTYPE q_factor; 1364 QOMX_WORK_BUFFER work_buffer; 1365 OMX_INDEXTYPE work_buffer_index; 1366 mm_jpeg_encode_params_t *p_params = &p_session->params; 1367 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1368 int i; 1369 1370 /* common config */ 1371 ret = mm_jpeg_session_config_common(p_session); 1372 if (OMX_ErrorNone != ret) { 1373 CDBG_ERROR("%s:%d] config common failed", __func__, __LINE__); 1374 1375 } 1376 1377 /* config Main Image crop */ 1378 CDBG("%s:%d] config main crop", __func__, __LINE__); 1379 ret = mm_jpeg_session_config_main_crop(p_session); 1380 if (OMX_ErrorNone != ret) { 1381 CDBG_ERROR("%s: config crop failed", __func__); 1382 return ret; 1383 } 1384 1385 /* set quality */ 1386 memset(&q_factor, 0, sizeof(q_factor)); 1387 q_factor.nPortIndex = 0; 1388 q_factor.nQFactor = p_params->quality; 1389 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexParamQFactor, &q_factor); 1390 CDBG("%s:%d] config QFactor: %d", __func__, __LINE__, (int)q_factor.nQFactor); 1391 if (OMX_ErrorNone != ret) { 1392 CDBG_ERROR("%s:%d] Error setting Q factor %d", __func__, __LINE__, ret); 1393 return ret; 1394 } 1395 1396 /* config thumbnail */ 1397 ret = mm_jpeg_session_config_thumbnail(p_session); 1398 if (OMX_ErrorNone != ret) { 1399 CDBG_ERROR("%s:%d] config thumbnail img failed", __func__, __LINE__); 1400 return ret; 1401 } 1402 1403 //Pass the ION buffer to be used as o/p for HW 1404 memset(&work_buffer, 0x0, sizeof(QOMX_WORK_BUFFER)); 1405 ret = OMX_GetExtensionIndex(p_session->omx_handle, 1406 QOMX_IMAGE_EXT_WORK_BUFFER_NAME, 1407 &work_buffer_index); 1408 if (ret) { 1409 CDBG_ERROR("%s:%d] Error getting work buffer index %d", 1410 __func__, __LINE__, ret); 1411 return ret; 1412 } 1413 work_buffer.fd = p_session->work_buffer.p_pmem_fd; 1414 work_buffer.vaddr = p_session->work_buffer.addr; 1415 work_buffer.length = (uint32_t)p_session->work_buffer.size; 1416 CDBG_ERROR("%s:%d] Work buffer info %d %p WorkBufSize: %d invalidate", __func__, __LINE__, 1417 work_buffer.fd, work_buffer.vaddr, work_buffer.length); 1418 1419 buffer_invalidate(&p_session->work_buffer); 1420 1421 ret = OMX_SetConfig(p_session->omx_handle, work_buffer_index, 1422 &work_buffer); 1423 if (ret) { 1424 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1425 return ret; 1426 } 1427 1428 /* set metadata */ 1429 ret = mm_jpeg_metadata(p_session); 1430 if (OMX_ErrorNone != ret) { 1431 CDBG_ERROR("%s: config makernote data failed", __func__); 1432 return ret; 1433 } 1434 1435 /* set QTable */ 1436 for (i = 0; i < QTABLE_MAX; i++) { 1437 if (p_jobparams->qtable_set[i]) { 1438 ret = OMX_SetConfig(p_session->omx_handle, 1439 OMX_IndexParamQuantizationTable, &p_jobparams->qtable[i]); 1440 if (OMX_ErrorNone != ret) { 1441 CDBG_ERROR("%s:%d] set QTable Error", __func__, __LINE__); 1442 return ret; 1443 } 1444 } 1445 } 1446 1447 return ret; 1448 } 1449 1450 /** mm_jpeg_session_configure: 1451 * 1452 * Arguments: 1453 * @data: encode session 1454 * 1455 * Return: 1456 * none 1457 * 1458 * Description: 1459 * Configure the session 1460 * 1461 **/ 1462 static OMX_ERRORTYPE mm_jpeg_session_configure(mm_jpeg_job_session_t *p_session) 1463 { 1464 OMX_ERRORTYPE ret = OMX_ErrorNone; 1465 1466 CDBG("%s:%d] E ", __func__, __LINE__); 1467 1468 MM_JPEG_CHK_ABORT(p_session, ret, error); 1469 1470 /* config main img */ 1471 ret = mm_jpeg_session_config_main(p_session); 1472 if (OMX_ErrorNone != ret) { 1473 CDBG_ERROR("%s:%d] config main img failed", __func__, __LINE__); 1474 goto error; 1475 } 1476 ret = mm_jpeg_session_change_state(p_session, OMX_StateIdle, 1477 mm_jpeg_session_send_buffers); 1478 if (ret) { 1479 CDBG_ERROR("%s:%d] change state to idle failed %d", 1480 __func__, __LINE__, ret); 1481 goto error; 1482 } 1483 1484 ret = mm_jpeg_session_change_state(p_session, OMX_StateExecuting, 1485 NULL); 1486 if (ret) { 1487 CDBG_ERROR("%s:%d] change state to executing failed %d", 1488 __func__, __LINE__, ret); 1489 goto error; 1490 } 1491 1492 error: 1493 CDBG("%s:%d] X ret %d", __func__, __LINE__, ret); 1494 return ret; 1495 } 1496 1497 1498 1499 1500 1501 1502 /** mm_jpeg_session_encode: 1503 * 1504 * Arguments: 1505 * @p_session: encode session 1506 * 1507 * Return: 1508 * OMX_ERRORTYPE 1509 * 1510 * Description: 1511 * Start the encoding 1512 * 1513 **/ 1514 static OMX_ERRORTYPE mm_jpeg_session_encode(mm_jpeg_job_session_t *p_session) 1515 { 1516 OMX_ERRORTYPE ret = OMX_ErrorNone; 1517 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1518 1519 pthread_mutex_lock(&p_session->lock); 1520 p_session->abort_state = MM_JPEG_ABORT_NONE; 1521 p_session->encoding = OMX_FALSE; 1522 pthread_mutex_unlock(&p_session->lock); 1523 1524 if (p_session->thumb_from_main) { 1525 if (0 > p_jobparams->src_index) { 1526 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1527 ret = OMX_ErrorUnsupportedIndex; 1528 goto error; 1529 } 1530 p_jobparams->thumb_index = (uint32_t)p_jobparams->src_index; 1531 p_jobparams->thumb_dim.crop = p_jobparams->main_dim.crop; 1532 } 1533 1534 if (OMX_FALSE == p_session->config) { 1535 ret = mm_jpeg_session_configure(p_session); 1536 if (ret) { 1537 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1538 goto error; 1539 } 1540 p_session->config = OMX_TRUE; 1541 } 1542 1543 ret = mm_jpeg_configure_job_params(p_session); 1544 if (ret) { 1545 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1546 goto error; 1547 } 1548 pthread_mutex_lock(&p_session->lock); 1549 p_session->encoding = OMX_TRUE; 1550 pthread_mutex_unlock(&p_session->lock); 1551 1552 MM_JPEG_CHK_ABORT(p_session, ret, error); 1553 1554 #ifdef MM_JPEG_DUMP_INPUT 1555 char filename[256]; 1556 snprintf(filename, sizeof(filename), 1557 QCAMERA_DUMP_FRM_LOCATION"jpeg/mm_jpeg_int%d.yuv", p_session->ebd_count); 1558 DUMP_TO_FILE(filename, 1559 p_session->p_in_omx_buf[p_jobparams->src_index]->pBuffer, 1560 (size_t)p_session->p_in_omx_buf[p_jobparams->src_index]->nAllocLen); 1561 #endif 1562 1563 ret = OMX_EmptyThisBuffer(p_session->omx_handle, 1564 p_session->p_in_omx_buf[p_jobparams->src_index]); 1565 if (ret) { 1566 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1567 goto error; 1568 } 1569 1570 if (p_session->params.encode_thumbnail) { 1571 #ifdef MM_JPEG_DUMP_INPUT 1572 char thumb_filename[FILENAME_MAX]; 1573 snprintf(thumb_filename, sizeof(thumb_filename), 1574 QCAMERA_DUMP_FRM_LOCATION"jpeg/mm_jpeg_int_t%d.yuv", p_session->ebd_count); 1575 DUMP_TO_FILE(filename, 1576 p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]->pBuffer, 1577 (size_t)p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]->nAllocLen); 1578 #endif 1579 ret = OMX_EmptyThisBuffer(p_session->omx_handle, 1580 p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]); 1581 if (ret) { 1582 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1583 goto error; 1584 } 1585 } 1586 1587 ret = OMX_FillThisBuffer(p_session->omx_handle, 1588 p_session->p_out_omx_buf[p_jobparams->dst_index]); 1589 if (ret) { 1590 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1591 goto error; 1592 } 1593 1594 MM_JPEG_CHK_ABORT(p_session, ret, error); 1595 1596 error: 1597 1598 CDBG("%s:%d] X ", __func__, __LINE__); 1599 return ret; 1600 } 1601 1602 /** mm_jpeg_process_encoding_job: 1603 * 1604 * Arguments: 1605 * @my_obj: jpeg client 1606 * @job_node: job node 1607 * 1608 * Return: 1609 * 0 for success -1 otherwise 1610 * 1611 * Description: 1612 * Start the encoding job 1613 * 1614 **/ 1615 int32_t mm_jpeg_process_encoding_job(mm_jpeg_obj *my_obj, mm_jpeg_job_q_node_t* job_node) 1616 { 1617 mm_jpeg_q_data_t qdata; 1618 int32_t rc = 0; 1619 OMX_ERRORTYPE ret = OMX_ErrorNone; 1620 mm_jpeg_job_session_t *p_session = NULL; 1621 uint32_t buf_idx; 1622 1623 /* check if valid session */ 1624 p_session = mm_jpeg_get_session(my_obj, job_node->enc_info.job_id); 1625 if (NULL == p_session) { 1626 CDBG_ERROR("%s:%d] invalid job id %x", __func__, __LINE__, 1627 job_node->enc_info.job_id); 1628 return -1; 1629 } 1630 1631 CDBG("%s:%d] before dequeue session %d", 1632 __func__, __LINE__, ret); 1633 1634 /* dequeue available omx handle */ 1635 qdata = mm_jpeg_queue_deq(p_session->session_handle_q); 1636 p_session = qdata.p; 1637 1638 if (NULL == p_session) { 1639 CDBG_HIGH("%s:%d] No available sessions %d", 1640 __func__, __LINE__, ret); 1641 /* No available handles */ 1642 qdata.p = job_node; 1643 mm_jpeg_queue_enq_head(&my_obj->job_mgr.job_queue, qdata); 1644 1645 CDBG_HIGH("%s:%d]end enqueue %d", 1646 __func__, __LINE__, ret); 1647 return rc; 1648 1649 } 1650 1651 p_session->auto_out_buf = OMX_FALSE; 1652 if (job_node->enc_info.encode_job.dst_index < 0) { 1653 /* dequeue available output buffer idx */ 1654 qdata = mm_jpeg_queue_deq(p_session->out_buf_q); 1655 buf_idx = qdata.u32; 1656 1657 if (0U == buf_idx) { 1658 CDBG_ERROR("%s:%d] No available output buffers %d", 1659 __func__, __LINE__, ret); 1660 return OMX_ErrorUndefined; 1661 } 1662 1663 buf_idx--; 1664 1665 job_node->enc_info.encode_job.dst_index = (int32_t)buf_idx; 1666 p_session->auto_out_buf = OMX_TRUE; 1667 } 1668 1669 /* sent encode cmd to OMX, queue job into ongoing queue */ 1670 qdata.p = job_node; 1671 rc = mm_jpeg_queue_enq(&my_obj->ongoing_job_q, qdata); 1672 if (rc) { 1673 CDBG_ERROR("%s:%d] jpeg enqueue failed %d", 1674 __func__, __LINE__, ret); 1675 goto error; 1676 } 1677 1678 p_session->encode_job = job_node->enc_info.encode_job; 1679 p_session->jobId = job_node->enc_info.job_id; 1680 ret = mm_jpeg_session_encode(p_session); 1681 if (ret) { 1682 CDBG_ERROR("%s:%d] encode session failed", __func__, __LINE__); 1683 goto error; 1684 } 1685 1686 CDBG_HIGH("%s:%d] Success X ", __func__, __LINE__); 1687 return rc; 1688 1689 error: 1690 1691 if ((OMX_ErrorNone != ret) && 1692 (NULL != p_session->params.jpeg_cb)) { 1693 p_session->job_status = JPEG_JOB_STATUS_ERROR; 1694 CDBG_ERROR("%s:%d] send jpeg error callback %d", __func__, __LINE__, 1695 p_session->job_status); 1696 p_session->params.jpeg_cb(p_session->job_status, 1697 p_session->client_hdl, 1698 p_session->jobId, 1699 NULL, 1700 p_session->params.userdata); 1701 } 1702 1703 /*remove the job*/ 1704 mm_jpegenc_job_done(p_session); 1705 CDBG("%s:%d] Error X ", __func__, __LINE__); 1706 1707 return rc; 1708 } 1709 1710 1711 1712 /** mm_jpeg_jobmgr_thread: 1713 * 1714 * Arguments: 1715 * @my_obj: jpeg object 1716 * 1717 * Return: 1718 * 0 for success else failure 1719 * 1720 * Description: 1721 * job manager thread main function 1722 * 1723 **/ 1724 static void *mm_jpeg_jobmgr_thread(void *data) 1725 { 1726 mm_jpeg_q_data_t qdata; 1727 int rc = 0; 1728 int running = 1; 1729 uint32_t num_ongoing_jobs = 0; 1730 mm_jpeg_obj *my_obj = (mm_jpeg_obj*)data; 1731 mm_jpeg_job_cmd_thread_t *cmd_thread = &my_obj->job_mgr; 1732 mm_jpeg_job_q_node_t* node = NULL; 1733 prctl(PR_SET_NAME, (unsigned long)"mm_jpeg_thread", 0, 0, 0); 1734 1735 do { 1736 do { 1737 rc = cam_sem_wait(&cmd_thread->job_sem); 1738 if (rc != 0 && errno != EINVAL) { 1739 CDBG_ERROR("%s: cam_sem_wait error (%s)", 1740 __func__, strerror(errno)); 1741 return NULL; 1742 } 1743 } while (rc != 0); 1744 1745 /* check ongoing q size */ 1746 num_ongoing_jobs = mm_jpeg_queue_get_size(&my_obj->ongoing_job_q); 1747 1748 CDBG("%s:%d] ongoing job %d %d", __func__, 1749 __LINE__, num_ongoing_jobs, MM_JPEG_CONCURRENT_SESSIONS_COUNT); 1750 if (num_ongoing_jobs >= MM_JPEG_CONCURRENT_SESSIONS_COUNT) { 1751 CDBG_ERROR("%s:%d] ongoing job already reach max %d", __func__, 1752 __LINE__, num_ongoing_jobs); 1753 continue; 1754 } 1755 1756 pthread_mutex_lock(&my_obj->job_lock); 1757 /* can go ahead with new work */ 1758 qdata = mm_jpeg_queue_deq(&cmd_thread->job_queue); 1759 node = (mm_jpeg_job_q_node_t*)qdata.p; 1760 if (node != NULL) { 1761 switch (node->type) { 1762 case MM_JPEG_CMD_TYPE_JOB: 1763 rc = mm_jpeg_process_encoding_job(my_obj, node); 1764 break; 1765 case MM_JPEG_CMD_TYPE_DECODE_JOB: 1766 rc = mm_jpegdec_process_decoding_job(my_obj, node); 1767 break; 1768 case MM_JPEG_CMD_TYPE_EXIT: 1769 default: 1770 /* free node */ 1771 free(node); 1772 /* set running flag to false */ 1773 running = 0; 1774 break; 1775 } 1776 } 1777 pthread_mutex_unlock(&my_obj->job_lock); 1778 1779 } while (running); 1780 return NULL; 1781 } 1782 1783 /** mm_jpeg_jobmgr_thread_launch: 1784 * 1785 * Arguments: 1786 * @my_obj: jpeg object 1787 * 1788 * Return: 1789 * 0 for success else failure 1790 * 1791 * Description: 1792 * launches the job manager thread 1793 * 1794 **/ 1795 int32_t mm_jpeg_jobmgr_thread_launch(mm_jpeg_obj *my_obj) 1796 { 1797 int32_t rc = 0; 1798 mm_jpeg_job_cmd_thread_t *job_mgr = &my_obj->job_mgr; 1799 1800 cam_sem_init(&job_mgr->job_sem, 0); 1801 mm_jpeg_queue_init(&job_mgr->job_queue); 1802 1803 /* launch the thread */ 1804 pthread_create(&job_mgr->pid, 1805 NULL, 1806 mm_jpeg_jobmgr_thread, 1807 (void *)my_obj); 1808 pthread_setname_np(job_mgr->pid, "CAM_jpeg_jobmgr"); 1809 return rc; 1810 } 1811 1812 /** mm_jpeg_jobmgr_thread_release: 1813 * 1814 * Arguments: 1815 * @my_obj: jpeg object 1816 * 1817 * Return: 1818 * 0 for success else failure 1819 * 1820 * Description: 1821 * Releases the job manager thread 1822 * 1823 **/ 1824 int32_t mm_jpeg_jobmgr_thread_release(mm_jpeg_obj * my_obj) 1825 { 1826 mm_jpeg_q_data_t qdata; 1827 int32_t rc = 0; 1828 mm_jpeg_job_cmd_thread_t * cmd_thread = &my_obj->job_mgr; 1829 mm_jpeg_job_q_node_t* node = 1830 (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t)); 1831 if (NULL == node) { 1832 CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__); 1833 return -1; 1834 } 1835 1836 memset(node, 0, sizeof(mm_jpeg_job_q_node_t)); 1837 node->type = MM_JPEG_CMD_TYPE_EXIT; 1838 1839 qdata.p = node; 1840 mm_jpeg_queue_enq(&cmd_thread->job_queue, qdata); 1841 cam_sem_post(&cmd_thread->job_sem); 1842 1843 /* wait until cmd thread exits */ 1844 if (pthread_join(cmd_thread->pid, NULL) != 0) { 1845 CDBG("%s: pthread dead already", __func__); 1846 } 1847 mm_jpeg_queue_deinit(&cmd_thread->job_queue); 1848 1849 cam_sem_destroy(&cmd_thread->job_sem); 1850 memset(cmd_thread, 0, sizeof(mm_jpeg_job_cmd_thread_t)); 1851 return rc; 1852 } 1853 1854 /** mm_jpeg_init: 1855 * 1856 * Arguments: 1857 * @my_obj: jpeg object 1858 * 1859 * Return: 1860 * 0 for success else failure 1861 * 1862 * Description: 1863 * Initializes the jpeg client 1864 * 1865 **/ 1866 int32_t mm_jpeg_init(mm_jpeg_obj *my_obj) 1867 { 1868 int32_t rc = 0; 1869 uint32_t work_buf_size; 1870 unsigned int i = 0; 1871 unsigned int initial_workbufs_cnt = 1; 1872 1873 /* init locks */ 1874 pthread_mutex_init(&my_obj->job_lock, NULL); 1875 1876 /* init ongoing job queue */ 1877 rc = mm_jpeg_queue_init(&my_obj->ongoing_job_q); 1878 if (0 != rc) { 1879 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1880 pthread_mutex_destroy(&my_obj->job_lock); 1881 return -1; 1882 } 1883 1884 1885 /* init job semaphore and launch jobmgr thread */ 1886 CDBG("%s:%d] Launch jobmgr thread rc %d", __func__, __LINE__, rc); 1887 rc = mm_jpeg_jobmgr_thread_launch(my_obj); 1888 if (0 != rc) { 1889 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1890 mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 1891 pthread_mutex_destroy(&my_obj->job_lock); 1892 return -1; 1893 } 1894 1895 /* set work buf size from max picture size */ 1896 if (my_obj->max_pic_w <= 0 || my_obj->max_pic_h <= 0) { 1897 CDBG_ERROR("%s:%d] Width and height are not valid " 1898 "dimensions, cannot calc work buf size",__func__, __LINE__); 1899 mm_jpeg_jobmgr_thread_release(my_obj); 1900 mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 1901 pthread_mutex_destroy(&my_obj->job_lock); 1902 return -1; 1903 } 1904 work_buf_size = CEILING64((uint32_t)my_obj->max_pic_w) * 1905 CEILING64((uint32_t)my_obj->max_pic_h) * 3U / 2U; 1906 for (i = 0; i < initial_workbufs_cnt; i++) { 1907 my_obj->ionBuffer[i].size = CEILING32(work_buf_size); 1908 CDBG_HIGH("Max picture size %d x %d, WorkBufSize = %zu", 1909 my_obj->max_pic_w, my_obj->max_pic_h, my_obj->ionBuffer[i].size); 1910 1911 my_obj->ionBuffer[i].addr = (uint8_t *)buffer_allocate(&my_obj->ionBuffer[i], 1); 1912 if (NULL == my_obj->ionBuffer[i].addr) { 1913 while (i--) { 1914 buffer_deallocate(&my_obj->ionBuffer[i]); 1915 } 1916 mm_jpeg_jobmgr_thread_release(my_obj); 1917 mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 1918 pthread_mutex_destroy(&my_obj->job_lock); 1919 CDBG_ERROR("%s:%d] Ion allocation failed",__func__, __LINE__); 1920 return -1; 1921 } 1922 } 1923 1924 my_obj->work_buf_cnt = i; 1925 1926 /* load OMX */ 1927 if (OMX_ErrorNone != OMX_Init()) { 1928 /* roll back in error case */ 1929 CDBG_ERROR("%s:%d] OMX_Init failed (%d)", __func__, __LINE__, rc); 1930 for (i = 0; i < initial_workbufs_cnt; i++) { 1931 buffer_deallocate(&my_obj->ionBuffer[i]); 1932 } 1933 mm_jpeg_jobmgr_thread_release(my_obj); 1934 mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 1935 pthread_mutex_destroy(&my_obj->job_lock); 1936 } 1937 1938 #ifdef LOAD_ADSP_RPC_LIB 1939 my_obj->adsprpc_lib_handle = dlopen("libadsprpc.so", RTLD_NOW); 1940 if (NULL == my_obj->adsprpc_lib_handle) { 1941 CDBG_ERROR("%s:%d] Cannot load the library", __func__, __LINE__); 1942 /* not returning error here bcoz even if this loading fails 1943 we can go ahead with SW JPEG enc */ 1944 } 1945 #endif 1946 1947 return rc; 1948 } 1949 1950 /** mm_jpeg_deinit: 1951 * 1952 * Arguments: 1953 * @my_obj: jpeg object 1954 * 1955 * Return: 1956 * 0 for success else failure 1957 * 1958 * Description: 1959 * Deinits the jpeg client 1960 * 1961 **/ 1962 int32_t mm_jpeg_deinit(mm_jpeg_obj *my_obj) 1963 { 1964 int32_t rc = 0; 1965 uint32_t i = 0; 1966 1967 /* release jobmgr thread */ 1968 rc = mm_jpeg_jobmgr_thread_release(my_obj); 1969 if (0 != rc) { 1970 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1971 } 1972 1973 /* unload OMX engine */ 1974 OMX_Deinit(); 1975 1976 /* deinit ongoing job and cb queue */ 1977 rc = mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 1978 if (0 != rc) { 1979 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1980 } 1981 1982 for (i = 0; i < my_obj->work_buf_cnt; i++) { 1983 /*Release the ION buffer*/ 1984 rc = buffer_deallocate(&my_obj->ionBuffer[i]); 1985 if (0 != rc) { 1986 CDBG_ERROR("%s:%d] Error releasing ION buffer", __func__, __LINE__); 1987 } 1988 } 1989 1990 /* destroy locks */ 1991 pthread_mutex_destroy(&my_obj->job_lock); 1992 1993 return rc; 1994 } 1995 1996 /** mm_jpeg_new_client: 1997 * 1998 * Arguments: 1999 * @my_obj: jpeg object 2000 * 2001 * Return: 2002 * 0 for success else failure 2003 * 2004 * Description: 2005 * Create new jpeg client 2006 * 2007 **/ 2008 uint32_t mm_jpeg_new_client(mm_jpeg_obj *my_obj) 2009 { 2010 uint32_t client_hdl = 0; 2011 uint8_t idx; 2012 int i = 0; 2013 2014 if (my_obj->num_clients >= MAX_JPEG_CLIENT_NUM) { 2015 CDBG_ERROR("%s: num of clients reached limit", __func__); 2016 return client_hdl; 2017 } 2018 2019 for (idx = 0; idx < MAX_JPEG_CLIENT_NUM; idx++) { 2020 if (0 == my_obj->clnt_mgr[idx].is_used) { 2021 break; 2022 } 2023 } 2024 2025 if (idx < MAX_JPEG_CLIENT_NUM) { 2026 /* client session avail */ 2027 /* generate client handler by index */ 2028 client_hdl = mm_jpeg_util_generate_handler(idx); 2029 2030 /* update client session */ 2031 my_obj->clnt_mgr[idx].is_used = 1; 2032 my_obj->clnt_mgr[idx].client_handle = client_hdl; 2033 2034 pthread_mutex_init(&my_obj->clnt_mgr[idx].lock, NULL); 2035 for (i = 0; i < MM_JPEG_MAX_SESSION; i++) { 2036 memset(&my_obj->clnt_mgr[idx].session[i], 0x0, sizeof(mm_jpeg_job_session_t)); 2037 } 2038 2039 /* increse client count */ 2040 my_obj->num_clients++; 2041 } 2042 2043 return client_hdl; 2044 } 2045 2046 /** mm_jpeg_start_job: 2047 * 2048 * Arguments: 2049 * @my_obj: jpeg object 2050 * @client_hdl: client handle 2051 * @job: pointer to encode job 2052 * @jobId: job id 2053 * 2054 * Return: 2055 * 0 for success else failure 2056 * 2057 * Description: 2058 * Start the encoding job 2059 * 2060 **/ 2061 int32_t mm_jpeg_start_job(mm_jpeg_obj *my_obj, 2062 mm_jpeg_job_t *job, 2063 uint32_t *job_id) 2064 { 2065 mm_jpeg_q_data_t qdata; 2066 int32_t rc = -1; 2067 uint8_t session_idx = 0; 2068 uint8_t client_idx = 0; 2069 mm_jpeg_job_q_node_t* node = NULL; 2070 mm_jpeg_job_session_t *p_session = NULL; 2071 mm_jpeg_encode_job_t *p_jobparams = &job->encode_job; 2072 2073 *job_id = 0; 2074 2075 /* check if valid session */ 2076 session_idx = GET_SESSION_IDX(p_jobparams->session_id); 2077 client_idx = GET_CLIENT_IDX(p_jobparams->session_id); 2078 CDBG_HIGH("%s:%d] session_idx %d client idx %d", __func__, __LINE__, 2079 session_idx, client_idx); 2080 2081 if ((session_idx >= MM_JPEG_MAX_SESSION) || 2082 (client_idx >= MAX_JPEG_CLIENT_NUM)) { 2083 CDBG_ERROR("%s:%d] invalid session id %x", __func__, __LINE__, 2084 job->encode_job.session_id); 2085 return rc; 2086 } 2087 2088 p_session = &my_obj->clnt_mgr[client_idx].session[session_idx]; 2089 if (OMX_FALSE == p_session->active) { 2090 CDBG_ERROR("%s:%d] session not active %x", __func__, __LINE__, 2091 job->encode_job.session_id); 2092 return rc; 2093 } 2094 2095 if ((p_jobparams->src_index >= (int32_t)p_session->params.num_src_bufs) || 2096 (p_jobparams->dst_index >= (int32_t)p_session->params.num_dst_bufs)) { 2097 CDBG_ERROR("%s:%d] invalid buffer indices", __func__, __LINE__); 2098 return rc; 2099 } 2100 2101 /* enqueue new job into todo job queue */ 2102 node = (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t)); 2103 if (NULL == node) { 2104 CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__); 2105 return -1; 2106 } 2107 2108 ATRACE_INT("Camera:JPEG", 2109 (int32_t)((uint32_t)session_idx<<16 | ++p_session->job_index)); 2110 2111 *job_id = job->encode_job.session_id | 2112 (((uint32_t)p_session->job_hist++ % JOB_HIST_MAX) << 16); 2113 2114 memset(node, 0, sizeof(mm_jpeg_job_q_node_t)); 2115 node->enc_info.encode_job = job->encode_job; 2116 if (p_session->thumb_from_main) { 2117 node->enc_info.encode_job.thumb_dim.src_dim = 2118 node->enc_info.encode_job.main_dim.src_dim; 2119 node->enc_info.encode_job.thumb_dim.crop = 2120 node->enc_info.encode_job.main_dim.crop; 2121 } 2122 node->enc_info.job_id = *job_id; 2123 node->enc_info.client_handle = p_session->client_hdl; 2124 node->type = MM_JPEG_CMD_TYPE_JOB; 2125 2126 2127 2128 qdata.p = node; 2129 rc = mm_jpeg_queue_enq(&my_obj->job_mgr.job_queue, qdata); 2130 if (0 == rc) { 2131 cam_sem_post(&my_obj->job_mgr.job_sem); 2132 } 2133 2134 CDBG_HIGH("%s:%d] job_id %d X", __func__, __LINE__, *job_id); 2135 2136 return rc; 2137 } 2138 2139 2140 2141 /** mm_jpeg_abort_job: 2142 * 2143 * Arguments: 2144 * @my_obj: jpeg object 2145 * @client_hdl: client handle 2146 * @jobId: job id 2147 * 2148 * Return: 2149 * 0 for success else failure 2150 * 2151 * Description: 2152 * Abort the encoding session 2153 * 2154 **/ 2155 int32_t mm_jpeg_abort_job(mm_jpeg_obj *my_obj, 2156 uint32_t jobId) 2157 { 2158 int32_t rc = -1; 2159 mm_jpeg_job_q_node_t *node = NULL; 2160 mm_jpeg_job_session_t *p_session = NULL; 2161 2162 CDBG("%s:%d] ", __func__, __LINE__); 2163 pthread_mutex_lock(&my_obj->job_lock); 2164 2165 /* abort job if in todo queue */ 2166 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->job_mgr.job_queue, jobId); 2167 if (NULL != node) { 2168 free(node); 2169 goto abort_done; 2170 } 2171 2172 /* abort job if in ongoing queue */ 2173 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, jobId); 2174 if (NULL != node) { 2175 /* find job that is OMX ongoing, ask OMX to abort the job */ 2176 p_session = mm_jpeg_get_session(my_obj, node->enc_info.job_id); 2177 if (p_session) { 2178 mm_jpeg_session_abort(p_session); 2179 } else { 2180 CDBG_ERROR("%s:%d] Invalid job id 0x%x", __func__, __LINE__, 2181 node->enc_info.job_id); 2182 } 2183 free(node); 2184 goto abort_done; 2185 } 2186 2187 abort_done: 2188 pthread_mutex_unlock(&my_obj->job_lock); 2189 2190 return rc; 2191 } 2192 2193 2194 #ifdef MM_JPEG_READ_META_KEYFILE 2195 static int32_t mm_jpeg_read_meta_keyfile(mm_jpeg_job_session_t *p_session, 2196 const char *filename) 2197 { 2198 int rc = 0; 2199 FILE *fp = NULL; 2200 size_t file_size = 0; 2201 fp = fopen(filename, "r"); 2202 if (!fp) { 2203 CDBG_ERROR("%s:%d] Key not present", __func__, __LINE__); 2204 return -1; 2205 } 2206 fseek(fp, 0, SEEK_END); 2207 file_size = (size_t)ftell(fp); 2208 fseek(fp, 0, SEEK_SET); 2209 2210 p_session->meta_enc_key = (uint8_t *) malloc((file_size + 1) * sizeof(uint8_t)); 2211 2212 if (!p_session->meta_enc_key) { 2213 CDBG_ERROR("%s:%d] error", __func__, __LINE__); 2214 return -1; 2215 } 2216 2217 fread(p_session->meta_enc_key, 1, file_size, fp); 2218 fclose(fp); 2219 2220 p_session->meta_enc_keylen = file_size; 2221 2222 return rc; 2223 } 2224 #endif // MM_JPEG_READ_META_KEYFILE 2225 2226 /** mm_jpeg_create_session: 2227 * 2228 * Arguments: 2229 * @my_obj: jpeg object 2230 * @client_hdl: client handle 2231 * @p_params: pointer to encode params 2232 * @p_session_id: session id 2233 * 2234 * Return: 2235 * 0 for success else failure 2236 * 2237 * Description: 2238 * Start the encoding session 2239 * 2240 **/ 2241 int32_t mm_jpeg_create_session(mm_jpeg_obj *my_obj, 2242 uint32_t client_hdl, 2243 mm_jpeg_encode_params_t *p_params, 2244 uint32_t* p_session_id) 2245 { 2246 mm_jpeg_q_data_t qdata; 2247 int32_t rc = 0; 2248 OMX_ERRORTYPE ret = OMX_ErrorNone; 2249 uint8_t clnt_idx = 0; 2250 int session_idx = -1; 2251 mm_jpeg_job_session_t *p_session = NULL; 2252 mm_jpeg_job_session_t * p_prev_session = NULL; 2253 *p_session_id = 0; 2254 uint32_t i = 0; 2255 uint32_t num_omx_sessions; 2256 uint32_t work_buf_size; 2257 mm_jpeg_queue_t *p_session_handle_q, *p_out_buf_q; 2258 uint32_t work_bufs_need; 2259 char trace_tag[32]; 2260 2261 /* validate the parameters */ 2262 if ((p_params->num_src_bufs > MM_JPEG_MAX_BUF) 2263 || (p_params->num_dst_bufs > MM_JPEG_MAX_BUF)) { 2264 CDBG_ERROR("%s:%d] invalid num buffers", __func__, __LINE__); 2265 return -1; 2266 } 2267 2268 /* check if valid client */ 2269 clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl); 2270 if (clnt_idx >= MAX_JPEG_CLIENT_NUM) { 2271 CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl); 2272 return -1; 2273 } 2274 2275 num_omx_sessions = 1; 2276 if (p_params->burst_mode) { 2277 num_omx_sessions = MM_JPEG_CONCURRENT_SESSIONS_COUNT; 2278 } 2279 work_bufs_need = num_omx_sessions; 2280 if (work_bufs_need > MM_JPEG_CONCURRENT_SESSIONS_COUNT) { 2281 work_bufs_need = MM_JPEG_CONCURRENT_SESSIONS_COUNT; 2282 } 2283 CDBG_HIGH("%s:%d] >>>> Work bufs need %d", __func__, __LINE__, work_bufs_need); 2284 work_buf_size = CEILING64((uint32_t)my_obj->max_pic_w) * 2285 CEILING64((uint32_t)my_obj->max_pic_h) * 3 / 2; 2286 for (i = my_obj->work_buf_cnt; i < work_bufs_need; i++) { 2287 my_obj->ionBuffer[i].size = CEILING32(work_buf_size); 2288 CDBG_HIGH("Max picture size %d x %d, WorkBufSize = %zu", 2289 my_obj->max_pic_w, my_obj->max_pic_h, my_obj->ionBuffer[i].size); 2290 2291 my_obj->ionBuffer[i].addr = (uint8_t *)buffer_allocate(&my_obj->ionBuffer[i], 1); 2292 if (NULL == my_obj->ionBuffer[i].addr) { 2293 CDBG_ERROR("%s:%d] Ion allocation failed",__func__, __LINE__); 2294 goto error1; 2295 } 2296 my_obj->work_buf_cnt++; 2297 } 2298 2299 2300 /* init omx handle queue */ 2301 p_session_handle_q = (mm_jpeg_queue_t *) malloc(sizeof(*p_session_handle_q)); 2302 if (NULL == p_session_handle_q) { 2303 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 2304 goto error1; 2305 } 2306 rc = mm_jpeg_queue_init(p_session_handle_q); 2307 if (0 != rc) { 2308 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 2309 free(p_session_handle_q); 2310 goto error1; 2311 } 2312 2313 /* init output buf queue */ 2314 p_out_buf_q = (mm_jpeg_queue_t *) malloc(sizeof(*p_out_buf_q)); 2315 if (NULL == p_out_buf_q) { 2316 CDBG_ERROR("%s:%d] Error: Cannot allocate memory\n", __func__, __LINE__); 2317 return -1; 2318 } 2319 2320 /* init omx handle queue */ 2321 rc = mm_jpeg_queue_init(p_out_buf_q); 2322 if (0 != rc) { 2323 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 2324 free(p_out_buf_q); 2325 goto error1; 2326 } 2327 2328 for (i = 0; i < num_omx_sessions; i++) { 2329 uint32_t buf_idx = 0U; 2330 session_idx = mm_jpeg_get_new_session_idx(my_obj, clnt_idx, &p_session); 2331 if (session_idx < 0 || NULL == p_session) { 2332 CDBG_ERROR("%s:%d] invalid session id (%d)", __func__, __LINE__, session_idx); 2333 goto error2; 2334 } 2335 2336 snprintf(trace_tag, sizeof(trace_tag), "Camera:JPEGsession%d", session_idx); 2337 ATRACE_INT(trace_tag, 1); 2338 2339 p_session->job_index = 0; 2340 2341 p_session->next_session = NULL; 2342 2343 if (p_prev_session) { 2344 p_prev_session->next_session = p_session; 2345 } 2346 p_prev_session = p_session; 2347 2348 buf_idx = i; 2349 if (buf_idx < MM_JPEG_CONCURRENT_SESSIONS_COUNT) { 2350 p_session->work_buffer = my_obj->ionBuffer[buf_idx]; 2351 } else { 2352 CDBG_ERROR("%s %d: Invalid Index, Setting buffer add to null", __func__, __LINE__); 2353 p_session->work_buffer.addr = NULL; 2354 p_session->work_buffer.ion_fd = -1; 2355 p_session->work_buffer.p_pmem_fd = -1; 2356 } 2357 2358 p_session->jpeg_obj = (void*)my_obj; /* save a ptr to jpeg_obj */ 2359 2360 ret = mm_jpeg_session_create(p_session); 2361 if (OMX_ErrorNone != ret) { 2362 p_session->active = OMX_FALSE; 2363 CDBG_ERROR("%s:%d] jpeg session create failed", __func__, __LINE__); 2364 goto error2; 2365 } 2366 2367 uint32_t session_id = (JOB_ID_MAGICVAL << 24) | 2368 ((uint32_t)session_idx << 8) | clnt_idx; 2369 2370 if (!*p_session_id) { 2371 *p_session_id = session_id; 2372 } 2373 2374 /*copy the params*/ 2375 p_session->params = *p_params; 2376 if (p_session->thumb_from_main) { 2377 memcpy(p_session->params.src_thumb_buf, p_session->params.src_main_buf, 2378 sizeof(p_session->params.src_thumb_buf)); 2379 p_session->params.num_tmb_bufs = p_session->params.num_src_bufs; 2380 if (!p_session->params.encode_thumbnail) { 2381 p_session->params.num_tmb_bufs = 0; 2382 } 2383 p_session->params.thumb_dim.src_dim = p_session->params.main_dim.src_dim; 2384 p_session->params.thumb_dim.crop = p_session->params.main_dim.crop; 2385 } 2386 p_session->client_hdl = client_hdl; 2387 p_session->sessionId = session_id; 2388 p_session->session_handle_q = p_session_handle_q; 2389 p_session->out_buf_q = p_out_buf_q; 2390 2391 qdata.p = p_session; 2392 mm_jpeg_queue_enq(p_session_handle_q, qdata); 2393 2394 p_session->meta_enc_key = NULL; 2395 p_session->meta_enc_keylen = 0; 2396 2397 #ifdef MM_JPEG_READ_META_KEYFILE 2398 mm_jpeg_read_meta_keyfile(p_session, META_KEYFILE); 2399 #endif 2400 2401 if (OMX_FALSE == p_session->config) { 2402 rc = mm_jpeg_session_configure(p_session); 2403 if (rc) { 2404 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 2405 goto error2; 2406 } 2407 p_session->config = OMX_TRUE; 2408 } 2409 p_session->num_omx_sessions = num_omx_sessions; 2410 2411 CDBG_HIGH("%s:%d] session id %x", __func__, __LINE__, session_id); 2412 } 2413 2414 // Queue the output buf indexes 2415 for (i = 0; i < p_params->num_dst_bufs; i++) { 2416 qdata.u32 = i + 1; 2417 mm_jpeg_queue_enq(p_out_buf_q, qdata); 2418 } 2419 2420 return rc; 2421 2422 error1: 2423 rc = -1; 2424 error2: 2425 if (NULL != p_session) { 2426 ATRACE_INT(trace_tag, 0); 2427 } 2428 return rc; 2429 } 2430 2431 /** mm_jpegenc_destroy_job 2432 * 2433 * Arguments: 2434 * @p_session: Session obj 2435 * 2436 * Return: 2437 * 0 for success else failure 2438 * 2439 * Description: 2440 * Destroy the job based paramenters 2441 * 2442 **/ 2443 static int32_t mm_jpegenc_destroy_job(mm_jpeg_job_session_t *p_session) 2444 { 2445 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 2446 int i = 0, rc = 0; 2447 2448 CDBG_HIGH("%s:%d] Exif entry count %d %d", __func__, __LINE__, 2449 (int)p_jobparams->exif_info.numOfEntries, 2450 (int)p_session->exif_count_local); 2451 for (i = 0; i < p_session->exif_count_local; i++) { 2452 rc = releaseExifEntry(&p_session->exif_info_local[i]); 2453 if (rc) { 2454 CDBG_ERROR("%s:%d] Exif release failed (%d)", __func__, __LINE__, rc); 2455 } 2456 } 2457 p_session->exif_count_local = 0; 2458 2459 return rc; 2460 } 2461 2462 /** mm_jpeg_session_encode: 2463 * 2464 * Arguments: 2465 * @p_session: encode session 2466 * 2467 * Return: 2468 * OMX_ERRORTYPE 2469 * 2470 * Description: 2471 * Start the encoding 2472 * 2473 **/ 2474 static void mm_jpegenc_job_done(mm_jpeg_job_session_t *p_session) 2475 { 2476 mm_jpeg_q_data_t qdata; 2477 mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj; 2478 mm_jpeg_job_q_node_t *node = NULL; 2479 2480 /*Destroy job related params*/ 2481 mm_jpegenc_destroy_job(p_session); 2482 2483 /*remove the job*/ 2484 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, 2485 p_session->jobId); 2486 if (node) { 2487 free(node); 2488 } 2489 p_session->encoding = OMX_FALSE; 2490 2491 // Queue to available sessions 2492 qdata.p = p_session; 2493 mm_jpeg_queue_enq(p_session->session_handle_q, qdata); 2494 2495 if (p_session->auto_out_buf) { 2496 //Queue out buf index 2497 qdata.u32 = (uint32_t)(p_session->encode_job.dst_index + 1); 2498 mm_jpeg_queue_enq(p_session->out_buf_q, qdata); 2499 } 2500 2501 /* wake up jobMgr thread to work on new job if there is any */ 2502 cam_sem_post(&my_obj->job_mgr.job_sem); 2503 } 2504 2505 /** mm_jpeg_destroy_session: 2506 * 2507 * Arguments: 2508 * @my_obj: jpeg object 2509 * @session_id: session index 2510 * 2511 * Return: 2512 * 0 for success else failure 2513 * 2514 * Description: 2515 * Destroy the encoding session 2516 * 2517 **/ 2518 int32_t mm_jpeg_destroy_session(mm_jpeg_obj *my_obj, 2519 mm_jpeg_job_session_t *p_session) 2520 { 2521 mm_jpeg_q_data_t qdata; 2522 int32_t rc = 0; 2523 mm_jpeg_job_q_node_t *node = NULL; 2524 uint32_t session_id = 0; 2525 mm_jpeg_job_session_t *p_cur_sess; 2526 char trace_tag[32]; 2527 2528 if (NULL == p_session) { 2529 CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__); 2530 return rc; 2531 } 2532 2533 session_id = p_session->sessionId; 2534 2535 pthread_mutex_lock(&my_obj->job_lock); 2536 2537 /* abort job if in todo queue */ 2538 CDBG_HIGH("%s:%d] abort todo jobs", __func__, __LINE__); 2539 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); 2540 while (NULL != node) { 2541 free(node); 2542 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); 2543 } 2544 2545 /* abort job if in ongoing queue */ 2546 CDBG_HIGH("%s:%d] abort ongoing jobs", __func__, __LINE__); 2547 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); 2548 while (NULL != node) { 2549 free(node); 2550 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); 2551 } 2552 2553 /* abort the current session */ 2554 mm_jpeg_session_abort(p_session); 2555 mm_jpeg_session_destroy(p_session); 2556 2557 p_cur_sess = p_session; 2558 2559 do { 2560 mm_jpeg_remove_session_idx(my_obj, p_cur_sess->sessionId); 2561 } while (NULL != (p_cur_sess = p_cur_sess->next_session)); 2562 2563 2564 pthread_mutex_unlock(&my_obj->job_lock); 2565 2566 while (1) { 2567 qdata = mm_jpeg_queue_deq(p_session->session_handle_q); 2568 if (NULL == qdata.p) 2569 break; 2570 } 2571 mm_jpeg_queue_deinit(p_session->session_handle_q); 2572 free(p_session->session_handle_q); 2573 p_session->session_handle_q = NULL; 2574 2575 while (1) { 2576 qdata = mm_jpeg_queue_deq(p_session->out_buf_q); 2577 if (0U == qdata.u32) 2578 break; 2579 } 2580 mm_jpeg_queue_deinit(p_session->out_buf_q); 2581 free(p_session->out_buf_q); 2582 p_session->out_buf_q = NULL; 2583 2584 2585 /* wake up jobMgr thread to work on new job if there is any */ 2586 cam_sem_post(&my_obj->job_mgr.job_sem); 2587 2588 snprintf(trace_tag, sizeof(trace_tag), "Camera:JPEGsession%d", GET_SESSION_IDX(session_id)); 2589 ATRACE_INT(trace_tag, 0); 2590 2591 CDBG_HIGH("%s:%d] destroy session successful. X", __func__, __LINE__); 2592 2593 return rc; 2594 } 2595 2596 2597 2598 2599 /** mm_jpeg_destroy_session: 2600 * 2601 * Arguments: 2602 * @my_obj: jpeg object 2603 * @session_id: session index 2604 * 2605 * Return: 2606 * 0 for success else failure 2607 * 2608 * Description: 2609 * Destroy the encoding session 2610 * 2611 **/ 2612 int32_t mm_jpeg_destroy_session_unlocked(mm_jpeg_obj *my_obj, 2613 mm_jpeg_job_session_t *p_session) 2614 { 2615 int32_t rc = -1; 2616 mm_jpeg_job_q_node_t *node = NULL; 2617 uint32_t session_id = 0; 2618 if (NULL == p_session) { 2619 CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__); 2620 return rc; 2621 } 2622 2623 session_id = p_session->sessionId; 2624 2625 /* abort job if in todo queue */ 2626 CDBG("%s:%d] abort todo jobs", __func__, __LINE__); 2627 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); 2628 while (NULL != node) { 2629 free(node); 2630 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); 2631 } 2632 2633 /* abort job if in ongoing queue */ 2634 CDBG("%s:%d] abort ongoing jobs", __func__, __LINE__); 2635 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); 2636 while (NULL != node) { 2637 free(node); 2638 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); 2639 } 2640 2641 /* abort the current session */ 2642 mm_jpeg_session_abort(p_session); 2643 //mm_jpeg_remove_session_idx(my_obj, session_id); 2644 2645 return rc; 2646 } 2647 2648 /** mm_jpeg_destroy_session: 2649 * 2650 * Arguments: 2651 * @my_obj: jpeg object 2652 * @session_id: session index 2653 * 2654 * Return: 2655 * 0 for success else failure 2656 * 2657 * Description: 2658 * Destroy the encoding session 2659 * 2660 **/ 2661 int32_t mm_jpeg_destroy_session_by_id(mm_jpeg_obj *my_obj, uint32_t session_id) 2662 { 2663 mm_jpeg_job_session_t *p_session = mm_jpeg_get_session(my_obj, session_id); 2664 2665 return mm_jpeg_destroy_session(my_obj, p_session); 2666 } 2667 2668 2669 2670 /** mm_jpeg_close: 2671 * 2672 * Arguments: 2673 * @my_obj: jpeg object 2674 * @client_hdl: client handle 2675 * 2676 * Return: 2677 * 0 for success else failure 2678 * 2679 * Description: 2680 * Close the jpeg client 2681 * 2682 **/ 2683 int32_t mm_jpeg_close(mm_jpeg_obj *my_obj, uint32_t client_hdl) 2684 { 2685 int32_t rc = -1; 2686 uint8_t clnt_idx = 0; 2687 int i = 0; 2688 2689 /* check if valid client */ 2690 clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl); 2691 if (clnt_idx >= MAX_JPEG_CLIENT_NUM) { 2692 CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl); 2693 return rc; 2694 } 2695 2696 CDBG("%s:%d] E", __func__, __LINE__); 2697 2698 /* abort all jobs from the client */ 2699 pthread_mutex_lock(&my_obj->job_lock); 2700 2701 CDBG("%s:%d] ", __func__, __LINE__); 2702 2703 for (i = 0; i < MM_JPEG_MAX_SESSION; i++) { 2704 if (OMX_TRUE == my_obj->clnt_mgr[clnt_idx].session[i].active) 2705 mm_jpeg_destroy_session_unlocked(my_obj, 2706 &my_obj->clnt_mgr[clnt_idx].session[i]); 2707 } 2708 2709 CDBG("%s:%d] ", __func__, __LINE__); 2710 2711 #ifdef LOAD_ADSP_RPC_LIB 2712 if (NULL != my_obj->adsprpc_lib_handle) { 2713 dlclose(my_obj->adsprpc_lib_handle); 2714 my_obj->adsprpc_lib_handle = NULL; 2715 } 2716 #endif 2717 2718 pthread_mutex_unlock(&my_obj->job_lock); 2719 CDBG("%s:%d] ", __func__, __LINE__); 2720 2721 /* invalidate client session */ 2722 pthread_mutex_destroy(&my_obj->clnt_mgr[clnt_idx].lock); 2723 memset(&my_obj->clnt_mgr[clnt_idx], 0, sizeof(mm_jpeg_client_t)); 2724 2725 rc = 0; 2726 CDBG("%s:%d] X", __func__, __LINE__); 2727 return rc; 2728 } 2729 2730 OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent, 2731 OMX_PTR pAppData, 2732 OMX_BUFFERHEADERTYPE *pBuffer) 2733 { 2734 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData; 2735 2736 CDBG_HIGH("%s:%d] count %d ", __func__, __LINE__, p_session->ebd_count); 2737 pthread_mutex_lock(&p_session->lock); 2738 p_session->ebd_count++; 2739 pthread_mutex_unlock(&p_session->lock); 2740 return 0; 2741 } 2742 2743 OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent, 2744 OMX_PTR pAppData, 2745 OMX_BUFFERHEADERTYPE *pBuffer) 2746 { 2747 OMX_ERRORTYPE ret = OMX_ErrorNone; 2748 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData; 2749 mm_jpeg_output_t output_buf; 2750 CDBG_HIGH("%s:%d] count %d ", __func__, __LINE__, p_session->fbd_count); 2751 CDBG_HIGH("[KPI Perf] : PROFILE_JPEG_FBD"); 2752 2753 pthread_mutex_lock(&p_session->lock); 2754 ATRACE_INT("Camera:JPEG", 2755 (int32_t)((uint32_t)GET_SESSION_IDX( 2756 p_session->sessionId)<<16 | --p_session->job_index)); 2757 if (MM_JPEG_ABORT_NONE != p_session->abort_state) { 2758 pthread_mutex_unlock(&p_session->lock); 2759 return ret; 2760 } 2761 #ifdef MM_JPEG_DUMP_OUT_BS 2762 char filename[256]; 2763 static int bsc; 2764 snprintf(filename, sizeof(filename), 2765 QCAMERA_DUMP_FRM_LOCATION"jpeg/mm_jpeg_bs%d.jpg", bsc++); 2766 DUMP_TO_FILE(filename, 2767 pBuffer->pBuffer, 2768 (size_t)(uint32_t)pBuffer->nFilledLen); 2769 #endif 2770 2771 p_session->fbd_count++; 2772 if (NULL != p_session->params.jpeg_cb) { 2773 2774 p_session->job_status = JPEG_JOB_STATUS_DONE; 2775 output_buf.buf_filled_len = (uint32_t)pBuffer->nFilledLen; 2776 output_buf.buf_vaddr = pBuffer->pBuffer; 2777 output_buf.fd = -1; 2778 CDBG_HIGH("%s:%d] send jpeg callback %d buf 0x%p len %u JobID %u", 2779 __func__, __LINE__, 2780 p_session->job_status, pBuffer->pBuffer, 2781 (unsigned int)pBuffer->nFilledLen, p_session->jobId); 2782 p_session->params.jpeg_cb(p_session->job_status, 2783 p_session->client_hdl, 2784 p_session->jobId, 2785 &output_buf, 2786 p_session->params.userdata); 2787 2788 mm_jpegenc_job_done(p_session); 2789 2790 } 2791 pthread_mutex_unlock(&p_session->lock); 2792 CDBG("%s:%d] ", __func__, __LINE__); 2793 2794 return ret; 2795 } 2796 2797 2798 2799 OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent, 2800 OMX_PTR pAppData, 2801 OMX_EVENTTYPE eEvent, 2802 OMX_U32 nData1, 2803 OMX_U32 nData2, 2804 OMX_PTR pEventData) 2805 { 2806 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData; 2807 2808 CDBG("%s:%d] %d %d %d state %d", __func__, __LINE__, eEvent, (int)nData1, 2809 (int)nData2, p_session->abort_state); 2810 2811 pthread_mutex_lock(&p_session->lock); 2812 2813 if (MM_JPEG_ABORT_INIT == p_session->abort_state) { 2814 p_session->abort_state = MM_JPEG_ABORT_DONE; 2815 pthread_cond_signal(&p_session->cond); 2816 pthread_mutex_unlock(&p_session->lock); 2817 return OMX_ErrorNone; 2818 } 2819 2820 if (eEvent == OMX_EventError) { 2821 p_session->error_flag = nData2; 2822 if (p_session->encoding == OMX_TRUE) { 2823 CDBG_ERROR("%s:%d] Error during encoding", __func__, __LINE__); 2824 2825 /* send jpeg callback */ 2826 if (NULL != p_session->params.jpeg_cb) { 2827 p_session->job_status = JPEG_JOB_STATUS_ERROR; 2828 CDBG_ERROR("%s:%d] send jpeg error callback %d", __func__, __LINE__, 2829 p_session->job_status); 2830 p_session->params.jpeg_cb(p_session->job_status, 2831 p_session->client_hdl, 2832 p_session->jobId, 2833 NULL, 2834 p_session->params.userdata); 2835 } 2836 2837 /* remove from ready queue */ 2838 mm_jpegenc_job_done(p_session); 2839 } 2840 pthread_cond_signal(&p_session->cond); 2841 } else if (eEvent == OMX_EventCmdComplete) { 2842 if (p_session->state_change_pending == OMX_TRUE) { 2843 p_session->state_change_pending = OMX_FALSE; 2844 pthread_cond_signal(&p_session->cond); 2845 } 2846 } 2847 2848 pthread_mutex_unlock(&p_session->lock); 2849 CDBG("%s:%d]", __func__, __LINE__); 2850 return OMX_ErrorNone; 2851 } 2852 2853 2854 2855 /* remove the first job from the queue with matching client handle */ 2856 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id( 2857 mm_jpeg_queue_t* queue, uint32_t client_hdl) 2858 { 2859 mm_jpeg_q_node_t* node = NULL; 2860 mm_jpeg_job_q_node_t* data = NULL; 2861 mm_jpeg_job_q_node_t* job_node = NULL; 2862 struct cam_list *head = NULL; 2863 struct cam_list *pos = NULL; 2864 2865 pthread_mutex_lock(&queue->lock); 2866 head = &queue->head.list; 2867 pos = head->next; 2868 while(pos != head) { 2869 node = member_of(pos, mm_jpeg_q_node_t, list); 2870 data = (mm_jpeg_job_q_node_t *)node->data.p; 2871 2872 if (data && (data->enc_info.client_handle == client_hdl)) { 2873 CDBG_HIGH("%s:%d] found matching client handle", __func__, __LINE__); 2874 job_node = data; 2875 cam_list_del_node(&node->list); 2876 queue->size--; 2877 free(node); 2878 CDBG_HIGH("%s: queue size = %d", __func__, queue->size); 2879 break; 2880 } 2881 pos = pos->next; 2882 } 2883 2884 pthread_mutex_unlock(&queue->lock); 2885 2886 return job_node; 2887 } 2888 2889 /* remove the first job from the queue with matching session id */ 2890 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_session_id( 2891 mm_jpeg_queue_t* queue, uint32_t session_id) 2892 { 2893 mm_jpeg_q_node_t* node = NULL; 2894 mm_jpeg_job_q_node_t* data = NULL; 2895 mm_jpeg_job_q_node_t* job_node = NULL; 2896 struct cam_list *head = NULL; 2897 struct cam_list *pos = NULL; 2898 2899 pthread_mutex_lock(&queue->lock); 2900 head = &queue->head.list; 2901 pos = head->next; 2902 while(pos != head) { 2903 node = member_of(pos, mm_jpeg_q_node_t, list); 2904 data = (mm_jpeg_job_q_node_t *)node->data.p; 2905 2906 if (data && (data->enc_info.encode_job.session_id == session_id)) { 2907 CDBG_HIGH("%s:%d] found matching session id", __func__, __LINE__); 2908 job_node = data; 2909 cam_list_del_node(&node->list); 2910 queue->size--; 2911 free(node); 2912 CDBG_HIGH("%s: queue size = %d", __func__, queue->size); 2913 break; 2914 } 2915 pos = pos->next; 2916 } 2917 2918 pthread_mutex_unlock(&queue->lock); 2919 2920 return job_node; 2921 } 2922 2923 /* remove job from the queue with matching job id */ 2924 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id( 2925 mm_jpeg_queue_t* queue, uint32_t job_id) 2926 { 2927 mm_jpeg_q_node_t* node = NULL; 2928 mm_jpeg_job_q_node_t* data = NULL; 2929 mm_jpeg_job_q_node_t* job_node = NULL; 2930 struct cam_list *head = NULL; 2931 struct cam_list *pos = NULL; 2932 uint32_t lq_job_id; 2933 2934 pthread_mutex_lock(&queue->lock); 2935 head = &queue->head.list; 2936 pos = head->next; 2937 while(pos != head) { 2938 node = member_of(pos, mm_jpeg_q_node_t, list); 2939 data = (mm_jpeg_job_q_node_t *)node->data.p; 2940 2941 if(NULL == data) { 2942 CDBG_ERROR("%s:%d] Data is NULL", __func__, __LINE__); 2943 pthread_mutex_unlock(&queue->lock); 2944 return NULL; 2945 } 2946 2947 if (data->type == MM_JPEG_CMD_TYPE_DECODE_JOB) { 2948 lq_job_id = data->dec_info.job_id; 2949 } else { 2950 lq_job_id = data->enc_info.job_id; 2951 } 2952 2953 if (data && (lq_job_id == job_id)) { 2954 CDBG_HIGH("%s:%d] found matching job id", __func__, __LINE__); 2955 job_node = data; 2956 cam_list_del_node(&node->list); 2957 queue->size--; 2958 free(node); 2959 break; 2960 } 2961 pos = pos->next; 2962 } 2963 2964 pthread_mutex_unlock(&queue->lock); 2965 2966 return job_node; 2967 } 2968 2969 /* remove job from the queue with matching job id */ 2970 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_unlk( 2971 mm_jpeg_queue_t* queue, uint32_t job_id) 2972 { 2973 mm_jpeg_q_node_t* node = NULL; 2974 mm_jpeg_job_q_node_t* data = NULL; 2975 mm_jpeg_job_q_node_t* job_node = NULL; 2976 struct cam_list *head = NULL; 2977 struct cam_list *pos = NULL; 2978 2979 head = &queue->head.list; 2980 pos = head->next; 2981 while(pos != head) { 2982 node = member_of(pos, mm_jpeg_q_node_t, list); 2983 data = (mm_jpeg_job_q_node_t *)node->data.p; 2984 2985 if (data && (data->enc_info.job_id == job_id)) { 2986 job_node = data; 2987 cam_list_del_node(&node->list); 2988 queue->size--; 2989 free(node); 2990 break; 2991 } 2992 pos = pos->next; 2993 } 2994 2995 return job_node; 2996 } 2997