1/* Copyright (c) 2012-2016, 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// System dependencies 31#include <pthread.h> 32#include <errno.h> 33#include <fcntl.h> 34#include <math.h> 35#define PRCTL_H <SYSTEM_HEADER_PREFIX/prctl.h> 36#include PRCTL_H 37 38#ifdef LOAD_ADSP_RPC_LIB 39#include <dlfcn.h> 40#include <stdlib.h> 41#endif 42 43// JPEG dependencies 44#include "mm_jpeg_dbg.h" 45#include "mm_jpeg_interface.h" 46#include "mm_jpeg.h" 47#include "mm_jpeg_inlines.h" 48#ifdef LIB2D_ROTATION_ENABLE 49#include "mm_lib2d.h" 50#endif 51 52#define ENCODING_MODE_PARALLEL 1 53 54#define META_KEYFILE QCAMERA_DUMP_FRM_LOCATION"metadata.key" 55 56/** 57 * minimal resolution needed for normal mode of ops 58 */ 59#define MM_JPEG_MIN_NOM_RESOLUTION 7680000 /*8MP*/ 60 61#ifdef MM_JPEG_USE_PIPELINE 62#undef MM_JPEG_CONCURRENT_SESSIONS_COUNT 63#define MM_JPEG_CONCURRENT_SESSIONS_COUNT 1 64#endif 65 66OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent, 67 OMX_PTR pAppData, 68 OMX_BUFFERHEADERTYPE* pBuffer); 69OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent, 70 OMX_PTR pAppData, 71 OMX_BUFFERHEADERTYPE* pBuffer); 72OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent, 73 OMX_PTR pAppData, 74 OMX_EVENTTYPE eEvent, 75 OMX_U32 nData1, 76 OMX_U32 nData2, 77 OMX_PTR pEventData); 78 79static int32_t mm_jpegenc_destroy_job(mm_jpeg_job_session_t *p_session); 80static void mm_jpegenc_job_done(mm_jpeg_job_session_t *p_session); 81mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_dst_ptr( 82 mm_jpeg_queue_t* queue, void * dst_ptr); 83static OMX_ERRORTYPE mm_jpeg_session_configure(mm_jpeg_job_session_t *p_session); 84 85/** mm_jpeg_get_comp_name: 86 * 87 * Arguments: 88 * None 89 * 90 * Return: 91 * Encoder component name 92 * 93 * Description: 94 * Get the name of omx component to be used for jpeg encoding 95 * 96 **/ 97static inline char* mm_jpeg_get_comp_name() 98{ 99#ifdef MM_JPEG_USE_PIPELINE 100 return "OMX.qcom.image.jpeg.encoder_pipeline"; 101#else 102 return "OMX.qcom.image.jpeg.encoder"; 103#endif 104} 105 106/** mm_jpeg_session_send_buffers: 107 * 108 * Arguments: 109 * @data: job session 110 * 111 * Return: 112 * OMX error values 113 * 114 * Description: 115 * Send the buffers to OMX layer 116 * 117 **/ 118OMX_ERRORTYPE mm_jpeg_session_send_buffers(void *data) 119{ 120 uint32_t i = 0; 121 mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data; 122 OMX_ERRORTYPE ret = OMX_ErrorNone; 123 QOMX_BUFFER_INFO lbuffer_info; 124 mm_jpeg_encode_params_t *p_params = &p_session->params; 125 126 memset(&lbuffer_info, 0x0, sizeof(QOMX_BUFFER_INFO)); 127 128 if (p_session->lib2d_rotation_flag) { 129 for (i = 0; i < p_session->num_src_rot_bufs; i++) { 130 lbuffer_info.fd = (OMX_U32)p_session->src_rot_main_buf[i].fd; 131 LOGD("Source rot buffer %d", i); 132 ret = OMX_UseBuffer(p_session->omx_handle, 133 &(p_session->p_in_rot_omx_buf[i]), 0, 134 &lbuffer_info, p_session->src_rot_main_buf[i].buf_size, 135 p_session->src_rot_main_buf[i].buf_vaddr); 136 if (ret) { 137 LOGE("Error %d", ret); 138 return ret; 139 } 140 } 141 } else { 142 for (i = 0; i < p_params->num_src_bufs; i++) { 143 LOGD("Source buffer %d", i); 144 lbuffer_info.fd = (OMX_U32)p_params->src_main_buf[i].fd; 145 ret = OMX_UseBuffer(p_session->omx_handle, 146 &(p_session->p_in_omx_buf[i]), 0, 147 &lbuffer_info, p_params->src_main_buf[i].buf_size, 148 p_params->src_main_buf[i].buf_vaddr); 149 if (ret) { 150 LOGE("Error %d", ret); 151 return ret; 152 } 153 } 154 } 155 156 if (p_session->params.encode_thumbnail) { 157 if (p_session->lib2d_rotation_flag && p_session->thumb_from_main) { 158 for (i = 0; i < p_session->num_src_rot_bufs; i++) { 159 LOGD("Source rot buffer thumb %d", i); 160 lbuffer_info.fd = (OMX_U32)p_session->src_rot_main_buf[i].fd; 161 ret = OMX_UseBuffer(p_session->omx_handle, 162 &(p_session->p_in_rot_omx_thumb_buf[i]), 2, 163 &lbuffer_info, p_session->src_rot_main_buf[i].buf_size, 164 p_session->src_rot_main_buf[i].buf_vaddr); 165 if (ret) { 166 LOGE("Error %d", ret); 167 return ret; 168 } 169 } 170 } else { 171 for (i = 0; i < p_params->num_tmb_bufs; i++) { 172 LOGD("Source tmb buffer %d", i); 173 lbuffer_info.fd = (OMX_U32)p_params->src_thumb_buf[i].fd; 174 ret = OMX_UseBuffer(p_session->omx_handle, 175 &(p_session->p_in_omx_thumb_buf[i]), 2, 176 &lbuffer_info, p_params->src_thumb_buf[i].buf_size, 177 p_params->src_thumb_buf[i].buf_vaddr); 178 if (ret) { 179 LOGE("Error %d", ret); 180 return ret; 181 } 182 } 183 } 184 } 185 186 for (i = 0; i < p_params->num_dst_bufs; i++) { 187 LOGD("Dest buffer %d", i); 188 lbuffer_info.fd = (OMX_U32)p_params->dest_buf[i].fd; 189 ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_out_omx_buf[i]), 190 1, &lbuffer_info, p_params->dest_buf[i].buf_size, 191 p_params->dest_buf[i].buf_vaddr); 192 if (ret) { 193 LOGE("Error"); 194 return ret; 195 } 196 } 197 198 return ret; 199} 200 201 202/** mm_jpeg_session_free_buffers: 203 * 204 * Arguments: 205 * @data: job session 206 * 207 * Return: 208 * OMX error values 209 * 210 * Description: 211 * Free the buffers from OMX layer 212 * 213 **/ 214OMX_ERRORTYPE mm_jpeg_session_free_buffers(void *data) 215{ 216 OMX_ERRORTYPE ret = OMX_ErrorNone; 217 uint32_t i = 0; 218 mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data; 219 mm_jpeg_encode_params_t *p_params = &p_session->params; 220 221 222 if (p_session->lib2d_rotation_flag) { 223 for (i = 0; i < p_session->num_src_rot_bufs; i++) { 224 LOGD("Source rot buffer %d", i); 225 ret = OMX_FreeBuffer(p_session->omx_handle, 0, 226 p_session->p_in_rot_omx_buf[i]); 227 if (ret) { 228 LOGE("Error %d", ret); 229 return ret; 230 } 231 } 232 } else { 233 for (i = 0; i < p_params->num_src_bufs; i++) { 234 LOGD("Source buffer %d", i); 235 ret = OMX_FreeBuffer(p_session->omx_handle, 0, 236 p_session->p_in_omx_buf[i]); 237 if (ret) { 238 LOGE("Error %d", ret); 239 return ret; 240 } 241 } 242 } 243 244 if (p_session->params.encode_thumbnail) { 245 if (p_session->lib2d_rotation_flag && p_session->thumb_from_main) { 246 for (i = 0; i < p_session->num_src_rot_bufs; i++) { 247 LOGD("Source rot buffer thumb %d", i); 248 ret = OMX_FreeBuffer(p_session->omx_handle, 2, 249 p_session->p_in_rot_omx_thumb_buf[i]); 250 if (ret) { 251 LOGE("Error %d", ret); 252 return ret; 253 } 254 } 255 } else { 256 for (i = 0; i < p_params->num_tmb_bufs; i++) { 257 LOGD("Source buffer %d", i); 258 ret = OMX_FreeBuffer(p_session->omx_handle, 2, 259 p_session->p_in_omx_thumb_buf[i]); 260 if (ret) { 261 LOGE("Error %d", ret); 262 return ret; 263 } 264 } 265 } 266 } 267 268 for (i = 0; i < p_params->num_dst_bufs; i++) { 269 LOGD("Dest buffer %d", i); 270 ret = OMX_FreeBuffer(p_session->omx_handle, 1, p_session->p_out_omx_buf[i]); 271 if (ret) { 272 LOGE("Error"); 273 return ret; 274 } 275 } 276 return ret; 277} 278 279 280 281 282/** mm_jpeg_session_change_state: 283 * 284 * Arguments: 285 * @p_session: job session 286 * @new_state: new state to be transitioned to 287 * @p_exec: transition function 288 * 289 * Return: 290 * OMX error values 291 * 292 * Description: 293 * This method is used for state transition 294 * 295 **/ 296OMX_ERRORTYPE mm_jpeg_session_change_state(mm_jpeg_job_session_t* p_session, 297 OMX_STATETYPE new_state, 298 mm_jpeg_transition_func_t p_exec) 299{ 300 OMX_ERRORTYPE ret = OMX_ErrorNone; 301 OMX_STATETYPE current_state; 302 LOGD("new_state %d p_exec %p", 303 new_state, p_exec); 304 305 306 pthread_mutex_lock(&p_session->lock); 307 308 ret = OMX_GetState(p_session->omx_handle, ¤t_state); 309 310 if (ret) { 311 pthread_mutex_unlock(&p_session->lock); 312 return ret; 313 } 314 315 if (current_state == new_state) { 316 pthread_mutex_unlock(&p_session->lock); 317 return OMX_ErrorNone; 318 } 319 320 p_session->state_change_pending = OMX_TRUE; 321 pthread_mutex_unlock(&p_session->lock); 322 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet, 323 new_state, NULL); 324 pthread_mutex_lock(&p_session->lock); 325 if (ret) { 326 LOGE("Error %d", ret); 327 pthread_mutex_unlock(&p_session->lock); 328 return OMX_ErrorIncorrectStateTransition; 329 } 330 if ((OMX_ErrorNone != p_session->error_flag) && 331 (OMX_ErrorOverflow != p_session->error_flag)) { 332 LOGE("Error %d", p_session->error_flag); 333 pthread_mutex_unlock(&p_session->lock); 334 return p_session->error_flag; 335 } 336 if (p_exec) { 337 ret = p_exec(p_session); 338 if (ret) { 339 LOGE("Error %d", ret); 340 pthread_mutex_unlock(&p_session->lock); 341 return ret; 342 } 343 } 344 if (p_session->state_change_pending) { 345 LOGL("before wait"); 346 pthread_cond_wait(&p_session->cond, &p_session->lock); 347 LOGL("after wait"); 348 } 349 pthread_mutex_unlock(&p_session->lock); 350 return ret; 351} 352 353/** mm_jpeg_session_create: 354 * 355 * Arguments: 356 * @p_session: job session 357 * 358 * Return: 359 * OMX error types 360 * 361 * Description: 362 * Create a jpeg encode session 363 * 364 **/ 365OMX_ERRORTYPE mm_jpeg_session_create(mm_jpeg_job_session_t* p_session) 366{ 367 OMX_ERRORTYPE rc = OMX_ErrorNone; 368 mm_jpeg_obj *my_obj = (mm_jpeg_obj *) p_session->jpeg_obj; 369 370 pthread_mutex_init(&p_session->lock, NULL); 371 pthread_cond_init(&p_session->cond, NULL); 372 cirq_reset(&p_session->cb_q); 373 p_session->state_change_pending = OMX_FALSE; 374 p_session->abort_state = MM_JPEG_ABORT_NONE; 375 p_session->error_flag = OMX_ErrorNone; 376 p_session->ebd_count = 0; 377 p_session->fbd_count = 0; 378 p_session->encode_pid = -1; 379 p_session->config = OMX_FALSE; 380 p_session->exif_count_local = 0; 381 p_session->auto_out_buf = OMX_FALSE; 382 383 p_session->omx_callbacks.EmptyBufferDone = mm_jpeg_ebd; 384 p_session->omx_callbacks.FillBufferDone = mm_jpeg_fbd; 385 p_session->omx_callbacks.EventHandler = mm_jpeg_event_handler; 386 387 p_session->thumb_from_main = 0; 388#ifdef MM_JPEG_USE_PIPELINE 389 p_session->thumb_from_main = !p_session->params.thumb_from_postview; 390#endif 391 392 rc = OMX_GetHandle(&p_session->omx_handle, 393 mm_jpeg_get_comp_name(), 394 (void *)p_session, 395 &p_session->omx_callbacks); 396 if (OMX_ErrorNone != rc) { 397 LOGE("OMX_GetHandle failed (%d)", rc); 398 return rc; 399 } 400 401 my_obj->num_sessions++; 402 403 return rc; 404} 405 406 407 408/** mm_jpeg_session_destroy: 409 * 410 * Arguments: 411 * @p_session: job session 412 * 413 * Return: 414 * none 415 * 416 * Description: 417 * Destroy a jpeg encode session 418 * 419 **/ 420void mm_jpeg_session_destroy(mm_jpeg_job_session_t* p_session) 421{ 422 OMX_ERRORTYPE rc = OMX_ErrorNone; 423 OMX_STATETYPE state; 424 uint32_t i; 425 mm_jpeg_obj *my_obj = (mm_jpeg_obj *) p_session->jpeg_obj; 426 427 LOGD("E"); 428 if (NULL == p_session->omx_handle) { 429 LOGE("invalid handle"); 430 return; 431 } 432 433 rc = OMX_GetState(p_session->omx_handle, &state); 434 435 //Check state before state transition 436 if ((state == OMX_StateExecuting) || (state == OMX_StatePause)) { 437 rc = mm_jpeg_session_change_state(p_session, OMX_StateIdle, NULL); 438 if (rc) { 439 LOGE("Error"); 440 } 441 } 442 443 rc = OMX_GetState(p_session->omx_handle, &state); 444 445 if (state == OMX_StateIdle) { 446 rc = mm_jpeg_session_change_state(p_session, OMX_StateLoaded, 447 mm_jpeg_session_free_buffers); 448 if (rc) { 449 LOGE("Error"); 450 } 451 } 452 453 if (p_session->lib2d_rotation_flag) { 454 for (i = 0; i < p_session->num_src_rot_bufs; i++) { 455 if (p_session->src_rot_ion_buffer[i].addr) { 456 buffer_deallocate(&p_session->src_rot_ion_buffer[i]); 457 } 458 } 459 } 460 461 /* If current session is the session in progress 462 set session in progress pointer to null*/ 463 p_session->config = OMX_FALSE; 464 if (my_obj->p_session_inprogress == p_session) { 465 my_obj->p_session_inprogress = NULL; 466 } 467 468 rc = OMX_FreeHandle(p_session->omx_handle); 469 if (0 != rc) { 470 LOGE("OMX_FreeHandle failed (%d)", rc); 471 } 472 p_session->omx_handle = NULL; 473 474 pthread_mutex_destroy(&p_session->lock); 475 pthread_cond_destroy(&p_session->cond); 476 477 if (NULL != p_session->meta_enc_key) { 478 free(p_session->meta_enc_key); 479 p_session->meta_enc_key = NULL; 480 } 481 482 my_obj->num_sessions--; 483 484 // Destroy next session 485 if (p_session->next_session) { 486 mm_jpeg_session_destroy(p_session->next_session); 487 } 488 489 LOGD("Session destroy successful. X"); 490} 491 492 493 494/** mm_jpeg_session_config_main_buffer_offset: 495 * 496 * Arguments: 497 * @p_session: job session 498 * 499 * Return: 500 * OMX error values 501 * 502 * Description: 503 * Configure the buffer offsets 504 * 505 **/ 506OMX_ERRORTYPE mm_jpeg_session_config_main_buffer_offset( 507 mm_jpeg_job_session_t* p_session) 508{ 509 OMX_ERRORTYPE rc = 0; 510 OMX_INDEXTYPE buffer_index; 511 QOMX_YUV_FRAME_INFO frame_info; 512 size_t totalSize = 0; 513 mm_jpeg_encode_params_t *p_params = &p_session->params; 514 515 mm_jpeg_buf_t *p_src_buf = 516 &p_params->src_main_buf[0]; 517 518 memset(&frame_info, 0x0, sizeof(QOMX_YUV_FRAME_INFO)); 519 520 frame_info.cbcrStartOffset[0] = p_src_buf->offset.mp[0].len; 521 frame_info.cbcrStartOffset[1] = p_src_buf->offset.mp[1].len; 522 if (!p_session->lib2d_rotation_flag) { 523 frame_info.yOffset = p_src_buf->offset.mp[0].offset; 524 frame_info.cbcrOffset[0] = p_src_buf->offset.mp[1].offset; 525 frame_info.cbcrOffset[1] = p_src_buf->offset.mp[2].offset; 526 } 527 totalSize = p_src_buf->buf_size; 528 529 rc = OMX_GetExtensionIndex(p_session->omx_handle, 530 QOMX_IMAGE_EXT_BUFFER_OFFSET_NAME, &buffer_index); 531 if (rc != OMX_ErrorNone) { 532 LOGE("Failed"); 533 return rc; 534 } 535 536 LOGD("yOffset = %d, cbcrOffset = (%d %d), totalSize = %zd," 537 "cbcrStartOffset = (%d %d)", 538 (int)frame_info.yOffset, 539 (int)frame_info.cbcrOffset[0], 540 (int)frame_info.cbcrOffset[1], 541 totalSize, 542 (int)frame_info.cbcrStartOffset[0], 543 (int)frame_info.cbcrStartOffset[1]); 544 545 rc = OMX_SetParameter(p_session->omx_handle, buffer_index, &frame_info); 546 if (rc != OMX_ErrorNone) { 547 LOGE("Failed"); 548 return rc; 549 } 550 return rc; 551} 552 553/** mm_jpeg_encoding_mode: 554 * 555 * Arguments: 556 * @p_session: job session 557 * 558 * Return: 559 * OMX error values 560 * 561 * Description: 562 * Configure the serial or parallel encoding 563 * mode 564 * 565 **/ 566OMX_ERRORTYPE mm_jpeg_encoding_mode( 567 mm_jpeg_job_session_t* p_session) 568{ 569 OMX_ERRORTYPE rc = 0; 570 OMX_INDEXTYPE indextype; 571 QOMX_ENCODING_MODE encoding_mode; 572 573 rc = OMX_GetExtensionIndex(p_session->omx_handle, 574 QOMX_IMAGE_EXT_ENCODING_MODE_NAME, &indextype); 575 if (rc != OMX_ErrorNone) { 576 LOGE("Failed"); 577 return rc; 578 } 579 580 if (ENCODING_MODE_PARALLEL) { 581 encoding_mode = OMX_Parallel_Encoding; 582 } else { 583 encoding_mode = OMX_Serial_Encoding; 584 } 585 LOGD("encoding mode = %d ", 586 (int)encoding_mode); 587 rc = OMX_SetParameter(p_session->omx_handle, indextype, &encoding_mode); 588 if (rc != OMX_ErrorNone) { 589 LOGE("Failed"); 590 return rc; 591 } 592 return rc; 593} 594 595/** mm_jpeg_get_speed: 596 * 597 * Arguments: 598 * @p_session: job session 599 * 600 * Return: 601 * ops speed type for jpeg 602 * 603 * Description: 604 * Configure normal or high speed jpeg 605 * 606 **/ 607QOMX_JPEG_SPEED_MODE mm_jpeg_get_speed( 608 mm_jpeg_job_session_t* p_session) 609{ 610 mm_jpeg_encode_params_t *p_params = &p_session->params; 611 cam_dimension_t *p_dim = &p_params->main_dim.src_dim; 612 if (p_params->burst_mode || 613 (MM_JPEG_MIN_NOM_RESOLUTION < (p_dim->width * p_dim->height))) { 614 return QOMX_JPEG_SPEED_MODE_HIGH; 615 } 616 return QOMX_JPEG_SPEED_MODE_NORMAL; 617} 618 619/** mm_jpeg_speed_mode: 620 * 621 * Arguments: 622 * @p_session: job session 623 * 624 * Return: 625 * OMX error values 626 * 627 * Description: 628 * Configure normal or high speed jpeg 629 * 630 **/ 631OMX_ERRORTYPE mm_jpeg_speed_mode( 632 mm_jpeg_job_session_t* p_session) 633{ 634 OMX_ERRORTYPE rc = 0; 635 OMX_INDEXTYPE indextype; 636 QOMX_JPEG_SPEED jpeg_speed; 637 638 rc = OMX_GetExtensionIndex(p_session->omx_handle, 639 QOMX_IMAGE_EXT_JPEG_SPEED_NAME, &indextype); 640 if (rc != OMX_ErrorNone) { 641 LOGE("Failed"); 642 return rc; 643 } 644 645 jpeg_speed.speedMode = mm_jpeg_get_speed(p_session); 646 LOGH("speed %d", jpeg_speed.speedMode); 647 648 rc = OMX_SetParameter(p_session->omx_handle, indextype, &jpeg_speed); 649 if (rc != OMX_ErrorNone) { 650 LOGE("Failed"); 651 return rc; 652 } 653 return rc; 654} 655 656/** mm_jpeg_get_mem: 657 * 658 * Arguments: 659 * @p_out_buf : jpeg output buffer 660 * @p_jpeg_session: job session 661 * 662 * Return: 663 * 0 for success else failure 664 * 665 * Description: 666 * gets the jpeg output buffer 667 * 668 **/ 669static int32_t mm_jpeg_get_mem( 670 omx_jpeg_ouput_buf_t *p_out_buf, void* p_jpeg_session) 671{ 672 int32_t rc = 0; 673 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *)p_jpeg_session; 674 mm_jpeg_encode_params_t *p_params = NULL; 675 mm_jpeg_encode_job_t *p_encode_job = NULL; 676 677 if (!p_session) { 678 LOGE("Invalid input"); 679 return -1; 680 } 681 p_params = &p_session->params; 682 p_encode_job = &p_session->encode_job; 683 if (!p_params || !p_encode_job || !p_params->get_memory) { 684 LOGE("Invalid jpeg encode params"); 685 return -1; 686 } 687 p_params->get_memory(p_out_buf); 688 p_encode_job->ref_count++; 689 p_encode_job->alloc_out_buffer = p_out_buf; 690 LOGD("ref_count %d p_out_buf %p", 691 p_encode_job->ref_count, p_out_buf); 692 return rc; 693} 694 695/** mm_jpeg_put_mem: 696 * 697 * Arguments: 698 * @p_jpeg_session: job session 699 * 700 * Return: 701 * 0 for success else failure 702 * 703 * Description: 704 * releases the jpeg output buffer 705 * 706 **/ 707static int32_t mm_jpeg_put_mem(void* p_jpeg_session) 708{ 709 int32_t rc = 0; 710 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *)p_jpeg_session; 711 mm_jpeg_encode_params_t *p_params = NULL; 712 mm_jpeg_encode_job_t *p_encode_job = NULL; 713 714 if (!p_session) { 715 LOGE("Invalid input"); 716 return -1; 717 } 718 p_params = &p_session->params; 719 p_encode_job = &p_session->encode_job; 720 721 if (!p_params->get_memory) { 722 LOGD("get_mem not defined, ignore put mem"); 723 return 0; 724 } 725 if (!p_params || !p_encode_job || !p_params->put_memory) { 726 LOGE("Invalid jpeg encode params"); 727 return -1; 728 } 729 if ((MM_JPEG_ABORT_NONE != p_session->abort_state) && 730 p_encode_job->ref_count) { 731 omx_jpeg_ouput_buf_t *p_out_buf = 732 ( omx_jpeg_ouput_buf_t *) p_encode_job->alloc_out_buffer; 733 p_params->put_memory(p_out_buf); 734 p_encode_job->ref_count--; 735 p_encode_job->alloc_out_buffer = NULL; 736 } else if (p_encode_job->ref_count) { 737 p_encode_job->ref_count--; 738 } else { 739 LOGW("Buffer already released %d", p_encode_job->ref_count); 740 rc = -1; 741 } 742 LOGD("ref_count %d p_out_buf %p", 743 p_encode_job->ref_count, p_encode_job->alloc_out_buffer); 744 return rc; 745} 746 747/** mm_jpeg_mem_ops: 748 * 749 * Arguments: 750 * @p_session: job session 751 * 752 * Return: 753 * OMX error values 754 * 755 * Description: 756 * Configure the serial or parallel encoding 757 * mode 758 * 759 **/ 760OMX_ERRORTYPE mm_jpeg_mem_ops( 761 mm_jpeg_job_session_t* p_session) 762{ 763 OMX_ERRORTYPE rc = 0; 764 OMX_INDEXTYPE indextype; 765 QOMX_MEM_OPS mem_ops; 766 mm_jpeg_encode_params_t *p_params = &p_session->params; 767 768 if (p_params->get_memory) { 769 mem_ops.get_memory = mm_jpeg_get_mem; 770 } else { 771 mem_ops.get_memory = NULL; 772 LOGH("HAL get_mem handler undefined"); 773 } 774 775 mem_ops.psession = p_session; 776 rc = OMX_GetExtensionIndex(p_session->omx_handle, 777 QOMX_IMAGE_EXT_MEM_OPS_NAME, &indextype); 778 if (rc != OMX_ErrorNone) { 779 LOGE("Failed"); 780 return rc; 781 } 782 783 rc = OMX_SetParameter(p_session->omx_handle, indextype, &mem_ops); 784 if (rc != OMX_ErrorNone) { 785 LOGE("Failed"); 786 return rc; 787 } 788 return rc; 789} 790 791/** mm_jpeg_metadata: 792 * 793 * Arguments: 794 * @p_session: job session 795 * 796 * Return: 797 * OMX error values 798 * 799 * Description: 800 * Pass meta data 801 * 802 **/ 803OMX_ERRORTYPE mm_jpeg_metadata( 804 mm_jpeg_job_session_t* p_session) 805{ 806 OMX_ERRORTYPE rc = OMX_ErrorNone; 807 OMX_INDEXTYPE indexType; 808 QOMX_METADATA lMeta; 809 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 810 mm_jpeg_obj *my_obj = (mm_jpeg_obj *) p_session->jpeg_obj; 811 812 rc = OMX_GetExtensionIndex(p_session->omx_handle, 813 QOMX_IMAGE_EXT_METADATA_NAME, &indexType); 814 815 if (rc != OMX_ErrorNone) { 816 LOGE("Failed"); 817 return rc; 818 } 819 820 lMeta.metadata = (OMX_U8 *)p_jobparams->p_metadata; 821 lMeta.metaPayloadSize = sizeof(*p_jobparams->p_metadata); 822 lMeta.mobicat_mask = p_jobparams->mobicat_mask; 823 lMeta.static_metadata = (OMX_U8 *)my_obj->jpeg_metadata; 824 825 rc = OMX_SetConfig(p_session->omx_handle, indexType, &lMeta); 826 if (rc != OMX_ErrorNone) { 827 LOGE("Failed"); 828 return rc; 829 } 830 return OMX_ErrorNone; 831} 832 833/** mm_jpeg_meta_enc_key: 834 * 835 * Arguments: 836 * @p_session: job session 837 * 838 * Return: 839 * OMX error values 840 * 841 * Description: 842 * Pass metadata encrypt key 843 * 844 **/ 845OMX_ERRORTYPE mm_jpeg_meta_enc_key( 846 mm_jpeg_job_session_t* p_session) 847{ 848 OMX_ERRORTYPE rc = OMX_ErrorNone; 849 OMX_INDEXTYPE indexType; 850 QOMX_META_ENC_KEY lKey; 851 852 lKey.metaKey = p_session->meta_enc_key; 853 lKey.keyLen = p_session->meta_enc_keylen; 854 855 if ((!lKey.metaKey) || (!lKey.keyLen)){ 856 LOGD("Key is invalid"); 857 return OMX_ErrorNone; 858 } 859 860 rc = OMX_GetExtensionIndex(p_session->omx_handle, 861 QOMX_IMAGE_EXT_META_ENC_KEY_NAME, &indexType); 862 863 if (rc != OMX_ErrorNone) { 864 LOGE("Failed"); 865 return rc; 866 } 867 868 rc = OMX_SetConfig(p_session->omx_handle, indexType, &lKey); 869 if (rc != OMX_ErrorNone) { 870 LOGE("Failed"); 871 return rc; 872 } 873 return OMX_ErrorNone; 874} 875 876/** map_jpeg_format: 877 * 878 * Arguments: 879 * @color_fmt: color format 880 * 881 * Return: 882 * OMX color format 883 * 884 * Description: 885 * Map mmjpeg color format to OMX color format 886 * 887 **/ 888int map_jpeg_format(mm_jpeg_color_format color_fmt) 889{ 890 switch (color_fmt) { 891 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2: 892 return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar; 893 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2: 894 return (int)OMX_COLOR_FormatYUV420SemiPlanar; 895 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1: 896 return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar; 897 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1: 898 return (int)OMX_COLOR_FormatYUV422SemiPlanar; 899 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V2: 900 return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar_h1v2; 901 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V2: 902 return (int)OMX_QCOM_IMG_COLOR_FormatYUV422SemiPlanar_h1v2; 903 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V1: 904 return (int)OMX_QCOM_IMG_COLOR_FormatYVU444SemiPlanar; 905 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V1: 906 return (int)OMX_QCOM_IMG_COLOR_FormatYUV444SemiPlanar; 907 case MM_JPEG_COLOR_FORMAT_MONOCHROME: 908 return (int)OMX_COLOR_FormatMonochrome; 909 default: 910 LOGW("invalid format %d", color_fmt); 911 return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar; 912 } 913} 914 915/** mm_jpeg_get_imgfmt_from_colorfmt: 916 * 917 * Arguments: 918 * @color_fmt: color format 919 * 920 * Return: 921 * cam format 922 * 923 * Description: 924 * Get camera image format from color format 925 * 926 **/ 927cam_format_t mm_jpeg_get_imgfmt_from_colorfmt 928 (mm_jpeg_color_format color_fmt) 929{ 930 switch (color_fmt) { 931 case MM_JPEG_COLOR_FORMAT_MONOCHROME: 932 return CAM_FORMAT_Y_ONLY; 933 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2: 934 return CAM_FORMAT_YUV_420_NV21; 935 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2: 936 return CAM_FORMAT_YUV_420_NV12; 937 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1: 938 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V2: 939 return CAM_FORMAT_YUV_422_NV61; 940 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1: 941 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V2: 942 return CAM_FORMAT_YUV_422_NV16; 943 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V1: 944 return CAM_FORMAT_YUV_444_NV42; 945 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V1: 946 return CAM_FORMAT_YUV_444_NV24; 947 default: 948 return CAM_FORMAT_Y_ONLY; 949 } 950} 951 952/** mm_jpeg_session_config_port: 953 * 954 * Arguments: 955 * @p_session: job session 956 * 957 * Return: 958 * OMX error values 959 * 960 * Description: 961 * Configure OMX ports 962 * 963 **/ 964OMX_ERRORTYPE mm_jpeg_session_config_ports(mm_jpeg_job_session_t* p_session) 965{ 966 OMX_ERRORTYPE ret = OMX_ErrorNone; 967 mm_jpeg_encode_params_t *p_params = &p_session->params; 968 OMX_CONFIG_ROTATIONTYPE rotate; 969 970 mm_jpeg_buf_t *p_src_buf = 971 &p_params->src_main_buf[0]; 972 973 p_session->inputPort.nPortIndex = 0; 974 p_session->outputPort.nPortIndex = 1; 975 p_session->inputTmbPort.nPortIndex = 2; 976 977 ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 978 &p_session->inputPort); 979 if (ret) { 980 LOGE("failed"); 981 return ret; 982 } 983 984 ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 985 &p_session->inputTmbPort); 986 if (ret) { 987 LOGE("failed"); 988 return ret; 989 } 990 991 ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 992 &p_session->outputPort); 993 if (ret) { 994 LOGE("failed"); 995 return ret; 996 } 997 998 if (p_session->lib2d_rotation_flag && 999 ((p_session->params.rotation == 90) || 1000 (p_session->params.rotation == 270))) { 1001 p_session->inputPort.format.image.nFrameWidth = 1002 (OMX_U32)p_params->main_dim.src_dim.height; 1003 p_session->inputPort.format.image.nFrameHeight = 1004 (OMX_U32)p_params->main_dim.src_dim.width; 1005 p_session->inputPort.format.image.nStride = 1006 p_src_buf->offset.mp[0].scanline; 1007 p_session->inputPort.format.image.nSliceHeight = 1008 (OMX_U32)p_src_buf->offset.mp[0].stride; 1009 } else { 1010 p_session->inputPort.format.image.nFrameWidth = 1011 (OMX_U32)p_params->main_dim.src_dim.width; 1012 p_session->inputPort.format.image.nFrameHeight = 1013 (OMX_U32)p_params->main_dim.src_dim.height; 1014 p_session->inputPort.format.image.nStride = 1015 p_src_buf->offset.mp[0].stride; 1016 p_session->inputPort.format.image.nSliceHeight = 1017 (OMX_U32)p_src_buf->offset.mp[0].scanline; 1018 } 1019 1020 p_session->inputPort.format.image.eColorFormat = 1021 map_jpeg_format(p_params->color_format); 1022 p_session->inputPort.nBufferSize = 1023 p_params->src_main_buf[0/*p_jobparams->src_index*/].buf_size; 1024 1025 if (p_session->lib2d_rotation_flag) { 1026 p_session->inputPort.nBufferCountActual = 1027 (OMX_U32)p_session->num_src_rot_bufs; 1028 } else { 1029 p_session->inputPort.nBufferCountActual = 1030 (OMX_U32)p_params->num_src_bufs; 1031 } 1032 1033 ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 1034 &p_session->inputPort); 1035 if (ret) { 1036 LOGE("failed"); 1037 return ret; 1038 } 1039 1040 if (p_session->params.encode_thumbnail) { 1041 mm_jpeg_buf_t *p_tmb_buf = 1042 &p_params->src_thumb_buf[0]; 1043 if ((p_session->lib2d_rotation_flag && p_session->thumb_from_main) && 1044 ((p_session->params.rotation == 90) || 1045 (p_session->params.rotation == 270))) { 1046 p_session->inputTmbPort.format.image.nFrameWidth = 1047 (OMX_U32)p_params->thumb_dim.src_dim.height; 1048 p_session->inputTmbPort.format.image.nFrameHeight = 1049 (OMX_U32)p_params->thumb_dim.src_dim.width; 1050 p_session->inputTmbPort.format.image.nStride = 1051 p_tmb_buf->offset.mp[0].scanline; 1052 p_session->inputTmbPort.format.image.nSliceHeight = 1053 (OMX_U32)p_tmb_buf->offset.mp[0].stride; 1054 } else { 1055 p_session->inputTmbPort.format.image.nFrameWidth = 1056 (OMX_U32)p_params->thumb_dim.src_dim.width; 1057 p_session->inputTmbPort.format.image.nFrameHeight = 1058 (OMX_U32)p_params->thumb_dim.src_dim.height; 1059 p_session->inputTmbPort.format.image.nStride = 1060 p_tmb_buf->offset.mp[0].stride; 1061 p_session->inputTmbPort.format.image.nSliceHeight = 1062 (OMX_U32)p_tmb_buf->offset.mp[0].scanline; 1063 } 1064 1065 p_session->inputTmbPort.format.image.eColorFormat = 1066 map_jpeg_format(p_params->thumb_color_format); 1067 p_session->inputTmbPort.nBufferSize = 1068 p_params->src_thumb_buf[0].buf_size; 1069 1070 if (p_session->lib2d_rotation_flag && p_session->thumb_from_main) { 1071 p_session->inputTmbPort.nBufferCountActual = 1072 (OMX_U32)p_session->num_src_rot_bufs; 1073 } else { 1074 p_session->inputTmbPort.nBufferCountActual = 1075 (OMX_U32)p_params->num_tmb_bufs; 1076 } 1077 1078 ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 1079 &p_session->inputTmbPort); 1080 1081 if (ret) { 1082 LOGE("failed"); 1083 return ret; 1084 } 1085 1086 // Enable thumbnail port 1087 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortEnable, 1088 p_session->inputTmbPort.nPortIndex, NULL); 1089 1090 if (ret) { 1091 LOGE("failed"); 1092 return ret; 1093 } 1094 } else { 1095 // Disable thumbnail port 1096 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortDisable, 1097 p_session->inputTmbPort.nPortIndex, NULL); 1098 1099 if (ret) { 1100 LOGE("failed"); 1101 return ret; 1102 } 1103 } 1104 1105 p_session->outputPort.nBufferSize = 1106 p_params->dest_buf[0].buf_size; 1107 p_session->outputPort.nBufferCountActual = (OMX_U32)p_params->num_dst_bufs; 1108 ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 1109 &p_session->outputPort); 1110 if (ret) { 1111 LOGE("failed"); 1112 return ret; 1113 } 1114 1115 /* set rotation */ 1116 memset(&rotate, 0, sizeof(rotate)); 1117 rotate.nPortIndex = 1; 1118 1119 if (p_session->lib2d_rotation_flag) { 1120 rotate.nRotation = 0; 1121 } else { 1122 rotate.nRotation = (OMX_S32)p_params->rotation; 1123 } 1124 1125 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonRotate, 1126 &rotate); 1127 if (OMX_ErrorNone != ret) { 1128 LOGE("Error %d", ret); 1129 return ret; 1130 } 1131 LOGD("Set rotation to %d at port_idx = %d", 1132 (int)p_params->rotation, (int)rotate.nPortIndex); 1133 1134 return ret; 1135} 1136 1137/** mm_jpeg_update_thumbnail_crop 1138 * 1139 * Arguments: 1140 * @p_thumb_dim: thumbnail dimension 1141 * @crop_width : flag indicating if width needs to be cropped 1142 * 1143 * Return: 1144 * OMX error values 1145 * 1146 * Description: 1147 * Updates thumbnail crop aspect ratio based on 1148 * thumbnail destination aspect ratio. 1149 * 1150 */ 1151OMX_ERRORTYPE mm_jpeg_update_thumbnail_crop(mm_jpeg_dim_t *p_thumb_dim, 1152 uint8_t crop_width) 1153{ 1154 OMX_ERRORTYPE ret = OMX_ErrorNone; 1155 int32_t cropped_width = 0, cropped_height = 0; 1156 1157 if (crop_width) { 1158 // Keep height constant 1159 cropped_height = p_thumb_dim->crop.height; 1160 cropped_width = floor((cropped_height * p_thumb_dim->dst_dim.width) / 1161 p_thumb_dim->dst_dim.height); 1162 if (cropped_width % 2) { 1163 cropped_width -= 1; 1164 } 1165 } else { 1166 // Keep width constant 1167 cropped_width = p_thumb_dim->crop.width; 1168 cropped_height = floor((cropped_width * p_thumb_dim->dst_dim.height) / 1169 p_thumb_dim->dst_dim.width); 1170 if (cropped_height % 2) { 1171 cropped_height -= 1; 1172 } 1173 } 1174 p_thumb_dim->crop.left = p_thumb_dim->crop.left + 1175 floor((p_thumb_dim->crop.width - cropped_width) / 2); 1176 if (p_thumb_dim->crop.left % 2) { 1177 p_thumb_dim->crop.left -= 1; 1178 } 1179 p_thumb_dim->crop.top = p_thumb_dim->crop.top + 1180 floor((p_thumb_dim->crop.height - cropped_height) / 2); 1181 if (p_thumb_dim->crop.top % 2) { 1182 p_thumb_dim->crop.top -= 1; 1183 } 1184 p_thumb_dim->crop.width = cropped_width; 1185 p_thumb_dim->crop.height = cropped_height; 1186 1187 LOGH("New thumbnail crop: left %d, top %d, crop width %d," 1188 " crop height %d", p_thumb_dim->crop.left, 1189 p_thumb_dim->crop.top, p_thumb_dim->crop.width, 1190 p_thumb_dim->crop.height); 1191 1192 return ret; 1193} 1194 1195/** mm_jpeg_omx_config_thumbnail: 1196 * 1197 * Arguments: 1198 * @p_session: job session 1199 * 1200 * Return: 1201 * OMX error values 1202 * 1203 * Description: 1204 * Configure OMX ports 1205 * 1206 **/ 1207OMX_ERRORTYPE mm_jpeg_session_config_thumbnail(mm_jpeg_job_session_t* p_session) 1208{ 1209 OMX_ERRORTYPE ret = OMX_ErrorNone; 1210 QOMX_THUMBNAIL_INFO thumbnail_info; 1211 OMX_INDEXTYPE thumb_indextype; 1212 mm_jpeg_encode_params_t *p_params = &p_session->params; 1213 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1214 mm_jpeg_dim_t *p_thumb_dim = &p_jobparams->thumb_dim; 1215 mm_jpeg_dim_t *p_main_dim = &p_jobparams->main_dim; 1216 QOMX_YUV_FRAME_INFO *p_frame_info = &thumbnail_info.tmbOffset; 1217 mm_jpeg_buf_t *p_tmb_buf = &p_params->src_thumb_buf[p_jobparams->thumb_index]; 1218 1219 LOGH("encode_thumbnail %u", 1220 p_params->encode_thumbnail); 1221 if (OMX_FALSE == p_params->encode_thumbnail) { 1222 return ret; 1223 } 1224 1225 if ((p_thumb_dim->dst_dim.width == 0) || (p_thumb_dim->dst_dim.height == 0)) { 1226 LOGE("Error invalid output dim for thumbnail"); 1227 return OMX_ErrorBadParameter; 1228 } 1229 1230 if ((p_thumb_dim->src_dim.width == 0) || (p_thumb_dim->src_dim.height == 0)) { 1231 LOGE("Error invalid input dim for thumbnail"); 1232 return OMX_ErrorBadParameter; 1233 } 1234 1235 if ((p_thumb_dim->crop.width == 0) || (p_thumb_dim->crop.height == 0)) { 1236 p_thumb_dim->crop.width = p_thumb_dim->src_dim.width; 1237 p_thumb_dim->crop.height = p_thumb_dim->src_dim.height; 1238 } 1239 1240 /* check crop boundary */ 1241 if ((p_thumb_dim->crop.width + p_thumb_dim->crop.left > p_thumb_dim->src_dim.width) || 1242 (p_thumb_dim->crop.height + p_thumb_dim->crop.top > p_thumb_dim->src_dim.height)) { 1243 LOGE("invalid crop boundary (%d, %d) offset (%d, %d) out of (%d, %d)", 1244 p_thumb_dim->crop.width, 1245 p_thumb_dim->crop.height, 1246 p_thumb_dim->crop.left, 1247 p_thumb_dim->crop.top, 1248 p_thumb_dim->src_dim.width, 1249 p_thumb_dim->src_dim.height); 1250 return OMX_ErrorBadParameter; 1251 } 1252 1253 memset(&thumbnail_info, 0x0, sizeof(QOMX_THUMBNAIL_INFO)); 1254 ret = OMX_GetExtensionIndex(p_session->omx_handle, 1255 QOMX_IMAGE_EXT_THUMBNAIL_NAME, 1256 &thumb_indextype); 1257 if (ret) { 1258 LOGE("Error %d", ret); 1259 return ret; 1260 } 1261 1262 /* fill thumbnail info */ 1263 thumbnail_info.scaling_enabled = 1; 1264 thumbnail_info.input_width = (OMX_U32)p_thumb_dim->src_dim.width; 1265 thumbnail_info.input_height = (OMX_U32)p_thumb_dim->src_dim.height; 1266 thumbnail_info.rotation = (OMX_U32)p_params->thumb_rotation; 1267 thumbnail_info.quality = (OMX_U32)p_params->thumb_quality; 1268 thumbnail_info.output_width = (OMX_U32)p_thumb_dim->dst_dim.width; 1269 thumbnail_info.output_height = (OMX_U32)p_thumb_dim->dst_dim.height; 1270 1271 if (p_session->thumb_from_main) { 1272 1273 if (p_session->lib2d_rotation_flag) { 1274 thumbnail_info.rotation = 0; 1275 } else { 1276 if ((p_session->params.thumb_rotation == 90 || 1277 p_session->params.thumb_rotation == 270) && 1278 (p_session->params.rotation == 0 || 1279 p_session->params.rotation == 180)) { 1280 1281 thumbnail_info.output_width = (OMX_U32)p_thumb_dim->dst_dim.height; 1282 thumbnail_info.output_height = (OMX_U32)p_thumb_dim->dst_dim.width; 1283 thumbnail_info.rotation = p_session->params.rotation; 1284 } 1285 } 1286 1287 //Thumb FOV should be within main image FOV 1288 if (p_thumb_dim->crop.left < p_main_dim->crop.left) { 1289 p_thumb_dim->crop.left = p_main_dim->crop.left; 1290 } 1291 1292 if (p_thumb_dim->crop.top < p_main_dim->crop.top) { 1293 p_thumb_dim->crop.top = p_main_dim->crop.top; 1294 } 1295 1296 while ((p_thumb_dim->crop.left + p_thumb_dim->crop.width) > 1297 (p_main_dim->crop.left + p_main_dim->crop.width)) { 1298 if (p_thumb_dim->crop.left == p_main_dim->crop.left) { 1299 p_thumb_dim->crop.width = p_main_dim->crop.width; 1300 } else { 1301 p_thumb_dim->crop.left = p_main_dim->crop.left; 1302 } 1303 } 1304 1305 while ((p_thumb_dim->crop.top + p_thumb_dim->crop.height) > 1306 (p_main_dim->crop.top + p_main_dim->crop.height)) { 1307 if (p_thumb_dim->crop.top == p_main_dim->crop.top) { 1308 p_thumb_dim->crop.height = p_main_dim->crop.height; 1309 } else { 1310 p_thumb_dim->crop.top = p_main_dim->crop.top; 1311 } 1312 } 1313 } else if ((p_thumb_dim->dst_dim.width > p_thumb_dim->src_dim.width) || 1314 (p_thumb_dim->dst_dim.height > p_thumb_dim->src_dim.height)) { 1315 LOGE("Incorrect thumbnail dim %dx%d resetting to %dx%d", p_thumb_dim->dst_dim.width, 1316 p_thumb_dim->dst_dim.height, p_thumb_dim->src_dim.width, 1317 p_thumb_dim->src_dim.height); 1318 thumbnail_info.output_width = (OMX_U32)p_thumb_dim->src_dim.width; 1319 thumbnail_info.output_height = (OMX_U32)p_thumb_dim->src_dim.height; 1320 } 1321 1322 // If the thumbnail crop aspect ratio image and thumbnail dest aspect 1323 // ratio are different, reset the thumbnail crop 1324 double thumbcrop_aspect_ratio = (double)p_thumb_dim->crop.width / 1325 (double)p_thumb_dim->crop.height; 1326 double thumbdst_aspect_ratio = (double)p_thumb_dim->dst_dim.width / 1327 (double)p_thumb_dim->dst_dim.height; 1328 if ((thumbdst_aspect_ratio - thumbcrop_aspect_ratio) > 1329 ASPECT_TOLERANCE) { 1330 mm_jpeg_update_thumbnail_crop(p_thumb_dim, 0); 1331 } else if ((thumbcrop_aspect_ratio - thumbdst_aspect_ratio) > 1332 ASPECT_TOLERANCE) { 1333 mm_jpeg_update_thumbnail_crop(p_thumb_dim, 1); 1334 } 1335 1336 // Fill thumbnail crop info 1337 thumbnail_info.crop_info.nWidth = (OMX_U32)p_thumb_dim->crop.width; 1338 thumbnail_info.crop_info.nHeight = (OMX_U32)p_thumb_dim->crop.height; 1339 thumbnail_info.crop_info.nLeft = p_thumb_dim->crop.left; 1340 thumbnail_info.crop_info.nTop = p_thumb_dim->crop.top; 1341 1342 memset(p_frame_info, 0x0, sizeof(*p_frame_info)); 1343 1344 p_frame_info->cbcrStartOffset[0] = p_tmb_buf->offset.mp[0].len; 1345 p_frame_info->cbcrStartOffset[1] = p_tmb_buf->offset.mp[1].len; 1346 p_frame_info->yOffset = p_tmb_buf->offset.mp[0].offset; 1347 p_frame_info->cbcrOffset[0] = p_tmb_buf->offset.mp[1].offset; 1348 p_frame_info->cbcrOffset[1] = p_tmb_buf->offset.mp[2].offset; 1349 1350 if (p_session->lib2d_rotation_flag && p_session->thumb_from_main) { 1351 p_frame_info->yOffset = 0; 1352 p_frame_info->cbcrOffset[0] = 0; 1353 p_frame_info->cbcrOffset[1] = 0; 1354 } 1355 1356 ret = OMX_SetConfig(p_session->omx_handle, thumb_indextype, 1357 &thumbnail_info); 1358 if (ret) { 1359 LOGE("Error"); 1360 return ret; 1361 } 1362 1363 return ret; 1364} 1365 1366/** mm_jpeg_session_config_main_crop: 1367 * 1368 * Arguments: 1369 * @p_session: job session 1370 * 1371 * Return: 1372 * OMX error values 1373 * 1374 * Description: 1375 * Configure main image crop 1376 * 1377 **/ 1378OMX_ERRORTYPE mm_jpeg_session_config_main_crop(mm_jpeg_job_session_t *p_session) 1379{ 1380 OMX_CONFIG_RECTTYPE rect_type_in, rect_type_out; 1381 OMX_ERRORTYPE ret = OMX_ErrorNone; 1382 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1383 mm_jpeg_dim_t *dim = &p_jobparams->main_dim; 1384 1385 if ((dim->crop.width == 0) || (dim->crop.height == 0)) { 1386 dim->crop.width = dim->src_dim.width; 1387 dim->crop.height = dim->src_dim.height; 1388 } 1389 /* error check first */ 1390 if ((dim->crop.width + dim->crop.left > dim->src_dim.width) || 1391 (dim->crop.height + dim->crop.top > dim->src_dim.height)) { 1392 LOGE("invalid crop boundary (%d, %d) out of (%d, %d)", 1393 dim->crop.width + dim->crop.left, 1394 dim->crop.height + dim->crop.top, 1395 dim->src_dim.width, 1396 dim->src_dim.height); 1397 return OMX_ErrorBadParameter; 1398 } 1399 1400 memset(&rect_type_in, 0, sizeof(rect_type_in)); 1401 memset(&rect_type_out, 0, sizeof(rect_type_out)); 1402 rect_type_in.nPortIndex = 0; 1403 rect_type_out.nPortIndex = 0; 1404 1405 if ((dim->src_dim.width != dim->crop.width) || 1406 (dim->src_dim.height != dim->crop.height) || 1407 (dim->src_dim.width != dim->dst_dim.width) || 1408 (dim->src_dim.height != dim->dst_dim.height)) { 1409 /* Scaler information */ 1410 rect_type_in.nWidth = CEILING2(dim->crop.width); 1411 rect_type_in.nHeight = CEILING2(dim->crop.height); 1412 rect_type_in.nLeft = dim->crop.left; 1413 rect_type_in.nTop = dim->crop.top; 1414 1415 if (dim->dst_dim.width && dim->dst_dim.height) { 1416 rect_type_out.nWidth = (OMX_U32)dim->dst_dim.width; 1417 rect_type_out.nHeight = (OMX_U32)dim->dst_dim.height; 1418 } 1419 } 1420 1421 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonInputCrop, 1422 &rect_type_in); 1423 if (OMX_ErrorNone != ret) { 1424 LOGE("Error"); 1425 return ret; 1426 } 1427 1428 LOGH("OMX_IndexConfigCommonInputCrop w = %d, h = %d, l = %d, t = %d," 1429 " port_idx = %d", 1430 (int)rect_type_in.nWidth, (int)rect_type_in.nHeight, 1431 (int)rect_type_in.nLeft, (int)rect_type_in.nTop, 1432 (int)rect_type_in.nPortIndex); 1433 1434 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonOutputCrop, 1435 &rect_type_out); 1436 if (OMX_ErrorNone != ret) { 1437 LOGE("Error"); 1438 return ret; 1439 } 1440 LOGD("OMX_IndexConfigCommonOutputCrop w = %d, h = %d," 1441 " port_idx = %d", 1442 (int)rect_type_out.nWidth, (int)rect_type_out.nHeight, 1443 (int)rect_type_out.nPortIndex); 1444 1445 return ret; 1446} 1447 1448/** mm_jpeg_session_config_main: 1449 * 1450 * Arguments: 1451 * @p_session: job session 1452 * 1453 * Return: 1454 * OMX error values 1455 * 1456 * Description: 1457 * Configure main image 1458 * 1459 **/ 1460OMX_ERRORTYPE mm_jpeg_session_config_main(mm_jpeg_job_session_t *p_session) 1461{ 1462 OMX_ERRORTYPE rc = OMX_ErrorNone; 1463 1464 /* config port */ 1465 LOGD("config port"); 1466 rc = mm_jpeg_session_config_ports(p_session); 1467 if (OMX_ErrorNone != rc) { 1468 LOGE("config port failed"); 1469 return rc; 1470 } 1471 1472 /* config buffer offset */ 1473 LOGD("config main buf offset"); 1474 rc = mm_jpeg_session_config_main_buffer_offset(p_session); 1475 if (OMX_ErrorNone != rc) { 1476 LOGE("config buffer offset failed"); 1477 return rc; 1478 } 1479 1480 /* set the encoding mode */ 1481 rc = mm_jpeg_encoding_mode(p_session); 1482 if (OMX_ErrorNone != rc) { 1483 LOGE("config encoding mode failed"); 1484 return rc; 1485 } 1486 1487 /* set the metadata encrypt key */ 1488 rc = mm_jpeg_meta_enc_key(p_session); 1489 if (OMX_ErrorNone != rc) { 1490 LOGE("config session failed"); 1491 return rc; 1492 } 1493 1494 /* set the mem ops */ 1495 rc = mm_jpeg_mem_ops(p_session); 1496 if (OMX_ErrorNone != rc) { 1497 LOGE("config mem ops failed"); 1498 return rc; 1499 } 1500 /* set the jpeg speed mode */ 1501 rc = mm_jpeg_speed_mode(p_session); 1502 if (OMX_ErrorNone != rc) { 1503 LOGE("config speed mode failed"); 1504 return rc; 1505 } 1506 1507 return rc; 1508} 1509 1510/** mm_jpeg_session_config_common: 1511 * 1512 * Arguments: 1513 * @p_session: job session 1514 * 1515 * Return: 1516 * OMX error values 1517 * 1518 * Description: 1519 * Configure common parameters 1520 * 1521 **/ 1522OMX_ERRORTYPE mm_jpeg_session_config_common(mm_jpeg_job_session_t *p_session) 1523{ 1524 OMX_ERRORTYPE rc = OMX_ErrorNone; 1525 OMX_INDEXTYPE exif_idx; 1526 OMX_CONFIG_ROTATIONTYPE rotate; 1527 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1528 QOMX_EXIF_INFO exif_info; 1529 1530 /* set rotation */ 1531 memset(&rotate, 0, sizeof(rotate)); 1532 rotate.nPortIndex = 1; 1533 1534 if (p_session->lib2d_rotation_flag) { 1535 rotate.nRotation = 0; 1536 } else { 1537 rotate.nRotation = (OMX_S32)p_jobparams->rotation; 1538 } 1539 1540 rc = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonRotate, 1541 &rotate); 1542 if (OMX_ErrorNone != rc) { 1543 LOGE("Error %d", rc); 1544 return rc; 1545 } 1546 LOGD("Set rotation to %d at port_idx = %d", 1547 (int)p_jobparams->rotation, (int)rotate.nPortIndex); 1548 1549 /* Set Exif data*/ 1550 memset(&p_session->exif_info_local[0], 0, sizeof(p_session->exif_info_local)); 1551 rc = OMX_GetExtensionIndex(p_session->omx_handle, QOMX_IMAGE_EXT_EXIF_NAME, 1552 &exif_idx); 1553 if (OMX_ErrorNone != rc) { 1554 LOGE("Error %d", rc); 1555 return rc; 1556 } 1557 1558 LOGD("Num of exif entries passed from HAL: %d", 1559 (int)p_jobparams->exif_info.numOfEntries); 1560 if (p_jobparams->exif_info.numOfEntries > 0) { 1561 rc = OMX_SetConfig(p_session->omx_handle, exif_idx, 1562 &p_jobparams->exif_info); 1563 if (OMX_ErrorNone != rc) { 1564 LOGE("Error %d", rc); 1565 return rc; 1566 } 1567 } 1568 /*parse aditional exif data from the metadata*/ 1569 exif_info.numOfEntries = 0; 1570 exif_info.exif_data = &p_session->exif_info_local[0]; 1571 process_meta_data(p_jobparams->p_metadata, &exif_info, 1572 &p_jobparams->cam_exif_params, p_jobparams->hal_version); 1573 /* After Parse metadata */ 1574 p_session->exif_count_local = (int)exif_info.numOfEntries; 1575 1576 if (exif_info.numOfEntries > 0) { 1577 /* set exif tags */ 1578 LOGD("exif tags from metadata count %d", 1579 (int)exif_info.numOfEntries); 1580 1581 rc = OMX_SetConfig(p_session->omx_handle, exif_idx, 1582 &exif_info); 1583 if (OMX_ErrorNone != rc) { 1584 LOGE("Error %d", rc); 1585 return rc; 1586 } 1587 } 1588 1589 return rc; 1590} 1591 1592/** mm_jpeg_session_abort: 1593 * 1594 * Arguments: 1595 * @p_session: jpeg session 1596 * 1597 * Return: 1598 * OMX_BOOL 1599 * 1600 * Description: 1601 * Abort ongoing job 1602 * 1603 **/ 1604OMX_BOOL mm_jpeg_session_abort(mm_jpeg_job_session_t *p_session) 1605{ 1606 OMX_ERRORTYPE ret = OMX_ErrorNone; 1607 int rc = 0; 1608 1609 LOGD("E"); 1610 pthread_mutex_lock(&p_session->lock); 1611 if (MM_JPEG_ABORT_NONE != p_session->abort_state) { 1612 pthread_mutex_unlock(&p_session->lock); 1613 LOGH("**** ALREADY ABORTED"); 1614 return 0; 1615 } 1616 p_session->abort_state = MM_JPEG_ABORT_INIT; 1617 if (OMX_TRUE == p_session->encoding) { 1618 p_session->state_change_pending = OMX_TRUE; 1619 1620 LOGH("**** ABORTING"); 1621 pthread_mutex_unlock(&p_session->lock); 1622 1623 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet, 1624 OMX_StateIdle, NULL); 1625 1626 if (ret != OMX_ErrorNone) { 1627 LOGE("OMX_SendCommand returned error %d", ret); 1628 return 1; 1629 } 1630 rc = mm_jpegenc_destroy_job(p_session); 1631 if (rc != 0) { 1632 LOGE("Destroy job returned error %d", rc); 1633 } 1634 1635 pthread_mutex_lock(&p_session->lock); 1636 if (MM_JPEG_ABORT_INIT == p_session->abort_state) { 1637 LOGL("before wait"); 1638 pthread_cond_wait(&p_session->cond, &p_session->lock); 1639 } 1640 LOGL("after wait"); 1641 } 1642 p_session->abort_state = MM_JPEG_ABORT_DONE; 1643 1644 mm_jpeg_put_mem((void *)p_session); 1645 1646 pthread_mutex_unlock(&p_session->lock); 1647 1648 // Abort next session 1649 if (p_session->next_session) { 1650 mm_jpeg_session_abort(p_session->next_session); 1651 } 1652 1653 LOGD("X"); 1654 return 0; 1655} 1656 1657/** mm_jpeg_config_multi_image_info 1658 * 1659 * Arguments: 1660 * @p_session: encode session 1661 * 1662 * Return: OMX_ERRORTYPE 1663 * 1664 * Description: 1665 * Configure multi image parameters 1666 * 1667 **/ 1668static OMX_ERRORTYPE mm_jpeg_config_multi_image_info( 1669 mm_jpeg_job_session_t *p_session) 1670{ 1671 OMX_ERRORTYPE ret = OMX_ErrorNone; 1672 QOMX_JPEG_MULTI_IMAGE_INFO multi_image_info; 1673 OMX_INDEXTYPE multi_image_index; 1674 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1675 1676 ret = OMX_GetExtensionIndex(p_session->omx_handle, 1677 QOMX_IMAGE_EXT_MULTI_IMAGE_NAME, &multi_image_index); 1678 if (ret) { 1679 LOGE("Error getting multi image info extention index %d", ret); 1680 return ret; 1681 } 1682 memset(&multi_image_info, 0, sizeof(multi_image_info)); 1683 if (p_jobparams->multi_image_info.type == MM_JPEG_TYPE_MPO) { 1684 multi_image_info.image_type = QOMX_JPEG_IMAGE_TYPE_MPO; 1685 } else { 1686 multi_image_info.image_type = QOMX_JPEG_IMAGE_TYPE_JPEG; 1687 } 1688 multi_image_info.is_primary_image = p_jobparams->multi_image_info.is_primary; 1689 multi_image_info.num_of_images = p_jobparams->multi_image_info.num_of_images; 1690 multi_image_info.enable_metadata = p_jobparams->multi_image_info.enable_metadata; 1691 1692 ret = OMX_SetConfig(p_session->omx_handle, multi_image_index, 1693 &multi_image_info); 1694 if (ret) { 1695 LOGE("Error setting multi image config"); 1696 return ret; 1697 } 1698 return ret; 1699} 1700 1701/** mm_jpeg_configure_params 1702 * 1703 * Arguments: 1704 * @p_session: encode session 1705 * 1706 * Return: 1707 * none 1708 * 1709 * Description: 1710 * Configure the job specific params 1711 * 1712 **/ 1713static OMX_ERRORTYPE mm_jpeg_configure_job_params( 1714 mm_jpeg_job_session_t *p_session) 1715{ 1716 OMX_ERRORTYPE ret = OMX_ErrorNone; 1717 OMX_IMAGE_PARAM_QFACTORTYPE q_factor; 1718 QOMX_WORK_BUFFER work_buffer; 1719 OMX_INDEXTYPE work_buffer_index; 1720 mm_jpeg_encode_params_t *p_params = &p_session->params; 1721 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1722 int i; 1723 1724 /* common config */ 1725 ret = mm_jpeg_session_config_common(p_session); 1726 if (OMX_ErrorNone != ret) { 1727 LOGE("config common failed"); 1728 } 1729 1730 /* config Main Image crop */ 1731 LOGD("config main crop"); 1732 ret = mm_jpeg_session_config_main_crop(p_session); 1733 if (OMX_ErrorNone != ret) { 1734 LOGE("config crop failed"); 1735 return ret; 1736 } 1737 1738 /* set quality */ 1739 memset(&q_factor, 0, sizeof(q_factor)); 1740 q_factor.nPortIndex = 0; 1741 q_factor.nQFactor = p_params->quality; 1742 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexParamQFactor, &q_factor); 1743 LOGD("config QFactor: %d", (int)q_factor.nQFactor); 1744 if (OMX_ErrorNone != ret) { 1745 LOGE("Error setting Q factor %d", ret); 1746 return ret; 1747 } 1748 1749 /* config thumbnail */ 1750 ret = mm_jpeg_session_config_thumbnail(p_session); 1751 if (OMX_ErrorNone != ret) { 1752 LOGE("config thumbnail img failed"); 1753 return ret; 1754 } 1755 1756 //Pass the ION buffer to be used as o/p for HW 1757 memset(&work_buffer, 0x0, sizeof(QOMX_WORK_BUFFER)); 1758 ret = OMX_GetExtensionIndex(p_session->omx_handle, 1759 QOMX_IMAGE_EXT_WORK_BUFFER_NAME, 1760 &work_buffer_index); 1761 if (ret) { 1762 LOGE("Error getting work buffer index %d", ret); 1763 return ret; 1764 } 1765 work_buffer.fd = p_session->work_buffer.p_pmem_fd; 1766 work_buffer.vaddr = p_session->work_buffer.addr; 1767 work_buffer.length = (uint32_t)p_session->work_buffer.size; 1768 LOGH("Work buffer info %d %p WorkBufSize: %d invalidate", 1769 work_buffer.fd, work_buffer.vaddr, work_buffer.length); 1770 1771 buffer_invalidate(&p_session->work_buffer); 1772 1773 ret = OMX_SetConfig(p_session->omx_handle, work_buffer_index, 1774 &work_buffer); 1775 if (ret) { 1776 LOGE("Error"); 1777 return ret; 1778 } 1779 1780 /* set metadata */ 1781 ret = mm_jpeg_metadata(p_session); 1782 if (OMX_ErrorNone != ret) { 1783 LOGE("config makernote data failed"); 1784 return ret; 1785 } 1786 1787 /* set QTable */ 1788 for (i = 0; i < QTABLE_MAX; i++) { 1789 if (p_jobparams->qtable_set[i]) { 1790 ret = OMX_SetConfig(p_session->omx_handle, 1791 OMX_IndexParamQuantizationTable, &p_jobparams->qtable[i]); 1792 if (OMX_ErrorNone != ret) { 1793 LOGE("set QTable Error"); 1794 return ret; 1795 } 1796 } 1797 } 1798 1799 /* Set multi image data*/ 1800 ret = mm_jpeg_config_multi_image_info(p_session); 1801 if (OMX_ErrorNone != ret) { 1802 LOGE("config multi image data failed"); 1803 return ret; 1804 } 1805 1806 return ret; 1807} 1808 1809/** mm_jpeg_session_configure: 1810 * 1811 * Arguments: 1812 * @data: encode session 1813 * 1814 * Return: 1815 * none 1816 * 1817 * Description: 1818 * Configure the session 1819 * 1820 **/ 1821static OMX_ERRORTYPE mm_jpeg_session_configure(mm_jpeg_job_session_t *p_session) 1822{ 1823 OMX_ERRORTYPE ret = OMX_ErrorNone; 1824 1825 LOGD("E "); 1826 1827 MM_JPEG_CHK_ABORT(p_session, ret, error); 1828 1829 /* config main img */ 1830 ret = mm_jpeg_session_config_main(p_session); 1831 if (OMX_ErrorNone != ret) { 1832 LOGE("config main img failed"); 1833 goto error; 1834 } 1835 ret = mm_jpeg_session_change_state(p_session, OMX_StateIdle, 1836 mm_jpeg_session_send_buffers); 1837 if (ret) { 1838 LOGE("change state to idle failed %d", ret); 1839 goto error; 1840 } 1841 1842 ret = mm_jpeg_session_change_state(p_session, OMX_StateExecuting, 1843 NULL); 1844 if (ret) { 1845 LOGE("change state to executing failed %d", ret); 1846 goto error; 1847 } 1848 1849error: 1850 LOGD("X ret %d", ret); 1851 return ret; 1852} 1853 1854 1855 1856 1857 1858 1859/** mm_jpeg_session_encode: 1860 * 1861 * Arguments: 1862 * @p_session: encode session 1863 * 1864 * Return: 1865 * OMX_ERRORTYPE 1866 * 1867 * Description: 1868 * Start the encoding 1869 * 1870 **/ 1871static OMX_ERRORTYPE mm_jpeg_session_encode(mm_jpeg_job_session_t *p_session) 1872{ 1873 OMX_ERRORTYPE ret = OMX_ErrorNone; 1874 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1875 mm_jpeg_obj *my_obj = (mm_jpeg_obj *) p_session->jpeg_obj; 1876 OMX_BUFFERHEADERTYPE *p_in_buf = NULL; 1877 OMX_BUFFERHEADERTYPE *p_in_thumb_buf = NULL; 1878 1879 pthread_mutex_lock(&p_session->lock); 1880 p_session->abort_state = MM_JPEG_ABORT_NONE; 1881 p_session->encoding = OMX_FALSE; 1882 pthread_mutex_unlock(&p_session->lock); 1883 1884 if (p_session->thumb_from_main) { 1885 if (0 > p_jobparams->src_index) { 1886 LOGE("Error"); 1887 ret = OMX_ErrorUnsupportedIndex; 1888 goto error; 1889 } 1890 p_jobparams->thumb_index = (uint32_t)p_jobparams->src_index; 1891 p_jobparams->thumb_dim.crop = p_jobparams->main_dim.crop; 1892 } 1893 1894 if (OMX_FALSE == p_session->config) { 1895 /* If another session in progress clear that sessions configuration */ 1896 if (my_obj->p_session_inprogress != NULL) { 1897 OMX_STATETYPE state; 1898 mm_jpeg_job_session_t *p_session_inprogress = my_obj->p_session_inprogress; 1899 1900 OMX_GetState(p_session_inprogress->omx_handle, &state); 1901 1902 //Check state before state transition 1903 if ((state == OMX_StateExecuting) || (state == OMX_StatePause)) { 1904 ret = mm_jpeg_session_change_state(p_session_inprogress, 1905 OMX_StateIdle, NULL); 1906 if (ret) { 1907 LOGE("Error"); 1908 goto error; 1909 } 1910 } 1911 1912 OMX_GetState(p_session_inprogress->omx_handle, &state); 1913 1914 if (state == OMX_StateIdle) { 1915 ret = mm_jpeg_session_change_state(p_session_inprogress, 1916 OMX_StateLoaded, mm_jpeg_session_free_buffers); 1917 if (ret) { 1918 LOGE("Error"); 1919 goto error; 1920 } 1921 } 1922 p_session_inprogress->config = OMX_FALSE; 1923 my_obj->p_session_inprogress = NULL; 1924 } 1925 1926 ret = mm_jpeg_session_configure(p_session); 1927 if (ret) { 1928 LOGE("Error"); 1929 goto error; 1930 } 1931 p_session->config = OMX_TRUE; 1932 my_obj->p_session_inprogress = p_session; 1933 } 1934 1935 ret = mm_jpeg_configure_job_params(p_session); 1936 if (ret) { 1937 LOGE("Error"); 1938 goto error; 1939 } 1940 pthread_mutex_lock(&p_session->lock); 1941 p_session->encoding = OMX_TRUE; 1942 pthread_mutex_unlock(&p_session->lock); 1943 1944 MM_JPEG_CHK_ABORT(p_session, ret, error); 1945 1946 if (p_session->lib2d_rotation_flag) { 1947 p_in_buf = p_session->p_in_rot_omx_buf[p_jobparams->src_index]; 1948 } else { 1949 p_in_buf = p_session->p_in_omx_buf[p_jobparams->src_index]; 1950 } 1951 1952#ifdef MM_JPEG_DUMP_INPUT 1953 char filename[256]; 1954 snprintf(filename, sizeof(filename), 1955 QCAMERA_DUMP_FRM_LOCATION"jpeg/mm_jpeg_int%d.yuv", p_session->ebd_count); 1956 DUMP_TO_FILE(filename, p_in_buf->pBuffer, (size_t)p_in_buf->nAllocLen); 1957#endif 1958 ret = OMX_EmptyThisBuffer(p_session->omx_handle, p_in_buf); 1959 if (ret) { 1960 LOGE("Error"); 1961 goto error; 1962 } 1963 1964 if (p_session->params.encode_thumbnail) { 1965 1966 if (p_session->thumb_from_main && 1967 p_session->lib2d_rotation_flag) { 1968 p_in_thumb_buf = p_session->p_in_rot_omx_thumb_buf[p_jobparams->thumb_index]; 1969 } else { 1970 p_in_thumb_buf = p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]; 1971 } 1972 1973#ifdef MM_JPEG_DUMP_INPUT 1974 char thumb_filename[FILENAME_MAX]; 1975 snprintf(thumb_filename, sizeof(thumb_filename), 1976 QCAMERA_DUMP_FRM_LOCATION"jpeg/mm_jpeg_int_t%d.yuv", p_session->ebd_count); 1977 DUMP_TO_FILE(thumb_filename, p_in_thumb_buf->pBuffer, 1978 (size_t)p_in_thumb_buf->nAllocLen); 1979#endif 1980 ret = OMX_EmptyThisBuffer(p_session->omx_handle, p_in_thumb_buf); 1981 if (ret) { 1982 LOGE("Error"); 1983 goto error; 1984 } 1985 } 1986 1987 ret = OMX_FillThisBuffer(p_session->omx_handle, 1988 p_session->p_out_omx_buf[p_jobparams->dst_index]); 1989 if (ret) { 1990 LOGE("Error"); 1991 goto error; 1992 } 1993 1994 MM_JPEG_CHK_ABORT(p_session, ret, error); 1995 1996error: 1997 1998 LOGD("X "); 1999 return ret; 2000} 2001 2002/** mm_jpeg_process_encoding_job: 2003 * 2004 * Arguments: 2005 * @my_obj: jpeg client 2006 * @job_node: job node 2007 * 2008 * Return: 2009 * 0 for success -1 otherwise 2010 * 2011 * Description: 2012 * Start the encoding job 2013 * 2014 **/ 2015int32_t mm_jpeg_process_encoding_job(mm_jpeg_obj *my_obj, mm_jpeg_job_q_node_t* job_node) 2016{ 2017 mm_jpeg_q_data_t qdata; 2018 int32_t rc = 0; 2019 OMX_ERRORTYPE ret = OMX_ErrorNone; 2020 mm_jpeg_job_session_t *p_session = NULL; 2021 uint32_t buf_idx; 2022 2023 /* check if valid session */ 2024 p_session = mm_jpeg_get_session(my_obj, job_node->enc_info.job_id); 2025 if (NULL == p_session) { 2026 LOGE("invalid job id %x", 2027 job_node->enc_info.job_id); 2028 return -1; 2029 } 2030 2031 LOGD("before dequeue session %d", ret); 2032 2033 /* dequeue available omx handle */ 2034 qdata = mm_jpeg_queue_deq(p_session->session_handle_q); 2035 p_session = qdata.p; 2036 2037 if (NULL == p_session) { 2038 LOGH("No available sessions %d", ret); 2039 /* No available handles */ 2040 qdata.p = job_node; 2041 mm_jpeg_queue_enq_head(&my_obj->job_mgr.job_queue, qdata); 2042 2043 LOGH("end enqueue %d", ret); 2044 return rc; 2045 2046 } 2047 2048 p_session->auto_out_buf = OMX_FALSE; 2049 if (job_node->enc_info.encode_job.dst_index < 0) { 2050 /* dequeue available output buffer idx */ 2051 qdata = mm_jpeg_queue_deq(p_session->out_buf_q); 2052 buf_idx = qdata.u32; 2053 2054 if (0U == buf_idx) { 2055 LOGE("No available output buffers %d", ret); 2056 return OMX_ErrorUndefined; 2057 } 2058 2059 buf_idx--; 2060 2061 job_node->enc_info.encode_job.dst_index = (int32_t)buf_idx; 2062 p_session->auto_out_buf = OMX_TRUE; 2063 } 2064 2065 /* sent encode cmd to OMX, queue job into ongoing queue */ 2066 qdata.p = job_node; 2067 rc = mm_jpeg_queue_enq(&my_obj->ongoing_job_q, qdata); 2068 if (rc) { 2069 LOGE("jpeg enqueue failed %d", ret); 2070 goto error; 2071 } 2072 2073 p_session->encode_job = job_node->enc_info.encode_job; 2074 p_session->jobId = job_node->enc_info.job_id; 2075 ret = mm_jpeg_session_encode(p_session); 2076 if (ret) { 2077 LOGE("encode session failed"); 2078 goto error; 2079 } 2080 2081 LOGH("Success X "); 2082 return rc; 2083 2084error: 2085 2086 if ((OMX_ErrorNone != ret) && 2087 (NULL != p_session->params.jpeg_cb)) { 2088 p_session->job_status = JPEG_JOB_STATUS_ERROR; 2089 LOGE("send jpeg error callback %d", 2090 p_session->job_status); 2091 p_session->params.jpeg_cb(p_session->job_status, 2092 p_session->client_hdl, 2093 p_session->jobId, 2094 NULL, 2095 p_session->params.userdata); 2096 } 2097 2098 /*remove the job*/ 2099 mm_jpegenc_job_done(p_session); 2100 LOGD("Error X "); 2101 2102 return rc; 2103} 2104 2105 2106 2107/** mm_jpeg_jobmgr_thread: 2108 * 2109 * Arguments: 2110 * @my_obj: jpeg object 2111 * 2112 * Return: 2113 * 0 for success else failure 2114 * 2115 * Description: 2116 * job manager thread main function 2117 * 2118 **/ 2119static void *mm_jpeg_jobmgr_thread(void *data) 2120{ 2121 mm_jpeg_q_data_t qdata; 2122 int rc = 0; 2123 int running = 1; 2124 uint32_t num_ongoing_jobs = 0; 2125 mm_jpeg_obj *my_obj = (mm_jpeg_obj*)data; 2126 mm_jpeg_job_cmd_thread_t *cmd_thread = &my_obj->job_mgr; 2127 mm_jpeg_job_q_node_t* node = NULL; 2128 prctl(PR_SET_NAME, (unsigned long)"mm_jpeg_thread", 0, 0, 0); 2129 2130 do { 2131 do { 2132 rc = cam_sem_wait(&cmd_thread->job_sem); 2133 if (rc != 0 && errno != EINVAL) { 2134 LOGE("cam_sem_wait error (%s)", 2135 strerror(errno)); 2136 return NULL; 2137 } 2138 } while (rc != 0); 2139 2140 /* check ongoing q size */ 2141 num_ongoing_jobs = mm_jpeg_queue_get_size(&my_obj->ongoing_job_q); 2142 2143 LOGD("ongoing job %d %d", num_ongoing_jobs, MM_JPEG_CONCURRENT_SESSIONS_COUNT); 2144 if (num_ongoing_jobs >= MM_JPEG_CONCURRENT_SESSIONS_COUNT) { 2145 LOGE("ongoing job already reach max %d", num_ongoing_jobs); 2146 continue; 2147 } 2148 2149 pthread_mutex_lock(&my_obj->job_lock); 2150 /* can go ahead with new work */ 2151 qdata = mm_jpeg_queue_deq(&cmd_thread->job_queue); 2152 node = (mm_jpeg_job_q_node_t*)qdata.p; 2153 if (node != NULL) { 2154 switch (node->type) { 2155 case MM_JPEG_CMD_TYPE_JOB: 2156 rc = mm_jpeg_process_encoding_job(my_obj, node); 2157 break; 2158 case MM_JPEG_CMD_TYPE_DECODE_JOB: 2159 rc = mm_jpegdec_process_decoding_job(my_obj, node); 2160 break; 2161 case MM_JPEG_CMD_TYPE_EXIT: 2162 default: 2163 /* free node */ 2164 free(node); 2165 /* set running flag to false */ 2166 running = 0; 2167 break; 2168 } 2169 } 2170 pthread_mutex_unlock(&my_obj->job_lock); 2171 2172 } while (running); 2173 return NULL; 2174} 2175 2176/** mm_jpeg_jobmgr_thread_launch: 2177 * 2178 * Arguments: 2179 * @my_obj: jpeg object 2180 * 2181 * Return: 2182 * 0 for success else failure 2183 * 2184 * Description: 2185 * launches the job manager thread 2186 * 2187 **/ 2188int32_t mm_jpeg_jobmgr_thread_launch(mm_jpeg_obj *my_obj) 2189{ 2190 int32_t rc = 0; 2191 mm_jpeg_job_cmd_thread_t *job_mgr = &my_obj->job_mgr; 2192 2193 cam_sem_init(&job_mgr->job_sem, 0); 2194 mm_jpeg_queue_init(&job_mgr->job_queue); 2195 2196 /* launch the thread */ 2197 pthread_create(&job_mgr->pid, 2198 NULL, 2199 mm_jpeg_jobmgr_thread, 2200 (void *)my_obj); 2201 pthread_setname_np(job_mgr->pid, "CAM_jpeg_jobmgr"); 2202 return rc; 2203} 2204 2205/** mm_jpeg_jobmgr_thread_release: 2206 * 2207 * Arguments: 2208 * @my_obj: jpeg object 2209 * 2210 * Return: 2211 * 0 for success else failure 2212 * 2213 * Description: 2214 * Releases the job manager thread 2215 * 2216 **/ 2217int32_t mm_jpeg_jobmgr_thread_release(mm_jpeg_obj * my_obj) 2218{ 2219 mm_jpeg_q_data_t qdata; 2220 int32_t rc = 0; 2221 mm_jpeg_job_cmd_thread_t * cmd_thread = &my_obj->job_mgr; 2222 mm_jpeg_job_q_node_t* node = 2223 (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t)); 2224 if (NULL == node) { 2225 LOGE("No memory for mm_jpeg_job_q_node_t"); 2226 return -1; 2227 } 2228 2229 memset(node, 0, sizeof(mm_jpeg_job_q_node_t)); 2230 node->type = MM_JPEG_CMD_TYPE_EXIT; 2231 2232 qdata.p = node; 2233 mm_jpeg_queue_enq(&cmd_thread->job_queue, qdata); 2234 cam_sem_post(&cmd_thread->job_sem); 2235 2236 /* wait until cmd thread exits */ 2237 if (pthread_join(cmd_thread->pid, NULL) != 0) { 2238 LOGD("pthread dead already"); 2239 } 2240 mm_jpeg_queue_deinit(&cmd_thread->job_queue); 2241 2242 cam_sem_destroy(&cmd_thread->job_sem); 2243 memset(cmd_thread, 0, sizeof(mm_jpeg_job_cmd_thread_t)); 2244 return rc; 2245} 2246 2247/** mm_jpeg_alloc_workbuffer: 2248 * 2249 * Arguments: 2250 * @my_obj: jpeg object 2251 * @work_bufs_need: number of work buffers required 2252 * @work_buf_size: size of the work buffer 2253 * 2254 * Return: 2255 * greater or equal to 0 for success else failure 2256 * 2257 * Description: 2258 * Allocates work buffer 2259 * 2260 **/ 2261int32_t mm_jpeg_alloc_workbuffer(mm_jpeg_obj *my_obj, 2262 uint32_t work_bufs_need, 2263 uint32_t work_buf_size) 2264{ 2265 int32_t rc = 0; 2266 uint32_t i; 2267 LOGH("work_bufs_need %d work_buf_cnt %d", 2268 work_bufs_need, my_obj->work_buf_cnt); 2269 for (i = my_obj->work_buf_cnt; i < work_bufs_need; i++) { 2270 my_obj->ionBuffer[i].size = CEILING32(work_buf_size); 2271 LOGH("Max picture size %d x %d, WorkBufSize = %zu", 2272 my_obj->max_pic_w, my_obj->max_pic_h, my_obj->ionBuffer[i].size); 2273 my_obj->ionBuffer[i].addr = (uint8_t *)buffer_allocate(&my_obj->ionBuffer[i], 1); 2274 if (NULL == my_obj->ionBuffer[i].addr) { 2275 LOGE("Ion allocation failed"); 2276 while (i--) { 2277 buffer_deallocate(&my_obj->ionBuffer[i]); 2278 my_obj->work_buf_cnt--; 2279 } 2280 return -1; 2281 } 2282 my_obj->work_buf_cnt++; 2283 rc = i; 2284 } 2285 LOGH("rc %d ", rc); 2286 return rc; 2287} 2288 2289/** mm_jpeg_release_workbuffer: 2290 * 2291 * Arguments: 2292 * @my_obj: jpeg object 2293 * @work_bufs_need: number of work buffers allocated 2294 * 2295 * Return: 2296 * 0 for success else failure 2297 * 2298 * Description: 2299 * Releases the allocated work buffer 2300 * 2301 **/ 2302int32_t mm_jpeg_release_workbuffer(mm_jpeg_obj *my_obj, 2303 uint32_t work_bufs_need) 2304{ 2305 int32_t rc = 0; 2306 uint32_t i; 2307 LOGH("release work_bufs %d ", work_bufs_need); 2308 for (i = my_obj->work_buf_cnt; i < work_bufs_need; i++) { 2309 buffer_deallocate(&my_obj->ionBuffer[i]); 2310 } 2311 return rc; 2312} 2313 2314/** mm_jpeg_init: 2315 * 2316 * Arguments: 2317 * @my_obj: jpeg object 2318 * 2319 * Return: 2320 * 0 for success else failure 2321 * 2322 * Description: 2323 * Initializes the jpeg client 2324 * 2325 **/ 2326int32_t mm_jpeg_init(mm_jpeg_obj *my_obj) 2327{ 2328 int32_t rc = 0; 2329 uint32_t work_buf_size; 2330 unsigned int initial_workbufs_cnt = 1; 2331 2332 /* init locks */ 2333 pthread_mutex_init(&my_obj->job_lock, NULL); 2334 2335 /* init ongoing job queue */ 2336 rc = mm_jpeg_queue_init(&my_obj->ongoing_job_q); 2337 if (0 != rc) { 2338 LOGE("Error"); 2339 pthread_mutex_destroy(&my_obj->job_lock); 2340 return -1; 2341 } 2342 2343 2344 /* init job semaphore and launch jobmgr thread */ 2345 LOGD("Launch jobmgr thread rc %d", rc); 2346 rc = mm_jpeg_jobmgr_thread_launch(my_obj); 2347 if (0 != rc) { 2348 LOGE("Error"); 2349 mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 2350 pthread_mutex_destroy(&my_obj->job_lock); 2351 return -1; 2352 } 2353 2354 /* set work buf size from max picture size */ 2355 if (my_obj->max_pic_w <= 0 || my_obj->max_pic_h <= 0) { 2356 LOGE("Width and height are not valid " 2357 "dimensions, cannot calc work buf size"); 2358 mm_jpeg_jobmgr_thread_release(my_obj); 2359 mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 2360 pthread_mutex_destroy(&my_obj->job_lock); 2361 return -1; 2362 } 2363 2364 /* allocate work buffer if reproc source buffer is not supposed to be used */ 2365 if (!my_obj->reuse_reproc_buffer) { 2366 work_buf_size = CEILING64((uint32_t)my_obj->max_pic_w) * 2367 CEILING64((uint32_t)my_obj->max_pic_h) * 3U / 2U; 2368 rc = mm_jpeg_alloc_workbuffer(my_obj, initial_workbufs_cnt, work_buf_size); 2369 if (rc == -1) { 2370 LOGE("Work buffer allocation failure"); 2371 return rc; 2372 } 2373 } 2374 2375 /* load OMX */ 2376 if (OMX_ErrorNone != OMX_Init()) { 2377 /* roll back in error case */ 2378 LOGE("OMX_Init failed (%d)", rc); 2379 if (!my_obj->reuse_reproc_buffer) { 2380 mm_jpeg_release_workbuffer(my_obj, initial_workbufs_cnt); 2381 } 2382 mm_jpeg_jobmgr_thread_release(my_obj); 2383 mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 2384 pthread_mutex_destroy(&my_obj->job_lock); 2385 } 2386 2387#ifdef LOAD_ADSP_RPC_LIB 2388 my_obj->adsprpc_lib_handle = dlopen("libadsprpc.so", RTLD_NOW); 2389 if (NULL == my_obj->adsprpc_lib_handle) { 2390 LOGE("Cannot load the library"); 2391 /* not returning error here bcoz even if this loading fails 2392 we can go ahead with SW JPEG enc */ 2393 } 2394#endif 2395 2396 // create dummy OMX handle to avoid dlopen latency 2397 OMX_GetHandle(&my_obj->dummy_handle, mm_jpeg_get_comp_name(), NULL, NULL); 2398 2399 return rc; 2400} 2401 2402/** mm_jpeg_deinit: 2403 * 2404 * Arguments: 2405 * @my_obj: jpeg object 2406 * 2407 * Return: 2408 * 0 for success else failure 2409 * 2410 * Description: 2411 * Deinits the jpeg client 2412 * 2413 **/ 2414int32_t mm_jpeg_deinit(mm_jpeg_obj *my_obj) 2415{ 2416 int32_t rc = 0; 2417 uint32_t i = 0; 2418 2419 /* release jobmgr thread */ 2420 rc = mm_jpeg_jobmgr_thread_release(my_obj); 2421 if (0 != rc) { 2422 LOGE("Error"); 2423 } 2424 2425 if (my_obj->dummy_handle) { 2426 OMX_FreeHandle(my_obj->dummy_handle); 2427 } 2428 2429 /* unload OMX engine */ 2430 OMX_Deinit(); 2431 2432 /* deinit ongoing job and cb queue */ 2433 rc = mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 2434 if (0 != rc) { 2435 LOGE("Error"); 2436 } 2437 2438 for (i = 0; i < my_obj->work_buf_cnt; i++) { 2439 /*Release the ION buffer*/ 2440 rc = buffer_deallocate(&my_obj->ionBuffer[i]); 2441 if (0 != rc) { 2442 LOGE("Error releasing ION buffer"); 2443 } 2444 } 2445 my_obj->work_buf_cnt = 0; 2446 my_obj->jpeg_metadata = NULL; 2447 2448 /* destroy locks */ 2449 pthread_mutex_destroy(&my_obj->job_lock); 2450 2451 return rc; 2452} 2453 2454/** mm_jpeg_new_client: 2455 * 2456 * Arguments: 2457 * @my_obj: jpeg object 2458 * 2459 * Return: 2460 * 0 for success else failure 2461 * 2462 * Description: 2463 * Create new jpeg client 2464 * 2465 **/ 2466uint32_t mm_jpeg_new_client(mm_jpeg_obj *my_obj) 2467{ 2468 uint32_t client_hdl = 0; 2469 uint8_t idx; 2470 int i = 0; 2471 2472 if (my_obj->num_clients >= MAX_JPEG_CLIENT_NUM) { 2473 LOGE("num of clients reached limit"); 2474 return client_hdl; 2475 } 2476 2477 for (idx = 0; idx < MAX_JPEG_CLIENT_NUM; idx++) { 2478 if (0 == my_obj->clnt_mgr[idx].is_used) { 2479 break; 2480 } 2481 } 2482 2483 if (idx < MAX_JPEG_CLIENT_NUM) { 2484 /* client session avail */ 2485 /* generate client handler by index */ 2486 client_hdl = mm_jpeg_util_generate_handler(idx); 2487 2488 /* update client session */ 2489 my_obj->clnt_mgr[idx].is_used = 1; 2490 my_obj->clnt_mgr[idx].client_handle = client_hdl; 2491 2492 pthread_mutex_init(&my_obj->clnt_mgr[idx].lock, NULL); 2493 for (i = 0; i < MM_JPEG_MAX_SESSION; i++) { 2494 memset(&my_obj->clnt_mgr[idx].session[i], 0x0, sizeof(mm_jpeg_job_session_t)); 2495 } 2496 2497 /* increse client count */ 2498 my_obj->num_clients++; 2499 } 2500 2501 return client_hdl; 2502} 2503 2504#ifdef LIB2D_ROTATION_ENABLE 2505/** 2506 * Function: mm_jpeg_lib2d_rotation_cb 2507 * 2508 * Description: Callback that is called on completion of requested job. 2509 * 2510 * Input parameters: 2511 * userdata - App userdata 2512 * jobid - job id that is finished execution 2513 * 2514 * Return values: 2515 * MM_LIB2D_SUCCESS 2516 * MM_LIB2D_ERR_GENERAL 2517 * 2518 * Notes: none 2519 **/ 2520lib2d_error mm_jpeg_lib2d_rotation_cb(void *userdata, int jobid) 2521{ 2522 LOGD("Received CB from lib2d\n"); 2523 return MM_LIB2D_SUCCESS; 2524} 2525 2526/** 2527 * Function: mm_jpeg_lib2d_rotation 2528 * 2529 * Description: lib2d rotation function. 2530 * 2531 * Input parameters: 2532 * p_session - pointer to session 2533 * p_node - pointer to job queue node 2534 * p_job - pointer to job 2535 * p_job_id - pointer to job id 2536 * 2537 * Return values: 2538 * 0 - success 2539 * -1 - failure 2540 * 2541 * Notes: none 2542 **/ 2543int32_t mm_jpeg_lib2d_rotation(mm_jpeg_job_session_t *p_session, 2544 mm_jpeg_job_q_node_t* p_node, mm_jpeg_job_t *p_job, uint32_t *p_job_id) 2545{ 2546 lib2d_error lib2d_err = MM_LIB2D_SUCCESS; 2547 mm_lib2d_buffer src_buffer; 2548 mm_lib2d_buffer dst_buffer; 2549 mm_jpeg_buf_t *p_src_main_buf = p_session->params.src_main_buf; 2550 mm_jpeg_buf_t *p_src_rot_main_buf = p_session->src_rot_main_buf; 2551 mm_jpeg_encode_job_t *p_jobparams = &p_job->encode_job; 2552 mm_jpeg_encode_job_t *p_jobparams_node = &p_node->enc_info.encode_job; 2553 cam_format_t format; 2554 int32_t scanline = 0; 2555 2556 memset(&src_buffer, 0x0, sizeof(mm_lib2d_buffer)); 2557 memset(&dst_buffer, 0x0, sizeof(mm_lib2d_buffer)); 2558 2559 switch (p_session->params.rotation) { 2560 case 0: 2561 break; 2562 case 90: 2563 p_jobparams_node->main_dim.src_dim.width = 2564 p_jobparams->main_dim.src_dim.height; 2565 p_jobparams_node->main_dim.src_dim.height = 2566 p_jobparams->main_dim.src_dim.width; 2567 2568 p_jobparams_node->main_dim.dst_dim.width = 2569 p_jobparams->main_dim.dst_dim.height; 2570 p_jobparams_node->main_dim.dst_dim.height = 2571 p_jobparams->main_dim.dst_dim.width; 2572 2573 p_jobparams_node->main_dim.crop.width = 2574 p_jobparams->main_dim.crop.height; 2575 p_jobparams_node->main_dim.crop.height = 2576 p_jobparams->main_dim.crop.width; 2577 2578 if (p_jobparams->main_dim.crop.top || 2579 p_jobparams->main_dim.crop.height) { 2580 p_jobparams_node->main_dim.crop.left = 2581 p_jobparams->main_dim.src_dim.height - 2582 (p_jobparams->main_dim.crop.top + 2583 p_jobparams->main_dim.crop.height); 2584 } else { 2585 p_jobparams_node->main_dim.crop.left = 0; 2586 } 2587 p_jobparams_node->main_dim.crop.top = 2588 p_jobparams->main_dim.crop.left; 2589 break; 2590 case 180: 2591 if (p_jobparams->main_dim.crop.left || 2592 p_jobparams->main_dim.crop.width) { 2593 p_jobparams_node->main_dim.crop.left = 2594 p_jobparams->main_dim.src_dim.width - 2595 (p_jobparams->main_dim.crop.left + 2596 p_jobparams->main_dim.crop.width); 2597 } else { 2598 p_jobparams_node->main_dim.crop.left = 0; 2599 } 2600 2601 if (p_jobparams->main_dim.crop.top || 2602 p_jobparams->main_dim.crop.height) { 2603 p_jobparams_node->main_dim.crop.top = 2604 p_jobparams->main_dim.src_dim.height - 2605 (p_jobparams->main_dim.crop.top + 2606 p_jobparams->main_dim.crop.height); 2607 } else { 2608 p_jobparams_node->main_dim.crop.top = 0; 2609 } 2610 break; 2611 case 270: 2612 p_jobparams_node->main_dim.src_dim.width = 2613 p_jobparams->main_dim.src_dim.height; 2614 p_jobparams_node->main_dim.src_dim.height = 2615 p_jobparams->main_dim.src_dim.width; 2616 2617 p_jobparams_node->main_dim.dst_dim.width = 2618 p_jobparams->main_dim.dst_dim.height; 2619 p_jobparams_node->main_dim.dst_dim.height = 2620 p_jobparams->main_dim.dst_dim.width; 2621 2622 p_jobparams_node->main_dim.crop.width = 2623 p_jobparams->main_dim.crop.height; 2624 p_jobparams_node->main_dim.crop.height = 2625 p_jobparams->main_dim.crop.width; 2626 p_jobparams_node->main_dim.crop.left = 2627 p_jobparams->main_dim.crop.top; 2628 if (p_jobparams->main_dim.crop.left || 2629 p_jobparams->main_dim.crop.width) { 2630 p_jobparams_node->main_dim.crop.top = 2631 p_jobparams->main_dim.src_dim.width - 2632 (p_jobparams->main_dim.crop.left + 2633 p_jobparams->main_dim.crop.width); 2634 } else { 2635 p_jobparams_node->main_dim.crop.top = 0; 2636 } 2637 break; 2638 } 2639 2640 LOGD("crop wxh %dx%d txl %dx%d", 2641 p_jobparams_node->main_dim.crop.width, 2642 p_jobparams_node->main_dim.crop.height, 2643 p_jobparams_node->main_dim.crop.top, 2644 p_jobparams_node->main_dim.crop.left); 2645 2646 format = mm_jpeg_get_imgfmt_from_colorfmt(p_session->params.color_format); 2647 src_buffer.buffer_type = MM_LIB2D_BUFFER_TYPE_YUV; 2648 src_buffer.yuv_buffer.fd = 2649 p_src_main_buf[p_jobparams->src_index].fd; 2650 src_buffer.yuv_buffer.format = format; 2651 src_buffer.yuv_buffer.width = p_jobparams->main_dim.src_dim.width; 2652 src_buffer.yuv_buffer.height = p_jobparams->main_dim.src_dim.height; 2653 src_buffer.yuv_buffer.plane0 = 2654 p_src_main_buf[p_jobparams->src_index].buf_vaddr; 2655 src_buffer.yuv_buffer.stride0 = 2656 p_src_main_buf[p_jobparams->src_index].offset.mp[0].stride; 2657 scanline = p_src_main_buf[p_jobparams->src_index].offset.mp[0].scanline; 2658 src_buffer.yuv_buffer.plane1 = 2659 (uint8_t*)src_buffer.yuv_buffer.plane0 + 2660 (src_buffer.yuv_buffer.stride0 * scanline); 2661 src_buffer.yuv_buffer.stride1 = src_buffer.yuv_buffer.stride0; 2662 2663 LOGD(" lib2d SRC wxh = %dx%d , stxsl = %dx%d\n", 2664 src_buffer.yuv_buffer.width, src_buffer.yuv_buffer.height, 2665 src_buffer.yuv_buffer.stride0, scanline); 2666 2667 dst_buffer.buffer_type = MM_LIB2D_BUFFER_TYPE_YUV; 2668 dst_buffer.yuv_buffer.fd = 2669 p_src_rot_main_buf[p_jobparams->src_index].fd; 2670 dst_buffer.yuv_buffer.format = format; 2671 dst_buffer.yuv_buffer.width = p_jobparams_node->main_dim.src_dim.width; 2672 dst_buffer.yuv_buffer.height = p_jobparams_node->main_dim.src_dim.height; 2673 dst_buffer.yuv_buffer.plane0 = 2674 p_src_rot_main_buf[p_jobparams->src_index].buf_vaddr; 2675 2676 if ((p_session->params.rotation == 90) || 2677 (p_session->params.rotation == 270)) { 2678 dst_buffer.yuv_buffer.stride0 = 2679 p_src_main_buf[p_jobparams->src_index].offset.mp[0].scanline; 2680 scanline = p_src_main_buf[p_jobparams->src_index].offset.mp[0].stride; 2681 } else { 2682 dst_buffer.yuv_buffer.stride0 = 2683 p_src_main_buf[p_jobparams->src_index].offset.mp[0].stride; 2684 scanline = p_src_main_buf[p_jobparams->src_index].offset.mp[0].scanline; 2685 } 2686 2687 dst_buffer.yuv_buffer.plane1 = 2688 (uint8_t*) dst_buffer.yuv_buffer.plane0 + 2689 (dst_buffer.yuv_buffer.stride0 * scanline); 2690 dst_buffer.yuv_buffer.stride1 = dst_buffer.yuv_buffer.stride0; 2691 2692 LOGD(" lib2d DEST wxh = %dx%d , stxsl = %dx%d\n", 2693 dst_buffer.yuv_buffer.width, dst_buffer.yuv_buffer.height, 2694 dst_buffer.yuv_buffer.stride0, scanline); 2695 2696 LOGD(" lib2d rotation = %d\n", p_session->params.rotation); 2697 2698 lib2d_err = mm_lib2d_start_job(p_session->lib2d_handle, &src_buffer, 2699 &dst_buffer, *p_job_id, NULL, mm_jpeg_lib2d_rotation_cb, 2700 p_session->params.rotation); 2701 if (lib2d_err != MM_LIB2D_SUCCESS) { 2702 LOGE("Error in mm_lib2d_start_job \n"); 2703 return -1; 2704 } 2705 2706 buffer_clean(&p_session->src_rot_ion_buffer[p_jobparams->src_index]); 2707 2708 return 0; 2709} 2710#endif 2711 2712/** mm_jpeg_start_job: 2713 * 2714 * Arguments: 2715 * @my_obj: jpeg object 2716 * @client_hdl: client handle 2717 * @job: pointer to encode job 2718 * @jobId: job id 2719 * 2720 * Return: 2721 * 0 for success else failure 2722 * 2723 * Description: 2724 * Start the encoding job 2725 * 2726 **/ 2727int32_t mm_jpeg_start_job(mm_jpeg_obj *my_obj, 2728 mm_jpeg_job_t *job, 2729 uint32_t *job_id) 2730{ 2731 mm_jpeg_q_data_t qdata; 2732 int32_t rc = -1; 2733 uint8_t session_idx = 0; 2734 uint8_t client_idx = 0; 2735 mm_jpeg_job_q_node_t* node = NULL; 2736 mm_jpeg_job_session_t *p_session = NULL; 2737 mm_jpeg_encode_job_t *p_jobparams = NULL; 2738 uint32_t work_bufs_need; 2739 uint32_t work_buf_size; 2740 2741 *job_id = 0; 2742 2743 if (!job) { 2744 LOGE("invalid job !!!"); 2745 return rc; 2746 } 2747 p_jobparams = &job->encode_job; 2748 2749 /* check if valid session */ 2750 session_idx = GET_SESSION_IDX(p_jobparams->session_id); 2751 client_idx = GET_CLIENT_IDX(p_jobparams->session_id); 2752 LOGD("session_idx %d client idx %d", 2753 session_idx, client_idx); 2754 2755 if ((session_idx >= MM_JPEG_MAX_SESSION) || 2756 (client_idx >= MAX_JPEG_CLIENT_NUM)) { 2757 LOGE("invalid session id %x", 2758 job->encode_job.session_id); 2759 return rc; 2760 } 2761 2762 p_session = &my_obj->clnt_mgr[client_idx].session[session_idx]; 2763 2764 if (my_obj->reuse_reproc_buffer) { 2765 p_session->work_buffer.addr = p_jobparams->work_buf.buf_vaddr; 2766 p_session->work_buffer.size = p_jobparams->work_buf.buf_size; 2767 p_session->work_buffer.ion_info_fd.fd = p_jobparams->work_buf.fd; 2768 p_session->work_buffer.p_pmem_fd = p_jobparams->work_buf.fd; 2769 2770 work_bufs_need = my_obj->num_sessions + 1; 2771 if (work_bufs_need > MM_JPEG_CONCURRENT_SESSIONS_COUNT) { 2772 work_bufs_need = MM_JPEG_CONCURRENT_SESSIONS_COUNT; 2773 } 2774 2775 if (p_session->work_buffer.addr) { 2776 work_bufs_need--; 2777 LOGD("HAL passed the work buffer of size = %d; don't alloc internally", 2778 p_session->work_buffer.size); 2779 } else { 2780 p_session->work_buffer = my_obj->ionBuffer[0]; 2781 } 2782 2783 LOGD(">>>> Work bufs need %d, %d", 2784 work_bufs_need, my_obj->work_buf_cnt); 2785 if (work_bufs_need) { 2786 work_buf_size = CEILING64(my_obj->max_pic_w) * 2787 CEILING64(my_obj->max_pic_h) * 3 / 2; 2788 rc = mm_jpeg_alloc_workbuffer(my_obj, work_bufs_need, work_buf_size); 2789 if (rc == -1) { 2790 LOGE("Work buffer allocation failure"); 2791 return rc; 2792 } else { 2793 p_session->work_buffer = my_obj->ionBuffer[rc]; 2794 } 2795 } 2796 } 2797 2798 if (OMX_FALSE == p_session->active) { 2799 LOGE("session not active %x", 2800 job->encode_job.session_id); 2801 return rc; 2802 } 2803 2804 if ((p_jobparams->src_index >= (int32_t)p_session->params.num_src_bufs) || 2805 (p_jobparams->dst_index >= (int32_t)p_session->params.num_dst_bufs)) { 2806 LOGE("invalid buffer indices"); 2807 return rc; 2808 } 2809 2810 /* enqueue new job into todo job queue */ 2811 node = (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t)); 2812 if (NULL == node) { 2813 LOGE("No memory for mm_jpeg_job_q_node_t"); 2814 return -1; 2815 } 2816 2817 KPI_ATRACE_ASYNC_BEGIN("Camera:JPEG", 2818 (int32_t)(job->encode_job.session_id)); 2819 2820 *job_id = job->encode_job.session_id | 2821 (((uint32_t)p_session->job_hist++ % JOB_HIST_MAX) << 16); 2822 2823 memset(node, 0, sizeof(mm_jpeg_job_q_node_t)); 2824 node->enc_info.encode_job = job->encode_job; 2825 2826#ifdef LIB2D_ROTATION_ENABLE 2827 if (p_session->lib2d_rotation_flag) { 2828 rc = mm_jpeg_lib2d_rotation(p_session, node, job, job_id); 2829 if (rc < 0) { 2830 LOGE("Lib2d rotation failed"); 2831 return rc; 2832 } 2833 } 2834#endif 2835 2836 if (p_session->thumb_from_main) { 2837 node->enc_info.encode_job.thumb_dim.src_dim = 2838 node->enc_info.encode_job.main_dim.src_dim; 2839 node->enc_info.encode_job.thumb_dim.crop = 2840 node->enc_info.encode_job.main_dim.crop; 2841 if (p_session->lib2d_rotation_flag) { 2842 if ((p_session->params.rotation == 90) || 2843 (p_session->params.rotation == 270)) { 2844 node->enc_info.encode_job.thumb_dim.dst_dim.width = 2845 job->encode_job.thumb_dim.dst_dim.height; 2846 node->enc_info.encode_job.thumb_dim.dst_dim.height = 2847 job->encode_job.thumb_dim.dst_dim.width; 2848 } 2849 } 2850 } 2851 node->enc_info.job_id = *job_id; 2852 node->enc_info.client_handle = p_session->client_hdl; 2853 node->type = MM_JPEG_CMD_TYPE_JOB; 2854 2855 qdata.p = node; 2856 rc = mm_jpeg_queue_enq(&my_obj->job_mgr.job_queue, qdata); 2857 if (0 == rc) { 2858 cam_sem_post(&my_obj->job_mgr.job_sem); 2859 } 2860 2861 LOGH("session_idx %u client_idx %u job_id %d X", 2862 session_idx, client_idx, *job_id); 2863 2864 return rc; 2865} 2866 2867 2868 2869/** mm_jpeg_abort_job: 2870 * 2871 * Arguments: 2872 * @my_obj: jpeg object 2873 * @client_hdl: client handle 2874 * @jobId: job id 2875 * 2876 * Return: 2877 * 0 for success else failure 2878 * 2879 * Description: 2880 * Abort the encoding session 2881 * 2882 **/ 2883int32_t mm_jpeg_abort_job(mm_jpeg_obj *my_obj, 2884 uint32_t jobId) 2885{ 2886 int32_t rc = -1; 2887 mm_jpeg_job_q_node_t *node = NULL; 2888 mm_jpeg_job_session_t *p_session = NULL; 2889 2890 pthread_mutex_lock(&my_obj->job_lock); 2891 2892 /* abort job if in todo queue */ 2893 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->job_mgr.job_queue, jobId); 2894 if (NULL != node) { 2895 free(node); 2896 goto abort_done; 2897 } 2898 2899 /* abort job if in ongoing queue */ 2900 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, jobId); 2901 if (NULL != node) { 2902 /* find job that is OMX ongoing, ask OMX to abort the job */ 2903 p_session = mm_jpeg_get_session(my_obj, node->enc_info.job_id); 2904 if (p_session) { 2905 mm_jpeg_session_abort(p_session); 2906 } else { 2907 LOGE("Invalid job id 0x%x", 2908 node->enc_info.job_id); 2909 } 2910 free(node); 2911 goto abort_done; 2912 } 2913 2914abort_done: 2915 pthread_mutex_unlock(&my_obj->job_lock); 2916 2917 return rc; 2918} 2919 2920 2921#ifdef MM_JPEG_READ_META_KEYFILE 2922static int32_t mm_jpeg_read_meta_keyfile(mm_jpeg_job_session_t *p_session, 2923 const char *filename) 2924{ 2925 int rc = 0; 2926 FILE *fp = NULL; 2927 size_t file_size = 0; 2928 fp = fopen(filename, "r"); 2929 if (!fp) { 2930 LOGE("Key not present"); 2931 return -1; 2932 } 2933 fseek(fp, 0, SEEK_END); 2934 file_size = (size_t)ftell(fp); 2935 fseek(fp, 0, SEEK_SET); 2936 2937 p_session->meta_enc_key = (uint8_t *) malloc((file_size + 1) * sizeof(uint8_t)); 2938 2939 if (!p_session->meta_enc_key) { 2940 LOGE("error"); 2941 return -1; 2942 } 2943 2944 fread(p_session->meta_enc_key, 1, file_size, fp); 2945 fclose(fp); 2946 2947 p_session->meta_enc_keylen = file_size; 2948 2949 return rc; 2950} 2951#endif // MM_JPEG_READ_META_KEYFILE 2952 2953/** mm_jpeg_create_session: 2954 * 2955 * Arguments: 2956 * @my_obj: jpeg object 2957 * @client_hdl: client handle 2958 * @p_params: pointer to encode params 2959 * @p_session_id: session id 2960 * 2961 * Return: 2962 * 0 for success else failure 2963 * 2964 * Description: 2965 * Start the encoding session 2966 * 2967 **/ 2968int32_t mm_jpeg_create_session(mm_jpeg_obj *my_obj, 2969 uint32_t client_hdl, 2970 mm_jpeg_encode_params_t *p_params, 2971 uint32_t* p_session_id) 2972{ 2973 mm_jpeg_q_data_t qdata; 2974 int32_t rc = 0; 2975 OMX_ERRORTYPE ret = OMX_ErrorNone; 2976 uint8_t clnt_idx = 0; 2977 int session_idx = -1; 2978 mm_jpeg_job_session_t *p_session = NULL; 2979 mm_jpeg_job_session_t * p_prev_session = NULL; 2980 *p_session_id = 0; 2981 uint32_t i = 0; 2982 uint32_t j = 0; 2983 uint32_t num_omx_sessions = 1; 2984 uint32_t work_buf_size; 2985 mm_jpeg_queue_t *p_session_handle_q, *p_out_buf_q; 2986 uint32_t work_bufs_need; 2987 char trace_tag[32]; 2988 2989 /* validate the parameters */ 2990 if ((p_params->num_src_bufs > MM_JPEG_MAX_BUF) 2991 || (p_params->num_dst_bufs > MM_JPEG_MAX_BUF)) { 2992 LOGE("invalid num buffers"); 2993 return -1; 2994 } 2995 2996 /* check if valid client */ 2997 clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl); 2998 if (clnt_idx >= MAX_JPEG_CLIENT_NUM) { 2999 LOGE("invalid client with handler (%d)", client_hdl); 3000 return -1; 3001 } 3002 3003 if (p_params->burst_mode) { 3004 num_omx_sessions = MM_JPEG_CONCURRENT_SESSIONS_COUNT; 3005 } 3006 3007 if (!my_obj->reuse_reproc_buffer) { 3008 work_bufs_need = num_omx_sessions; 3009 if (work_bufs_need > MM_JPEG_CONCURRENT_SESSIONS_COUNT) { 3010 work_bufs_need = MM_JPEG_CONCURRENT_SESSIONS_COUNT; 3011 } 3012 LOGD(">>>> Work bufs need %d", work_bufs_need); 3013 work_buf_size = CEILING64(my_obj->max_pic_w) * 3014 CEILING64(my_obj->max_pic_h) * 3 / 2; 3015 rc = mm_jpeg_alloc_workbuffer(my_obj, work_bufs_need, work_buf_size); 3016 if (rc == -1) { 3017 LOGE("Work buffer allocation failure"); 3018 return rc; 3019 } 3020 } 3021 3022 3023 /* init omx handle queue */ 3024 p_session_handle_q = (mm_jpeg_queue_t *) malloc(sizeof(*p_session_handle_q)); 3025 if (NULL == p_session_handle_q) { 3026 LOGE("Error"); 3027 goto error1; 3028 } 3029 rc = mm_jpeg_queue_init(p_session_handle_q); 3030 if (0 != rc) { 3031 LOGE("Error"); 3032 free(p_session_handle_q); 3033 goto error1; 3034 } 3035 3036 /* init output buf queue */ 3037 p_out_buf_q = (mm_jpeg_queue_t *) malloc(sizeof(*p_out_buf_q)); 3038 if (NULL == p_out_buf_q) { 3039 LOGE("Error: Cannot allocate memory\n"); 3040 return -1; 3041 } 3042 3043 /* init omx handle queue */ 3044 rc = mm_jpeg_queue_init(p_out_buf_q); 3045 if (0 != rc) { 3046 LOGE("Error"); 3047 free(p_out_buf_q); 3048 goto error1; 3049 } 3050 3051 for (i = 0; i < num_omx_sessions; i++) { 3052 uint32_t buf_idx = 0U; 3053 session_idx = mm_jpeg_get_new_session_idx(my_obj, clnt_idx, &p_session); 3054 if (session_idx < 0 || NULL == p_session) { 3055 LOGE("invalid session id (%d)", session_idx); 3056 goto error2; 3057 } 3058 3059 snprintf(trace_tag, sizeof(trace_tag), "Camera:JPEGsession%d", session_idx); 3060 KPI_ATRACE_ASYNC_BEGIN(trace_tag, session_idx); 3061 3062 p_session->job_index = 0; 3063 3064 p_session->next_session = NULL; 3065 3066 if (p_prev_session) { 3067 p_prev_session->next_session = p_session; 3068 } 3069 p_prev_session = p_session; 3070 3071 buf_idx = i; 3072 if (buf_idx < MM_JPEG_CONCURRENT_SESSIONS_COUNT) { 3073 p_session->work_buffer = my_obj->ionBuffer[buf_idx]; 3074 } else { 3075 LOGE("Invalid Index, Setting buffer add to null"); 3076 p_session->work_buffer.addr = NULL; 3077 p_session->work_buffer.ion_fd = -1; 3078 p_session->work_buffer.p_pmem_fd = -1; 3079 } 3080 3081 p_session->jpeg_obj = (void*)my_obj; /* save a ptr to jpeg_obj */ 3082 3083 /*copy the params*/ 3084 p_session->params = *p_params; 3085 ret = mm_jpeg_session_create(p_session); 3086 if (OMX_ErrorNone != ret) { 3087 p_session->active = OMX_FALSE; 3088 LOGE("jpeg session create failed"); 3089 goto error2; 3090 } 3091 3092 uint32_t session_id = (JOB_ID_MAGICVAL << 24) | 3093 ((uint32_t)session_idx << 8) | clnt_idx; 3094 3095 if (!*p_session_id) { 3096 *p_session_id = session_id; 3097 } 3098 3099 if (p_session->thumb_from_main) { 3100 memcpy(p_session->params.src_thumb_buf, p_session->params.src_main_buf, 3101 sizeof(p_session->params.src_thumb_buf)); 3102 p_session->params.num_tmb_bufs = p_session->params.num_src_bufs; 3103 if (!p_session->params.encode_thumbnail) { 3104 p_session->params.num_tmb_bufs = 0; 3105 } 3106 p_session->params.thumb_dim.src_dim = p_session->params.main_dim.src_dim; 3107 p_session->params.thumb_dim.crop = p_session->params.main_dim.crop; 3108 } 3109#ifdef LIB2D_ROTATION_ENABLE 3110 if (p_session->params.rotation) { 3111 LOGD("Enable lib2d rotation"); 3112 p_session->lib2d_rotation_flag = 1; 3113 3114 cam_format_t lib2d_format; 3115 lib2d_error lib2d_err = MM_LIB2D_SUCCESS; 3116 lib2d_format = 3117 mm_jpeg_get_imgfmt_from_colorfmt(p_session->params.color_format); 3118 lib2d_err = mm_lib2d_init(MM_LIB2D_SYNC_MODE, lib2d_format, 3119 lib2d_format, &p_session->lib2d_handle); 3120 if (lib2d_err != MM_LIB2D_SUCCESS) { 3121 LOGE("lib2d init for rotation failed\n"); 3122 rc = -1; 3123 p_session->lib2d_rotation_flag = 0; 3124 goto error2; 3125 } 3126 } else { 3127 LOGD("Disable lib2d rotation"); 3128 p_session->lib2d_rotation_flag = 0; 3129 } 3130#else 3131 p_session->lib2d_rotation_flag = 0; 3132#endif 3133 3134 if (p_session->lib2d_rotation_flag) { 3135 p_session->num_src_rot_bufs = p_session->params.num_src_bufs; 3136 memset(p_session->src_rot_main_buf, 0, 3137 sizeof(p_session->src_rot_main_buf)); 3138 3139 for (j = 0; j < p_session->num_src_rot_bufs; j++) { 3140 p_session->src_rot_main_buf[j].buf_size = 3141 p_session->params.src_main_buf[j].buf_size; 3142 p_session->src_rot_main_buf[j].format = 3143 p_session->params.src_main_buf[j].format; 3144 p_session->src_rot_main_buf[j].index = j; 3145 3146 memset(&p_session->src_rot_ion_buffer[j], 0, sizeof(buffer_t)); 3147 p_session->src_rot_ion_buffer[j].size = 3148 p_session->src_rot_main_buf[j].buf_size; 3149 p_session->src_rot_ion_buffer[j].addr = 3150 (uint8_t *)buffer_allocate(&p_session->src_rot_ion_buffer[j], 1); 3151 3152 if (NULL == p_session->src_rot_ion_buffer[j].addr) { 3153 LOGE("Ion buff alloc for rotation failed"); 3154 // deallocate all previously allocated rotation ion buffs 3155 for (j = 0; j < p_session->num_src_rot_bufs; j++) { 3156 if (p_session->src_rot_ion_buffer[j].addr) { 3157 buffer_deallocate(&p_session->src_rot_ion_buffer[j]); 3158 } 3159 } 3160 //fall back to SW encoding for rotation 3161 p_session->lib2d_rotation_flag = 0; 3162 } else { 3163 p_session->src_rot_main_buf[j].buf_vaddr = 3164 p_session->src_rot_ion_buffer[j].addr; 3165 p_session->src_rot_main_buf[j].fd = 3166 p_session->src_rot_ion_buffer[j].p_pmem_fd; 3167 } 3168 } 3169 } 3170 3171 p_session->client_hdl = client_hdl; 3172 p_session->sessionId = session_id; 3173 p_session->session_handle_q = p_session_handle_q; 3174 p_session->out_buf_q = p_out_buf_q; 3175 3176 qdata.p = p_session; 3177 mm_jpeg_queue_enq(p_session_handle_q, qdata); 3178 3179 p_session->meta_enc_key = NULL; 3180 p_session->meta_enc_keylen = 0; 3181 3182#ifdef MM_JPEG_READ_META_KEYFILE 3183 mm_jpeg_read_meta_keyfile(p_session, META_KEYFILE); 3184#endif 3185 3186 pthread_mutex_lock(&my_obj->job_lock); 3187 /* Configure session if not already configured and if 3188 no other session configured*/ 3189 if ((OMX_FALSE == p_session->config) && 3190 (my_obj->p_session_inprogress == NULL)) { 3191 rc = mm_jpeg_session_configure(p_session); 3192 if (rc) { 3193 LOGE("Error"); 3194 pthread_mutex_unlock(&my_obj->job_lock); 3195 goto error2; 3196 } 3197 p_session->config = OMX_TRUE; 3198 my_obj->p_session_inprogress = p_session; 3199 } 3200 pthread_mutex_unlock(&my_obj->job_lock); 3201 p_session->num_omx_sessions = num_omx_sessions; 3202 3203 LOGH("session id %x thumb_from_main %d", 3204 session_id, p_session->thumb_from_main); 3205 } 3206 3207 // Queue the output buf indexes 3208 for (i = 0; i < p_params->num_dst_bufs; i++) { 3209 qdata.u32 = i + 1; 3210 mm_jpeg_queue_enq(p_out_buf_q, qdata); 3211 } 3212 3213 return rc; 3214 3215error1: 3216 rc = -1; 3217error2: 3218 if (NULL != p_session) { 3219 KPI_ATRACE_ASYNC_END(trace_tag, session_idx); 3220 } 3221 return rc; 3222} 3223 3224/** mm_jpegenc_destroy_job 3225 * 3226 * Arguments: 3227 * @p_session: Session obj 3228 * 3229 * Return: 3230 * 0 for success else failure 3231 * 3232 * Description: 3233 * Destroy the job based paramenters 3234 * 3235 **/ 3236static int32_t mm_jpegenc_destroy_job(mm_jpeg_job_session_t *p_session) 3237{ 3238 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 3239 int i = 0, rc = 0; 3240 3241 LOGD("Exif entry count %d %d", 3242 (int)p_jobparams->exif_info.numOfEntries, 3243 (int)p_session->exif_count_local); 3244 for (i = 0; i < p_session->exif_count_local; i++) { 3245 rc = releaseExifEntry(&p_session->exif_info_local[i]); 3246 if (rc) { 3247 LOGE("Exif release failed (%d)", rc); 3248 } 3249 } 3250 p_session->exif_count_local = 0; 3251 3252 return rc; 3253} 3254 3255/** mm_jpeg_session_encode: 3256 * 3257 * Arguments: 3258 * @p_session: encode session 3259 * 3260 * Return: 3261 * OMX_ERRORTYPE 3262 * 3263 * Description: 3264 * Start the encoding 3265 * 3266 **/ 3267static void mm_jpegenc_job_done(mm_jpeg_job_session_t *p_session) 3268{ 3269 mm_jpeg_q_data_t qdata; 3270 mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj; 3271 mm_jpeg_job_q_node_t *node = NULL; 3272 3273 /*Destroy job related params*/ 3274 mm_jpegenc_destroy_job(p_session); 3275 3276 /*remove the job*/ 3277 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, 3278 p_session->jobId); 3279 if (node) { 3280 free(node); 3281 } 3282 p_session->encoding = OMX_FALSE; 3283 3284 // Queue to available sessions 3285 qdata.p = p_session; 3286 mm_jpeg_queue_enq(p_session->session_handle_q, qdata); 3287 3288 if (p_session->auto_out_buf) { 3289 //Queue out buf index 3290 qdata.u32 = (uint32_t)(p_session->encode_job.dst_index + 1); 3291 mm_jpeg_queue_enq(p_session->out_buf_q, qdata); 3292 } 3293 3294 /* wake up jobMgr thread to work on new job if there is any */ 3295 cam_sem_post(&my_obj->job_mgr.job_sem); 3296} 3297 3298/** mm_jpeg_destroy_session: 3299 * 3300 * Arguments: 3301 * @my_obj: jpeg object 3302 * @session_id: session index 3303 * 3304 * Return: 3305 * 0 for success else failure 3306 * 3307 * Description: 3308 * Destroy the encoding session 3309 * 3310 **/ 3311int32_t mm_jpeg_destroy_session(mm_jpeg_obj *my_obj, 3312 mm_jpeg_job_session_t *p_session) 3313{ 3314 mm_jpeg_q_data_t qdata; 3315 int32_t rc = 0; 3316 mm_jpeg_job_q_node_t *node = NULL; 3317 uint32_t session_id = 0; 3318 mm_jpeg_job_session_t *p_cur_sess; 3319 char trace_tag[32]; 3320 3321 if (NULL == p_session) { 3322 LOGE("invalid session"); 3323 return rc; 3324 } 3325 3326 session_id = p_session->sessionId; 3327 3328 pthread_mutex_lock(&my_obj->job_lock); 3329 3330 /* abort job if in todo queue */ 3331 LOGD("abort todo jobs"); 3332 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); 3333 while (NULL != node) { 3334 free(node); 3335 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); 3336 } 3337 3338 /* abort job if in ongoing queue */ 3339 LOGD("abort ongoing jobs"); 3340 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); 3341 while (NULL != node) { 3342 free(node); 3343 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); 3344 } 3345 3346 /* abort the current session */ 3347 mm_jpeg_session_abort(p_session); 3348 3349#ifdef LIB2D_ROTATION_ENABLE 3350 lib2d_error lib2d_err = MM_LIB2D_SUCCESS; 3351 if (p_session->lib2d_rotation_flag) { 3352 lib2d_err = mm_lib2d_deinit(p_session->lib2d_handle); 3353 if (lib2d_err != MM_LIB2D_SUCCESS) { 3354 LOGE("Error in mm_lib2d_deinit \n"); 3355 } 3356 } 3357#endif 3358 3359 mm_jpeg_session_destroy(p_session); 3360 3361 p_cur_sess = p_session; 3362 3363 do { 3364 mm_jpeg_remove_session_idx(my_obj, p_cur_sess->sessionId); 3365 } while (NULL != (p_cur_sess = p_cur_sess->next_session)); 3366 3367 3368 pthread_mutex_unlock(&my_obj->job_lock); 3369 3370 while (1) { 3371 qdata = mm_jpeg_queue_deq(p_session->session_handle_q); 3372 if (NULL == qdata.p) 3373 break; 3374 } 3375 mm_jpeg_queue_deinit(p_session->session_handle_q); 3376 free(p_session->session_handle_q); 3377 p_session->session_handle_q = NULL; 3378 3379 while (1) { 3380 qdata = mm_jpeg_queue_deq(p_session->out_buf_q); 3381 if (0U == qdata.u32) 3382 break; 3383 } 3384 mm_jpeg_queue_deinit(p_session->out_buf_q); 3385 free(p_session->out_buf_q); 3386 p_session->out_buf_q = NULL; 3387 3388 3389 /* wake up jobMgr thread to work on new job if there is any */ 3390 cam_sem_post(&my_obj->job_mgr.job_sem); 3391 3392 snprintf(trace_tag, sizeof(trace_tag), "Camera:JPEGsession%d", GET_SESSION_IDX(session_id)); 3393 KPI_ATRACE_ASYNC_END(trace_tag, session_id); 3394 3395 LOGH("destroy session successful. X"); 3396 3397 return rc; 3398} 3399 3400 3401 3402 3403/** mm_jpeg_destroy_session: 3404 * 3405 * Arguments: 3406 * @my_obj: jpeg object 3407 * @session_id: session index 3408 * 3409 * Return: 3410 * 0 for success else failure 3411 * 3412 * Description: 3413 * Destroy the encoding session 3414 * 3415 **/ 3416int32_t mm_jpeg_destroy_session_unlocked(mm_jpeg_obj *my_obj, 3417 mm_jpeg_job_session_t *p_session) 3418{ 3419 int32_t rc = -1; 3420 mm_jpeg_job_q_node_t *node = NULL; 3421 uint32_t session_id = 0; 3422 if (NULL == p_session) { 3423 LOGE("invalid session"); 3424 return rc; 3425 } 3426 3427 session_id = p_session->sessionId; 3428 3429 /* abort job if in todo queue */ 3430 LOGD("abort todo jobs"); 3431 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); 3432 while (NULL != node) { 3433 free(node); 3434 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); 3435 } 3436 3437 /* abort job if in ongoing queue */ 3438 LOGD("abort ongoing jobs"); 3439 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); 3440 while (NULL != node) { 3441 free(node); 3442 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); 3443 } 3444 3445 /* abort the current session */ 3446 mm_jpeg_session_abort(p_session); 3447 //mm_jpeg_remove_session_idx(my_obj, session_id); 3448 3449 return rc; 3450} 3451 3452/** mm_jpeg_destroy_session: 3453 * 3454 * Arguments: 3455 * @my_obj: jpeg object 3456 * @session_id: session index 3457 * 3458 * Return: 3459 * 0 for success else failure 3460 * 3461 * Description: 3462 * Destroy the encoding session 3463 * 3464 **/ 3465int32_t mm_jpeg_destroy_session_by_id(mm_jpeg_obj *my_obj, uint32_t session_id) 3466{ 3467 mm_jpeg_job_session_t *p_session = mm_jpeg_get_session(my_obj, session_id); 3468 3469 return mm_jpeg_destroy_session(my_obj, p_session); 3470} 3471 3472 3473 3474/** mm_jpeg_close: 3475 * 3476 * Arguments: 3477 * @my_obj: jpeg object 3478 * @client_hdl: client handle 3479 * 3480 * Return: 3481 * 0 for success else failure 3482 * 3483 * Description: 3484 * Close the jpeg client 3485 * 3486 **/ 3487int32_t mm_jpeg_close(mm_jpeg_obj *my_obj, uint32_t client_hdl) 3488{ 3489 int32_t rc = -1; 3490 uint8_t clnt_idx = 0; 3491 int i = 0; 3492 3493 /* check if valid client */ 3494 clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl); 3495 if (clnt_idx >= MAX_JPEG_CLIENT_NUM) { 3496 LOGE("invalid client with handler (%d)", client_hdl); 3497 return rc; 3498 } 3499 3500 LOGD("E"); 3501 3502 /* abort all jobs from the client */ 3503 pthread_mutex_lock(&my_obj->job_lock); 3504 3505 for (i = 0; i < MM_JPEG_MAX_SESSION; i++) { 3506 if (OMX_TRUE == my_obj->clnt_mgr[clnt_idx].session[i].active) 3507 mm_jpeg_destroy_session_unlocked(my_obj, 3508 &my_obj->clnt_mgr[clnt_idx].session[i]); 3509 } 3510 3511#ifdef LOAD_ADSP_RPC_LIB 3512 if (NULL != my_obj->adsprpc_lib_handle) { 3513 dlclose(my_obj->adsprpc_lib_handle); 3514 my_obj->adsprpc_lib_handle = NULL; 3515 } 3516#endif 3517 3518 pthread_mutex_unlock(&my_obj->job_lock); 3519 3520 /* invalidate client session */ 3521 pthread_mutex_destroy(&my_obj->clnt_mgr[clnt_idx].lock); 3522 memset(&my_obj->clnt_mgr[clnt_idx], 0, sizeof(mm_jpeg_client_t)); 3523 3524 rc = 0; 3525 LOGD("X"); 3526 return rc; 3527} 3528 3529OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent, 3530 OMX_PTR pAppData, 3531 OMX_BUFFERHEADERTYPE *pBuffer) 3532{ 3533 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData; 3534 3535 LOGH("count %d ", p_session->ebd_count); 3536 pthread_mutex_lock(&p_session->lock); 3537 p_session->ebd_count++; 3538 pthread_mutex_unlock(&p_session->lock); 3539 return 0; 3540} 3541 3542OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent, 3543 OMX_PTR pAppData, 3544 OMX_BUFFERHEADERTYPE *pBuffer) 3545{ 3546 OMX_ERRORTYPE ret = OMX_ErrorNone; 3547 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData; 3548 mm_jpeg_output_t output_buf; 3549 LOGI("count %d ", p_session->fbd_count); 3550 LOGI("KPI Perf] : PROFILE_JPEG_FBD"); 3551 3552 pthread_mutex_lock(&p_session->lock); 3553 KPI_ATRACE_ASYNC_END("Camera:JPEG", p_session->sessionId); 3554 if (MM_JPEG_ABORT_NONE != p_session->abort_state) { 3555 pthread_mutex_unlock(&p_session->lock); 3556 return ret; 3557 } 3558#ifdef MM_JPEG_DUMP_OUT_BS 3559 char filename[256]; 3560 static int bsc; 3561 snprintf(filename, sizeof(filename), 3562 QCAMERA_DUMP_FRM_LOCATION"jpeg/mm_jpeg_bs%d.jpg", bsc++); 3563 DUMP_TO_FILE(filename, 3564 pBuffer->pBuffer, 3565 (size_t)(uint32_t)pBuffer->nFilledLen); 3566#endif 3567 3568 p_session->fbd_count++; 3569 if (NULL != p_session->params.jpeg_cb) { 3570 3571 p_session->job_status = JPEG_JOB_STATUS_DONE; 3572 output_buf.buf_filled_len = (uint32_t)pBuffer->nFilledLen; 3573 output_buf.buf_vaddr = pBuffer->pBuffer; 3574 output_buf.fd = -1; 3575 LOGH("send jpeg callback %d buf 0x%p len %u JobID %u", 3576 p_session->job_status, pBuffer->pBuffer, 3577 (unsigned int)pBuffer->nFilledLen, p_session->jobId); 3578 p_session->params.jpeg_cb(p_session->job_status, 3579 p_session->client_hdl, 3580 p_session->jobId, 3581 &output_buf, 3582 p_session->params.userdata); 3583 3584 mm_jpegenc_job_done(p_session); 3585 3586 mm_jpeg_put_mem((void *)p_session); 3587 } 3588 pthread_mutex_unlock(&p_session->lock); 3589 3590 return ret; 3591} 3592 3593 3594 3595OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent, 3596 OMX_PTR pAppData, 3597 OMX_EVENTTYPE eEvent, 3598 OMX_U32 nData1, 3599 OMX_U32 nData2, 3600 OMX_PTR pEventData) 3601{ 3602 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData; 3603 3604 LOGD("%d %d %d state %d", eEvent, (int)nData1, 3605 (int)nData2, p_session->abort_state); 3606 3607 pthread_mutex_lock(&p_session->lock); 3608 3609 if (MM_JPEG_ABORT_INIT == p_session->abort_state) { 3610 p_session->abort_state = MM_JPEG_ABORT_DONE; 3611 pthread_cond_signal(&p_session->cond); 3612 pthread_mutex_unlock(&p_session->lock); 3613 return OMX_ErrorNone; 3614 } 3615 3616 if (eEvent == OMX_EventError) { 3617 p_session->error_flag = nData2; 3618 if (p_session->encoding == OMX_TRUE) { 3619 LOGE("Error during encoding"); 3620 3621 /* send jpeg callback */ 3622 if (NULL != p_session->params.jpeg_cb) { 3623 p_session->job_status = JPEG_JOB_STATUS_ERROR; 3624 LOGE("send jpeg error callback %d", 3625 p_session->job_status); 3626 p_session->params.jpeg_cb(p_session->job_status, 3627 p_session->client_hdl, 3628 p_session->jobId, 3629 NULL, 3630 p_session->params.userdata); 3631 } 3632 3633 /* remove from ready queue */ 3634 mm_jpegenc_job_done(p_session); 3635 } 3636 pthread_cond_signal(&p_session->cond); 3637 } else if (eEvent == OMX_EventCmdComplete) { 3638 if (p_session->state_change_pending == OMX_TRUE) { 3639 p_session->state_change_pending = OMX_FALSE; 3640 pthread_cond_signal(&p_session->cond); 3641 } 3642 } 3643 3644 pthread_mutex_unlock(&p_session->lock); 3645 return OMX_ErrorNone; 3646} 3647 3648 3649 3650/* remove the first job from the queue with matching client handle */ 3651mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id( 3652 mm_jpeg_queue_t* queue, uint32_t client_hdl) 3653{ 3654 mm_jpeg_q_node_t* node = NULL; 3655 mm_jpeg_job_q_node_t* data = NULL; 3656 mm_jpeg_job_q_node_t* job_node = NULL; 3657 struct cam_list *head = NULL; 3658 struct cam_list *pos = NULL; 3659 3660 pthread_mutex_lock(&queue->lock); 3661 head = &queue->head.list; 3662 pos = head->next; 3663 while(pos != head) { 3664 node = member_of(pos, mm_jpeg_q_node_t, list); 3665 data = (mm_jpeg_job_q_node_t *)node->data.p; 3666 3667 if (data && (data->enc_info.client_handle == client_hdl)) { 3668 LOGH("found matching client handle"); 3669 job_node = data; 3670 cam_list_del_node(&node->list); 3671 queue->size--; 3672 free(node); 3673 LOGH("queue size = %d", queue->size); 3674 break; 3675 } 3676 pos = pos->next; 3677 } 3678 3679 pthread_mutex_unlock(&queue->lock); 3680 3681 return job_node; 3682} 3683 3684/* remove the first job from the queue with matching session id */ 3685mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_session_id( 3686 mm_jpeg_queue_t* queue, uint32_t session_id) 3687{ 3688 mm_jpeg_q_node_t* node = NULL; 3689 mm_jpeg_job_q_node_t* data = NULL; 3690 mm_jpeg_job_q_node_t* job_node = NULL; 3691 struct cam_list *head = NULL; 3692 struct cam_list *pos = NULL; 3693 3694 pthread_mutex_lock(&queue->lock); 3695 head = &queue->head.list; 3696 pos = head->next; 3697 while(pos != head) { 3698 node = member_of(pos, mm_jpeg_q_node_t, list); 3699 data = (mm_jpeg_job_q_node_t *)node->data.p; 3700 3701 if (data && (data->enc_info.encode_job.session_id == session_id)) { 3702 LOGH("found matching session id"); 3703 job_node = data; 3704 cam_list_del_node(&node->list); 3705 queue->size--; 3706 free(node); 3707 LOGH("queue size = %d", queue->size); 3708 break; 3709 } 3710 pos = pos->next; 3711 } 3712 3713 pthread_mutex_unlock(&queue->lock); 3714 3715 return job_node; 3716} 3717 3718/* remove job from the queue with matching job id */ 3719mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id( 3720 mm_jpeg_queue_t* queue, uint32_t job_id) 3721{ 3722 mm_jpeg_q_node_t* node = NULL; 3723 mm_jpeg_job_q_node_t* data = NULL; 3724 mm_jpeg_job_q_node_t* job_node = NULL; 3725 struct cam_list *head = NULL; 3726 struct cam_list *pos = NULL; 3727 uint32_t lq_job_id; 3728 3729 pthread_mutex_lock(&queue->lock); 3730 head = &queue->head.list; 3731 pos = head->next; 3732 while(pos != head) { 3733 node = member_of(pos, mm_jpeg_q_node_t, list); 3734 data = (mm_jpeg_job_q_node_t *)node->data.p; 3735 3736 if(NULL == data) { 3737 LOGE("Data is NULL"); 3738 pthread_mutex_unlock(&queue->lock); 3739 return NULL; 3740 } 3741 3742 if (data->type == MM_JPEG_CMD_TYPE_DECODE_JOB) { 3743 lq_job_id = data->dec_info.job_id; 3744 } else { 3745 lq_job_id = data->enc_info.job_id; 3746 } 3747 3748 if (data && (lq_job_id == job_id)) { 3749 LOGD("found matching job id"); 3750 job_node = data; 3751 cam_list_del_node(&node->list); 3752 queue->size--; 3753 free(node); 3754 break; 3755 } 3756 pos = pos->next; 3757 } 3758 3759 pthread_mutex_unlock(&queue->lock); 3760 3761 return job_node; 3762} 3763 3764/* remove job from the queue with matching job id */ 3765mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_unlk( 3766 mm_jpeg_queue_t* queue, uint32_t job_id) 3767{ 3768 mm_jpeg_q_node_t* node = NULL; 3769 mm_jpeg_job_q_node_t* data = NULL; 3770 mm_jpeg_job_q_node_t* job_node = NULL; 3771 struct cam_list *head = NULL; 3772 struct cam_list *pos = NULL; 3773 3774 head = &queue->head.list; 3775 pos = head->next; 3776 while(pos != head) { 3777 node = member_of(pos, mm_jpeg_q_node_t, list); 3778 data = (mm_jpeg_job_q_node_t *)node->data.p; 3779 3780 if (data && (data->enc_info.job_id == job_id)) { 3781 job_node = data; 3782 cam_list_del_node(&node->list); 3783 queue->size--; 3784 free(node); 3785 break; 3786 } 3787 pos = pos->next; 3788 } 3789 3790 return job_node; 3791} 3792