1 /* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. 2 * 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions are 5 * met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer in the documentation and/or other materials provided 11 * with the distribution. 12 * * Neither the name of The Linux Foundation nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30 #include <pthread.h> 31 #include <errno.h> 32 #include <sys/ioctl.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <sys/prctl.h> 36 #include <fcntl.h> 37 #include <poll.h> 38 39 #include "mm_jpeg_dbg.h" 40 #include "mm_jpeg_interface.h" 41 #include "mm_jpeg.h" 42 43 /* define max num of supported concurrent jpeg jobs by OMX engine. 44 * Current, only one per time */ 45 #define NUM_MAX_JPEG_CNCURRENT_JOBS 1 46 47 #define JOB_ID_MAGICVAL 0x1 48 #define JOB_HIST_MAX 10000 49 50 /** DUMP_TO_FILE: 51 * @filename: file name 52 * @p_addr: address of the buffer 53 * @len: buffer length 54 * 55 * dump the image to the file 56 **/ 57 #define DUMP_TO_FILE(filename, p_addr, len) ({ \ 58 int rc = 0; \ 59 FILE *fp = fopen(filename, "w+"); \ 60 if (fp) { \ 61 rc = fwrite(p_addr, 1, len, fp); \ 62 CDBG_HIGH("%s:%d] written size %d", __func__, __LINE__, len); \ 63 fclose(fp); \ 64 } else { \ 65 CDBG_ERROR("%s:%d] open %s failed", __func__, __LINE__, filename); \ 66 } \ 67 }) 68 69 /** DUMP_TO_FILE2: 70 * @filename: file name 71 * @p_addr: address of the buffer 72 * @len: buffer length 73 * 74 * dump the image to the file if the memory is non-contiguous 75 **/ 76 #define DUMP_TO_FILE2(filename, p_addr1, len1, paddr2, len2) ({ \ 77 int rc = 0; \ 78 FILE *fp = fopen(filename, "w+"); \ 79 if (fp) { \ 80 rc = fwrite(p_addr1, 1, len1, fp); \ 81 rc = fwrite(p_addr2, 1, len2, fp); \ 82 CDBG_HIGH("%s:%d] written %d %d", __func__, __LINE__, len1, len2); \ 83 fclose(fp); \ 84 } else { \ 85 CDBG_ERROR("%s:%d] open %s failed", __func__, __LINE__, filename); \ 86 } \ 87 }) 88 89 /** MM_JPEG_CHK_ABORT: 90 * @p: client pointer 91 * @ret: return value 92 * @label: label to jump to 93 * 94 * check the abort failure 95 **/ 96 #define MM_JPEG_CHK_ABORT(p, ret, label) ({ \ 97 if (OMX_TRUE == p->abort_flag) { \ 98 CDBG_ERROR("%s:%d] jpeg abort", __func__, __LINE__); \ 99 ret = OMX_ErrorNone; \ 100 goto label; \ 101 } \ 102 }) 103 104 #define GET_CLIENT_IDX(x) ((x) & 0xff) 105 #define GET_SESSION_IDX(x) (((x) >> 8) & 0xff) 106 #define GET_JOB_IDX(x) (((x) >> 16) & 0xff) 107 108 OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent, 109 OMX_PTR pAppData, 110 OMX_BUFFERHEADERTYPE* pBuffer); 111 OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent, 112 OMX_PTR pAppData, 113 OMX_BUFFERHEADERTYPE* pBuffer); 114 OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent, 115 OMX_PTR pAppData, 116 OMX_EVENTTYPE eEvent, 117 OMX_U32 nData1, 118 OMX_U32 nData2, 119 OMX_PTR pEventData); 120 121 /** cirq_reset: 122 * 123 * Arguments: 124 * @q: circular queue 125 * 126 * Return: 127 * none 128 * 129 * Description: 130 * Resets the circular queue 131 * 132 **/ 133 static inline void cirq_reset(mm_jpeg_cirq_t *q) 134 { 135 q->front = 0; 136 q->rear = 0; 137 q->count = 0; 138 pthread_mutex_init(&q->lock, NULL); 139 } 140 141 /** cirq_empty: 142 * 143 * Arguments: 144 * @q: circular queue 145 * 146 * Return: 147 * none 148 * 149 * Description: 150 * check if the curcular queue is empty 151 * 152 **/ 153 #define cirq_empty(q) (q->count == 0) 154 155 /** cirq_full: 156 * 157 * Arguments: 158 * @q: circular queue 159 * 160 * Return: 161 * none 162 * 163 * Description: 164 * check if the curcular queue is full 165 * 166 **/ 167 #define cirq_full(q) (q->count == MM_JPEG_CIRQ_SIZE) 168 169 /** cirq_enqueue: 170 * 171 * Arguments: 172 * @q: circular queue 173 * @data: data to be inserted 174 * 175 * Return: 176 * true/false 177 * 178 * Description: 179 * enqueue an element into circular queue 180 * 181 **/ 182 #define cirq_enqueue(q, type, data) ({ \ 183 int rc = 0; \ 184 pthread_mutex_lock(&q->lock); \ 185 if (cirq_full(q)) { \ 186 rc = -1; \ 187 } else { \ 188 q->type[q->rear] = data; \ 189 q->rear = (q->rear + 1) % MM_JPEG_CIRQ_SIZE; \ 190 q->count++; \ 191 } \ 192 pthread_mutex_unlock(&q->lock); \ 193 rc; \ 194 }) 195 196 /** cirq_dequeue: 197 * 198 * Arguments: 199 * @q: circular queue 200 * @data: data to be popped 201 * 202 * Return: 203 * true/false 204 * 205 * Description: 206 * dequeue an element from the circular queue 207 * 208 **/ 209 #define cirq_dequeue(q, type, data) ({ \ 210 int rc = 0; \ 211 pthread_mutex_lock(&q->lock); \ 212 if (cirq_empty(q)) { \ 213 pthread_mutex_unlock(&q->lock); \ 214 rc = -1; \ 215 } else { \ 216 data = q->type[q->front]; \ 217 q->count--; \ 218 } \ 219 pthread_mutex_unlock(&q->lock); \ 220 rc; \ 221 }) 222 223 /** 224 * 225 * special queue functions for job queue 226 **/ 227 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id( 228 mm_jpeg_queue_t* queue, uint32_t client_hdl); 229 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id( 230 mm_jpeg_queue_t* queue, uint32_t job_id); 231 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_session_id( 232 mm_jpeg_queue_t* queue, uint32_t session_id); 233 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_unlk( 234 mm_jpeg_queue_t* queue, uint32_t job_id); 235 236 /** mm_jpeg_pending_func_t: 237 * 238 * Intermediate function for transition change 239 **/ 240 typedef OMX_ERRORTYPE (*mm_jpeg_transition_func_t)(void *); 241 242 243 /** mm_jpeg_queue_func_t: 244 * 245 * Intermediate function for queue operation 246 **/ 247 typedef void (*mm_jpeg_queue_func_t)(void *); 248 249 /** mm_jpeg_session_send_buffers: 250 * 251 * Arguments: 252 * @data: job session 253 * 254 * Return: 255 * OMX error values 256 * 257 * Description: 258 * Send the buffers to OMX layer 259 * 260 **/ 261 OMX_ERRORTYPE mm_jpeg_session_send_buffers(void *data) 262 { 263 uint32_t i = 0; 264 mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data; 265 OMX_ERRORTYPE ret = OMX_ErrorNone; 266 QOMX_BUFFER_INFO lbuffer_info; 267 mm_jpeg_encode_params_t *p_params = &p_session->params; 268 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 269 270 memset(&lbuffer_info, 0x0, sizeof(QOMX_BUFFER_INFO)); 271 for (i = 0; i < p_params->num_src_bufs; i++) { 272 CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i); 273 lbuffer_info.fd = p_params->src_main_buf[i].fd; 274 ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_in_omx_buf[i]), 0, 275 &lbuffer_info, p_params->src_main_buf[i].buf_size, 276 p_params->src_main_buf[i].buf_vaddr); 277 if (ret) { 278 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 279 return ret; 280 } 281 } 282 283 for (i = 0; i < p_params->num_tmb_bufs; i++) { 284 CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i); 285 lbuffer_info.fd = p_params->src_thumb_buf[i].fd; 286 ret = OMX_UseBuffer(p_session->omx_handle, 287 &(p_session->p_in_omx_thumb_buf[i]), 2, 288 &lbuffer_info, p_params->src_thumb_buf[i].buf_size, 289 p_params->src_thumb_buf[i].buf_vaddr); 290 if (ret) { 291 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 292 return ret; 293 } 294 } 295 296 for (i = 0; i < p_params->num_dst_bufs; i++) { 297 CDBG("%s:%d] Dest buffer %d", __func__, __LINE__, i); 298 ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_out_omx_buf[i]), 299 1, NULL, p_params->dest_buf[i].buf_size, 300 p_params->dest_buf[i].buf_vaddr); 301 if (ret) { 302 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 303 return ret; 304 } 305 } 306 CDBG("%s:%d]", __func__, __LINE__); 307 return ret; 308 } 309 310 /** mm_jpeg_session_free_buffers: 311 * 312 * Arguments: 313 * @data: job session 314 * 315 * Return: 316 * OMX error values 317 * 318 * Description: 319 * Free the buffers from OMX layer 320 * 321 **/ 322 OMX_ERRORTYPE mm_jpeg_session_free_buffers(void *data) 323 { 324 OMX_ERRORTYPE ret = OMX_ErrorNone; 325 uint32_t i = 0; 326 mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data; 327 mm_jpeg_encode_params_t *p_params = &p_session->params; 328 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 329 330 for (i = 0; i < p_params->num_src_bufs; i++) { 331 CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i); 332 ret = OMX_FreeBuffer(p_session->omx_handle, 0, p_session->p_in_omx_buf[i]); 333 if (ret) { 334 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 335 return ret; 336 } 337 } 338 339 for (i = 0; i < p_params->num_tmb_bufs; i++) { 340 CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i); 341 ret = OMX_FreeBuffer(p_session->omx_handle, 2, p_session->p_in_omx_thumb_buf[i]); 342 if (ret) { 343 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 344 return ret; 345 } 346 } 347 348 for (i = 0; i < p_params->num_dst_bufs; i++) { 349 CDBG("%s:%d] Dest buffer %d", __func__, __LINE__, i); 350 ret = OMX_FreeBuffer(p_session->omx_handle, 1, p_session->p_out_omx_buf[i]); 351 if (ret) { 352 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 353 return ret; 354 } 355 } 356 CDBG("%s:%d]", __func__, __LINE__); 357 return ret; 358 } 359 360 /** mm_jpeg_session_change_state: 361 * 362 * Arguments: 363 * @p_session: job session 364 * @new_state: new state to be transitioned to 365 * @p_exec: transition function 366 * 367 * Return: 368 * OMX error values 369 * 370 * Description: 371 * This method is used for state transition 372 * 373 **/ 374 OMX_ERRORTYPE mm_jpeg_session_change_state(mm_jpeg_job_session_t* p_session, 375 OMX_STATETYPE new_state, 376 mm_jpeg_transition_func_t p_exec) 377 { 378 OMX_ERRORTYPE ret = OMX_ErrorNone; 379 OMX_STATETYPE current_state; 380 CDBG("%s:%d] new_state %d p_exec %p", __func__, __LINE__, 381 new_state, p_exec); 382 383 384 pthread_mutex_lock(&p_session->lock); 385 386 ret = OMX_GetState(p_session->omx_handle, ¤t_state); 387 388 if (ret) { 389 pthread_mutex_unlock(&p_session->lock); 390 return ret; 391 } 392 393 if (current_state == new_state) { 394 pthread_mutex_unlock(&p_session->lock); 395 return OMX_ErrorNone; 396 } 397 398 p_session->state_change_pending = OMX_TRUE; 399 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet, 400 new_state, NULL); 401 if (ret) { 402 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 403 pthread_mutex_unlock(&p_session->lock); 404 return OMX_ErrorIncorrectStateTransition; 405 } 406 CDBG("%s:%d] ", __func__, __LINE__); 407 if (OMX_ErrorNone != p_session->error_flag) { 408 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, p_session->error_flag); 409 pthread_mutex_unlock(&p_session->lock); 410 return p_session->error_flag; 411 } 412 if (p_exec) { 413 ret = p_exec(p_session); 414 if (ret) { 415 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 416 pthread_mutex_unlock(&p_session->lock); 417 return ret; 418 } 419 } 420 CDBG("%s:%d] ", __func__, __LINE__); 421 if (p_session->state_change_pending) { 422 CDBG("%s:%d] before wait", __func__, __LINE__); 423 pthread_cond_wait(&p_session->cond, &p_session->lock); 424 CDBG("%s:%d] after wait", __func__, __LINE__); 425 } 426 pthread_mutex_unlock(&p_session->lock); 427 CDBG("%s:%d] ", __func__, __LINE__); 428 return ret; 429 } 430 431 /** mm_jpeg_session_create: 432 * 433 * Arguments: 434 * @p_session: job session 435 * 436 * Return: 437 * OMX error types 438 * 439 * Description: 440 * Create a jpeg encode session 441 * 442 **/ 443 OMX_ERRORTYPE mm_jpeg_session_create(mm_jpeg_job_session_t* p_session) 444 { 445 OMX_ERRORTYPE rc = OMX_ErrorNone; 446 mm_jpeg_cirq_t *p_cirq = NULL; 447 448 pthread_mutex_init(&p_session->lock, NULL); 449 pthread_cond_init(&p_session->cond, NULL); 450 cirq_reset(&p_session->cb_q); 451 p_session->state_change_pending = OMX_FALSE; 452 p_session->abort_flag = OMX_FALSE; 453 p_session->error_flag = OMX_ErrorNone; 454 p_session->ebd_count = 0; 455 p_session->fbd_count = 0; 456 p_session->encode_pid = -1; 457 p_session->config = OMX_FALSE; 458 p_session->exif_count_local = 0; 459 460 p_session->omx_callbacks.EmptyBufferDone = mm_jpeg_ebd; 461 p_session->omx_callbacks.FillBufferDone = mm_jpeg_fbd; 462 p_session->omx_callbacks.EventHandler = mm_jpeg_event_handler; 463 rc = OMX_GetHandle(&p_session->omx_handle, 464 "OMX.qcom.image.jpeg.encoder", 465 (void *)p_session, 466 &p_session->omx_callbacks); 467 468 if (OMX_ErrorNone != rc) { 469 CDBG_ERROR("%s:%d] OMX_GetHandle failed (%d)", __func__, __LINE__, rc); 470 return rc; 471 } 472 return rc; 473 } 474 475 /** mm_jpeg_session_destroy: 476 * 477 * Arguments: 478 * @p_session: job session 479 * 480 * Return: 481 * none 482 * 483 * Description: 484 * Destroy a jpeg encode session 485 * 486 **/ 487 void mm_jpeg_session_destroy(mm_jpeg_job_session_t* p_session) 488 { 489 OMX_ERRORTYPE rc = OMX_ErrorNone; 490 491 CDBG("%s:%d] E", __func__, __LINE__); 492 if (NULL == p_session->omx_handle) { 493 CDBG_ERROR("%s:%d] invalid handle", __func__, __LINE__); 494 return; 495 } 496 497 rc = mm_jpeg_session_change_state(p_session, OMX_StateIdle, NULL); 498 if (rc) { 499 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 500 } 501 502 rc = mm_jpeg_session_change_state(p_session, OMX_StateLoaded, 503 mm_jpeg_session_free_buffers); 504 if (rc) { 505 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 506 } 507 508 rc = OMX_FreeHandle(p_session->omx_handle); 509 if (0 != rc) { 510 CDBG_ERROR("%s:%d] OMX_FreeHandle failed (%d)", __func__, __LINE__, rc); 511 } 512 p_session->omx_handle = NULL; 513 514 pthread_mutex_destroy(&p_session->lock); 515 pthread_cond_destroy(&p_session->cond); 516 CDBG("%s:%d] X", __func__, __LINE__); 517 } 518 519 /** mm_jpeg_session_config_main_buffer_offset: 520 * 521 * Arguments: 522 * @p_session: job session 523 * 524 * Return: 525 * OMX error values 526 * 527 * Description: 528 * Configure the buffer offsets 529 * 530 **/ 531 OMX_ERRORTYPE mm_jpeg_session_config_main_buffer_offset( 532 mm_jpeg_job_session_t* p_session) 533 { 534 OMX_ERRORTYPE rc = 0; 535 int32_t i = 0; 536 OMX_INDEXTYPE buffer_index; 537 QOMX_YUV_FRAME_INFO frame_info; 538 int32_t totalSize = 0; 539 mm_jpeg_encode_params_t *p_params = &p_session->params; 540 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 541 542 mm_jpeg_buf_t *p_src_buf = 543 &p_params->src_main_buf[p_jobparams->src_index]; 544 545 memset(&frame_info, 0x0, sizeof(QOMX_YUV_FRAME_INFO)); 546 547 frame_info.cbcrStartOffset[0] = p_src_buf->offset.mp[0].len; 548 frame_info.cbcrStartOffset[1] = p_src_buf->offset.mp[1].len; 549 frame_info.yOffset = p_src_buf->offset.mp[0].offset; 550 frame_info.cbcrOffset[0] = p_src_buf->offset.mp[1].offset; 551 frame_info.cbcrOffset[1] = p_src_buf->offset.mp[2].offset; 552 totalSize = p_src_buf->buf_size; 553 554 rc = OMX_GetExtensionIndex(p_session->omx_handle, 555 QOMX_IMAGE_EXT_BUFFER_OFFSET_NAME, &buffer_index); 556 if (rc != OMX_ErrorNone) { 557 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 558 return rc; 559 } 560 561 CDBG_HIGH("%s:%d] yOffset = %d, cbcrOffset = (%d %d), totalSize = %d," 562 "cbcrStartOffset = (%d %d)", __func__, __LINE__, 563 (int)frame_info.yOffset, 564 (int)frame_info.cbcrOffset[0], 565 (int)frame_info.cbcrOffset[1], 566 totalSize, 567 (int)frame_info.cbcrStartOffset[0], 568 (int)frame_info.cbcrStartOffset[1]); 569 570 rc = OMX_SetParameter(p_session->omx_handle, buffer_index, &frame_info); 571 if (rc != OMX_ErrorNone) { 572 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 573 return rc; 574 } 575 return rc; 576 } 577 578 /** mm_jpeg_encoding_mode: 579 * 580 * Arguments: 581 * @p_session: job session 582 * 583 * Return: 584 * OMX error values 585 * 586 * Description: 587 * Configure the serial or parallel encoding 588 * mode 589 * 590 **/ 591 OMX_ERRORTYPE mm_jpeg_encoding_mode( 592 mm_jpeg_job_session_t* p_session) 593 { 594 OMX_ERRORTYPE rc = 0; 595 int32_t i = 0; 596 OMX_INDEXTYPE indextype; 597 QOMX_ENCODING_MODE encoding_mode; 598 int32_t totalSize = 0; 599 mm_jpeg_encode_params_t *p_params = &p_session->params; 600 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 601 602 rc = OMX_GetExtensionIndex(p_session->omx_handle, 603 QOMX_IMAGE_EXT_ENCODING_MODE_NAME, &indextype); 604 if (rc != OMX_ErrorNone) { 605 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 606 return rc; 607 } 608 609 CDBG_HIGH("%s:%d] OMX_Serial_Encoding = %d, OMX_Parallel_Encoding = %d ", __func__, __LINE__, 610 (int)OMX_Serial_Encoding, 611 (int)OMX_Parallel_Encoding); 612 613 encoding_mode = OMX_Serial_Encoding; 614 rc = OMX_SetParameter(p_session->omx_handle, indextype, &encoding_mode); 615 if (rc != OMX_ErrorNone) { 616 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__); 617 return rc; 618 } 619 return rc; 620 } 621 622 /** map_jpeg_format: 623 * 624 * Arguments: 625 * @color_fmt: color format 626 * 627 * Return: 628 * OMX color format 629 * 630 * Description: 631 * Map mmjpeg color format to OMX color format 632 * 633 **/ 634 int map_jpeg_format(mm_jpeg_color_format color_fmt) 635 { 636 switch (color_fmt) { 637 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2: 638 return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar; 639 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2: 640 return (int)OMX_COLOR_FormatYUV420SemiPlanar; 641 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1: 642 return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar; 643 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1: 644 return (int)OMX_COLOR_FormatYUV422SemiPlanar; 645 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V2: 646 return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar_h1v2; 647 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V2: 648 return (int)OMX_QCOM_IMG_COLOR_FormatYUV422SemiPlanar_h1v2; 649 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V1: 650 return (int)OMX_QCOM_IMG_COLOR_FormatYVU444SemiPlanar; 651 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V1: 652 return (int)OMX_QCOM_IMG_COLOR_FormatYUV444SemiPlanar; 653 default: 654 CDBG_ERROR("%s:%d] invalid format %d", __func__, __LINE__, color_fmt); 655 return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar; 656 } 657 } 658 659 /** mm_jpeg_session_config_port: 660 * 661 * Arguments: 662 * @p_session: job session 663 * 664 * Return: 665 * OMX error values 666 * 667 * Description: 668 * Configure OMX ports 669 * 670 **/ 671 OMX_ERRORTYPE mm_jpeg_session_config_ports(mm_jpeg_job_session_t* p_session) 672 { 673 OMX_ERRORTYPE ret = OMX_ErrorNone; 674 mm_jpeg_encode_params_t *p_params = &p_session->params; 675 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 676 677 mm_jpeg_buf_t *p_src_buf = 678 &p_params->src_main_buf[p_jobparams->src_index]; 679 680 p_session->inputPort.nPortIndex = 0; 681 p_session->outputPort.nPortIndex = 1; 682 p_session->inputTmbPort.nPortIndex = 2; 683 684 ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 685 &p_session->inputPort); 686 if (ret) { 687 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 688 return ret; 689 } 690 691 ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 692 &p_session->inputTmbPort); 693 if (ret) { 694 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 695 return ret; 696 } 697 698 ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 699 &p_session->outputPort); 700 if (ret) { 701 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 702 return ret; 703 } 704 705 p_session->inputPort.format.image.nFrameWidth = 706 p_jobparams->main_dim.src_dim.width; 707 p_session->inputPort.format.image.nFrameHeight = 708 p_jobparams->main_dim.src_dim.height; 709 p_session->inputPort.format.image.nStride = 710 p_src_buf->offset.mp[0].stride; 711 p_session->inputPort.format.image.nSliceHeight = 712 p_src_buf->offset.mp[0].scanline; 713 p_session->inputPort.format.image.eColorFormat = 714 map_jpeg_format(p_params->color_format); 715 p_session->inputPort.nBufferSize = 716 p_params->src_main_buf[p_jobparams->src_index].buf_size; 717 p_session->inputPort.nBufferCountActual = p_params->num_src_bufs; 718 ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 719 &p_session->inputPort); 720 if (ret) { 721 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 722 return ret; 723 } 724 725 if (p_session->params.encode_thumbnail) { 726 mm_jpeg_buf_t *p_tmb_buf = 727 &p_params->src_thumb_buf[p_jobparams->thumb_index]; 728 p_session->inputTmbPort.format.image.nFrameWidth = 729 p_jobparams->thumb_dim.src_dim.width; 730 p_session->inputTmbPort.format.image.nFrameHeight = 731 p_jobparams->thumb_dim.src_dim.height; 732 p_session->inputTmbPort.format.image.nStride = 733 p_tmb_buf->offset.mp[0].stride; 734 p_session->inputTmbPort.format.image.nSliceHeight = 735 p_tmb_buf->offset.mp[0].scanline; 736 p_session->inputTmbPort.format.image.eColorFormat = 737 map_jpeg_format(p_params->color_format); 738 p_session->inputTmbPort.nBufferSize = 739 p_params->src_thumb_buf[p_jobparams->thumb_index].buf_size; 740 p_session->inputTmbPort.nBufferCountActual = p_params->num_tmb_bufs; 741 ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 742 &p_session->inputTmbPort); 743 744 if (ret) { 745 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 746 return ret; 747 } 748 749 // Enable thumbnail port 750 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortEnable, 751 p_session->inputTmbPort.nPortIndex, NULL); 752 753 if (ret) { 754 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 755 return ret; 756 } 757 } else { 758 // Disable thumbnail port 759 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortDisable, 760 p_session->inputTmbPort.nPortIndex, NULL); 761 762 if (ret) { 763 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 764 return ret; 765 } 766 } 767 768 p_session->outputPort.nBufferSize = 769 p_params->dest_buf[p_jobparams->dst_index].buf_size; 770 p_session->outputPort.nBufferCountActual = p_params->num_dst_bufs; 771 ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, 772 &p_session->outputPort); 773 if (ret) { 774 CDBG_ERROR("%s:%d] failed", __func__, __LINE__); 775 return ret; 776 } 777 778 return ret; 779 } 780 781 /** mm_jpeg_omx_config_thumbnail: 782 * 783 * Arguments: 784 * @p_session: job session 785 * 786 * Return: 787 * OMX error values 788 * 789 * Description: 790 * Configure OMX ports 791 * 792 **/ 793 OMX_ERRORTYPE mm_jpeg_session_config_thumbnail(mm_jpeg_job_session_t* p_session) 794 { 795 OMX_ERRORTYPE ret = OMX_ErrorNone; 796 QOMX_THUMBNAIL_INFO thumbnail_info; 797 OMX_INDEXTYPE thumb_indextype; 798 OMX_BOOL encode_thumbnail = OMX_FALSE; 799 mm_jpeg_encode_params_t *p_params = &p_session->params; 800 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 801 mm_jpeg_dim_t *p_thumb_dim = &p_jobparams->thumb_dim; 802 mm_jpeg_dim_t *p_main_dim = &p_jobparams->main_dim; 803 QOMX_YUV_FRAME_INFO *p_frame_info = &thumbnail_info.tmbOffset; 804 mm_jpeg_buf_t *p_tmb_buf = &p_params->src_thumb_buf[p_jobparams->thumb_index]; 805 806 CDBG_HIGH("%s:%d] encode_thumbnail %d", __func__, __LINE__, 807 p_params->encode_thumbnail); 808 if (OMX_FALSE == p_params->encode_thumbnail) { 809 return ret; 810 } 811 812 if ((p_thumb_dim->dst_dim.width == 0) || (p_thumb_dim->dst_dim.height == 0)) { 813 CDBG_ERROR("%s:%d] Error invalid output dim for thumbnail", 814 __func__, __LINE__); 815 return OMX_ErrorBadParameter; 816 } 817 818 if ((p_thumb_dim->src_dim.width == 0) || (p_thumb_dim->src_dim.height == 0)) { 819 CDBG_ERROR("%s:%d] Error invalid input dim for thumbnail", 820 __func__, __LINE__); 821 return OMX_ErrorBadParameter; 822 } 823 824 if ((p_thumb_dim->crop.width == 0) || (p_thumb_dim->crop.height == 0)) { 825 p_thumb_dim->crop.width = p_thumb_dim->src_dim.width; 826 p_thumb_dim->crop.height = p_thumb_dim->src_dim.height; 827 } 828 829 /* check crop boundary */ 830 if ((p_thumb_dim->crop.width + p_thumb_dim->crop.left > p_thumb_dim->src_dim.width) || 831 (p_thumb_dim->crop.height + p_thumb_dim->crop.top > p_thumb_dim->src_dim.height)) { 832 CDBG_ERROR("%s:%d] invalid crop boundary (%d, %d) offset (%d, %d) out of (%d, %d)", 833 __func__, __LINE__, 834 p_thumb_dim->crop.width, 835 p_thumb_dim->crop.height, 836 p_thumb_dim->crop.left, 837 p_thumb_dim->crop.top, 838 p_thumb_dim->src_dim.width, 839 p_thumb_dim->src_dim.height); 840 return OMX_ErrorBadParameter; 841 } 842 843 memset(&thumbnail_info, 0x0, sizeof(QOMX_THUMBNAIL_INFO)); 844 ret = OMX_GetExtensionIndex(p_session->omx_handle, 845 QOMX_IMAGE_EXT_THUMBNAIL_NAME, 846 &thumb_indextype); 847 if (ret) { 848 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret); 849 return ret; 850 } 851 852 /* fill thumbnail info */ 853 thumbnail_info.scaling_enabled = 1; 854 thumbnail_info.input_width = p_thumb_dim->src_dim.width; 855 thumbnail_info.input_height = p_thumb_dim->src_dim.height; 856 thumbnail_info.crop_info.nWidth = p_thumb_dim->crop.width; 857 thumbnail_info.crop_info.nHeight = p_thumb_dim->crop.height; 858 thumbnail_info.crop_info.nLeft = p_thumb_dim->crop.left; 859 thumbnail_info.crop_info.nTop = p_thumb_dim->crop.top; 860 861 if ((p_main_dim->src_dim.width < p_thumb_dim->src_dim.width) || 862 (p_main_dim->src_dim.height < p_thumb_dim->src_dim.height)) { 863 CDBG_ERROR("%s:%d] Improper thumbnail dim %dx%d resetting to %dx%d", 864 __func__, __LINE__, 865 p_thumb_dim->src_dim.width, 866 p_thumb_dim->src_dim.height, 867 p_main_dim->src_dim.width, 868 p_main_dim->src_dim.height); 869 thumbnail_info.input_width = p_main_dim->src_dim.width; 870 thumbnail_info.input_height = p_main_dim->src_dim.height; 871 if ((thumbnail_info.crop_info.nWidth > thumbnail_info.input_width) 872 || (thumbnail_info.crop_info.nHeight > thumbnail_info.input_height)) { 873 thumbnail_info.crop_info.nLeft = 0; 874 thumbnail_info.crop_info.nTop = 0; 875 thumbnail_info.crop_info.nWidth = thumbnail_info.input_width; 876 thumbnail_info.crop_info.nHeight = thumbnail_info.input_height; 877 } 878 } 879 880 if ((p_thumb_dim->dst_dim.width > p_thumb_dim->src_dim.width) 881 || (p_thumb_dim->dst_dim.height > p_thumb_dim->src_dim.height)) { 882 CDBG_ERROR("%s:%d] Incorrect thumbnail dim %dx%d resetting to %dx%d", 883 __func__, __LINE__, 884 p_thumb_dim->dst_dim.width, 885 p_thumb_dim->dst_dim.height, 886 p_thumb_dim->src_dim.width, 887 p_thumb_dim->src_dim.height); 888 thumbnail_info.output_width = p_thumb_dim->src_dim.width; 889 thumbnail_info.output_height = p_thumb_dim->src_dim.height; 890 } else { 891 thumbnail_info.output_width = p_thumb_dim->dst_dim.width; 892 thumbnail_info.output_height = p_thumb_dim->dst_dim.height; 893 } 894 895 memset(p_frame_info, 0x0, sizeof(*p_frame_info)); 896 897 p_frame_info->cbcrStartOffset[0] = p_tmb_buf->offset.mp[0].len; 898 p_frame_info->cbcrStartOffset[1] = p_tmb_buf->offset.mp[1].len; 899 p_frame_info->yOffset = p_tmb_buf->offset.mp[0].offset; 900 p_frame_info->cbcrOffset[0] = p_tmb_buf->offset.mp[1].offset; 901 p_frame_info->cbcrOffset[1] = p_tmb_buf->offset.mp[2].offset; 902 903 ret = OMX_SetConfig(p_session->omx_handle, thumb_indextype, 904 &thumbnail_info); 905 if (ret) { 906 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 907 return ret; 908 } 909 910 return ret; 911 } 912 913 /** mm_jpeg_session_config_main_crop: 914 * 915 * Arguments: 916 * @p_session: job session 917 * 918 * Return: 919 * OMX error values 920 * 921 * Description: 922 * Configure main image crop 923 * 924 **/ 925 OMX_ERRORTYPE mm_jpeg_session_config_main_crop(mm_jpeg_job_session_t *p_session) 926 { 927 OMX_CONFIG_RECTTYPE rect_type_in, rect_type_out; 928 OMX_ERRORTYPE ret = OMX_ErrorNone; 929 mm_jpeg_encode_params_t *p_params = &p_session->params; 930 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 931 mm_jpeg_dim_t *dim = &p_jobparams->main_dim; 932 933 if ((dim->crop.width == 0) || (dim->crop.height == 0)) { 934 dim->crop.width = dim->src_dim.width; 935 dim->crop.height = dim->src_dim.height; 936 } 937 /* error check first */ 938 if ((dim->crop.width + dim->crop.left > dim->src_dim.width) || 939 (dim->crop.height + dim->crop.top > dim->src_dim.height)) { 940 CDBG_ERROR("%s:%d] invalid crop boundary (%d, %d) out of (%d, %d)", 941 __func__, __LINE__, 942 dim->crop.width + dim->crop.left, 943 dim->crop.height + dim->crop.top, 944 dim->src_dim.width, 945 dim->src_dim.height); 946 return OMX_ErrorBadParameter; 947 } 948 949 memset(&rect_type_in, 0, sizeof(rect_type_in)); 950 memset(&rect_type_out, 0, sizeof(rect_type_out)); 951 rect_type_in.nPortIndex = 0; 952 rect_type_out.nPortIndex = 0; 953 954 if ((dim->src_dim.width != dim->crop.width) || 955 (dim->src_dim.height != dim->crop.height) || 956 (dim->src_dim.width != dim->dst_dim.width) || 957 (dim->src_dim.height != dim->dst_dim.height)) { 958 /* Scaler information */ 959 rect_type_in.nWidth = CEILING2(dim->crop.width); 960 rect_type_in.nHeight = CEILING2(dim->crop.height); 961 rect_type_in.nLeft = dim->crop.left; 962 rect_type_in.nTop = dim->crop.top; 963 964 if (dim->dst_dim.width && dim->dst_dim.height) { 965 rect_type_out.nWidth = dim->dst_dim.width; 966 rect_type_out.nHeight = dim->dst_dim.height; 967 } 968 } 969 970 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonInputCrop, 971 &rect_type_in); 972 if (OMX_ErrorNone != ret) { 973 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 974 return ret; 975 } 976 977 CDBG("%s:%d] OMX_IndexConfigCommonInputCrop w = %d, h = %d, l = %d, t = %d," 978 " port_idx = %d", __func__, __LINE__, 979 (int)rect_type_in.nWidth, (int)rect_type_in.nHeight, 980 (int)rect_type_in.nLeft, (int)rect_type_in.nTop, 981 (int)rect_type_in.nPortIndex); 982 983 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonOutputCrop, 984 &rect_type_out); 985 if (OMX_ErrorNone != ret) { 986 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 987 return ret; 988 } 989 CDBG("%s:%d] OMX_IndexConfigCommonOutputCrop w = %d, h = %d," 990 " port_idx = %d", __func__, __LINE__, 991 (int)rect_type_out.nWidth, (int)rect_type_out.nHeight, 992 (int)rect_type_out.nPortIndex); 993 994 return ret; 995 } 996 997 /** mm_jpeg_session_config_main: 998 * 999 * Arguments: 1000 * @p_session: job session 1001 * 1002 * Return: 1003 * OMX error values 1004 * 1005 * Description: 1006 * Configure main image 1007 * 1008 **/ 1009 OMX_ERRORTYPE mm_jpeg_session_config_main(mm_jpeg_job_session_t *p_session) 1010 { 1011 OMX_ERRORTYPE rc = OMX_ErrorNone; 1012 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1013 1014 /* config port */ 1015 CDBG("%s:%d] config port", __func__, __LINE__); 1016 rc = mm_jpeg_session_config_ports(p_session); 1017 if (OMX_ErrorNone != rc) { 1018 CDBG_ERROR("%s: config port failed", __func__); 1019 return rc; 1020 } 1021 1022 /* config buffer offset */ 1023 CDBG("%s:%d] config main buf offset", __func__, __LINE__); 1024 rc = mm_jpeg_session_config_main_buffer_offset(p_session); 1025 if (OMX_ErrorNone != rc) { 1026 CDBG_ERROR("%s: config buffer offset failed", __func__); 1027 return rc; 1028 } 1029 1030 /* set the encoding mode */ 1031 mm_jpeg_encoding_mode(p_session); 1032 1033 return rc; 1034 } 1035 1036 /** mm_jpeg_session_config_common: 1037 * 1038 * Arguments: 1039 * @p_session: job session 1040 * 1041 * Return: 1042 * OMX error values 1043 * 1044 * Description: 1045 * Configure common parameters 1046 * 1047 **/ 1048 OMX_ERRORTYPE mm_jpeg_session_config_common(mm_jpeg_job_session_t *p_session) 1049 { 1050 OMX_ERRORTYPE rc = OMX_ErrorNone; 1051 int i; 1052 OMX_INDEXTYPE exif_idx; 1053 OMX_CONFIG_ROTATIONTYPE rotate; 1054 mm_jpeg_encode_params_t *p_params = &p_session->params; 1055 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1056 QOMX_EXIF_INFO exif_info; 1057 1058 /* set rotation */ 1059 memset(&rotate, 0, sizeof(rotate)); 1060 rotate.nPortIndex = 1; 1061 rotate.nRotation = p_jobparams->rotation; 1062 rc = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonRotate, 1063 &rotate); 1064 if (OMX_ErrorNone != rc) { 1065 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc); 1066 return rc; 1067 } 1068 CDBG("%s:%d] Set rotation to %d at port_idx = %d", __func__, __LINE__, 1069 (int)p_jobparams->rotation, (int)rotate.nPortIndex); 1070 1071 /* Set Exif data*/ 1072 memset(&p_session->exif_info_local[0], 0, sizeof(p_session->exif_info_local)); 1073 1074 1075 /* set exif tags */ 1076 rc = OMX_GetExtensionIndex(p_session->omx_handle, QOMX_IMAGE_EXT_EXIF_NAME, 1077 &exif_idx); 1078 if (OMX_ErrorNone != rc) { 1079 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc); 1080 return rc; 1081 } 1082 CDBG_HIGH("%s:%d] Num of exif entries passed from HAL: %d", __func__, __LINE__, 1083 (int)p_jobparams->exif_info.numOfEntries); 1084 if (p_jobparams->exif_info.numOfEntries > 0) { 1085 rc = OMX_SetConfig(p_session->omx_handle, exif_idx, 1086 &p_jobparams->exif_info); 1087 if (OMX_ErrorNone != rc) { 1088 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc); 1089 return rc; 1090 } 1091 } 1092 /*parse aditional exif data from the metadata if present*/ 1093 if ((NULL != p_jobparams->p_metadata_v3) || 1094 (NULL != p_jobparams->p_metadata_v1)) { 1095 exif_info.numOfEntries = 0; 1096 exif_info.exif_data = &p_session->exif_info_local[0]; 1097 1098 if (NULL != p_jobparams->p_metadata_v3) { 1099 process_meta_data_v3(p_jobparams->p_metadata_v3, 1100 &exif_info, &p_jobparams->cam_exif_params); 1101 } else { 1102 process_meta_data_v1(p_jobparams->p_metadata_v1, 1103 &exif_info, &p_jobparams->cam_exif_params); 1104 } 1105 /* After Parse metadata */ 1106 p_session->exif_count_local = exif_info.numOfEntries; 1107 1108 if (exif_info.numOfEntries > 0) { 1109 /* set exif tags */ 1110 CDBG("%s:%d] exif tags from metadata count %d", __func__, __LINE__, 1111 (int)exif_info.numOfEntries); 1112 rc = OMX_SetConfig(p_session->omx_handle, exif_idx, 1113 &exif_info); 1114 if (OMX_ErrorNone != rc) { 1115 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc); 1116 return rc; 1117 } 1118 } 1119 } else { 1120 CDBG_ERROR("%s:%d] Metadata is null", __func__, __LINE__, rc); 1121 } 1122 1123 return rc; 1124 } 1125 1126 /** mm_jpeg_session_abort: 1127 * 1128 * Arguments: 1129 * @p_session: jpeg session 1130 * 1131 * Return: 1132 * OMX_BOOL 1133 * 1134 * Description: 1135 * Abort ongoing job 1136 * 1137 **/ 1138 OMX_BOOL mm_jpeg_session_abort(mm_jpeg_job_session_t *p_session) 1139 { 1140 OMX_ERRORTYPE ret = OMX_ErrorNone; 1141 1142 CDBG("%s:%d] E", __func__, __LINE__); 1143 pthread_mutex_lock(&p_session->lock); 1144 if (OMX_TRUE == p_session->abort_flag) { 1145 pthread_mutex_unlock(&p_session->lock); 1146 CDBG("%s:%d] **** ALREADY ABORTED", __func__, __LINE__); 1147 return 0; 1148 } 1149 p_session->abort_flag = OMX_TRUE; 1150 if (OMX_TRUE == p_session->encoding) { 1151 p_session->state_change_pending = OMX_TRUE; 1152 1153 CDBG("%s:%d] **** ABORTING", __func__, __LINE__); 1154 1155 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet, 1156 OMX_StateIdle, NULL); 1157 1158 if (ret != OMX_ErrorNone) { 1159 CDBG("%s:%d] OMX_SendCommand returned error %d", __func__, __LINE__, ret); 1160 pthread_mutex_unlock(&p_session->lock); 1161 return 1; 1162 } 1163 ret = mm_jpeg_destroy_job(p_session); 1164 if (ret != 0) { 1165 CDBG("%s:%d] Destroy job returned error %d", __func__, __LINE__, rc); 1166 } 1167 1168 CDBG("%s:%d] before wait", __func__, __LINE__); 1169 pthread_cond_wait(&p_session->cond, &p_session->lock); 1170 CDBG("%s:%d] after wait", __func__, __LINE__); 1171 } 1172 pthread_mutex_unlock(&p_session->lock); 1173 CDBG("%s:%d] X", __func__, __LINE__); 1174 return 0; 1175 } 1176 1177 /** mm_jpeg_get_job_idx: 1178 * 1179 * Arguments: 1180 * @my_obj: jpeg object 1181 * @client_idx: client index 1182 * 1183 * Return: 1184 * job index 1185 * 1186 * Description: 1187 * Get job index by client id 1188 * 1189 **/ 1190 inline int mm_jpeg_get_new_session_idx(mm_jpeg_obj *my_obj, int client_idx, 1191 mm_jpeg_job_session_t **pp_session) 1192 { 1193 int i = 0; 1194 int index = -1; 1195 for (i = 0; i < MM_JPEG_MAX_SESSION; i++) { 1196 pthread_mutex_lock(&my_obj->clnt_mgr[client_idx].lock); 1197 if (!my_obj->clnt_mgr[client_idx].session[i].active) { 1198 *pp_session = &my_obj->clnt_mgr[client_idx].session[i]; 1199 my_obj->clnt_mgr[client_idx].session[i].active = OMX_TRUE; 1200 index = i; 1201 pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock); 1202 break; 1203 } 1204 pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock); 1205 } 1206 return index; 1207 } 1208 1209 /** mm_jpeg_get_job_idx: 1210 * 1211 * Arguments: 1212 * @my_obj: jpeg object 1213 * @client_idx: client index 1214 * 1215 * Return: 1216 * job index 1217 * 1218 * Description: 1219 * Get job index by client id 1220 * 1221 **/ 1222 inline void mm_jpeg_remove_session_idx(mm_jpeg_obj *my_obj, uint32_t job_id) 1223 { 1224 int client_idx = GET_CLIENT_IDX(job_id); 1225 int session_idx= GET_SESSION_IDX(job_id); 1226 CDBG("%s:%d] client_idx %d session_idx %d", __func__, __LINE__, 1227 client_idx, session_idx); 1228 pthread_mutex_lock(&my_obj->clnt_mgr[client_idx].lock); 1229 my_obj->clnt_mgr[client_idx].session[session_idx].active = OMX_FALSE; 1230 pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock); 1231 } 1232 1233 /** mm_jpeg_get_session_idx: 1234 * 1235 * Arguments: 1236 * @my_obj: jpeg object 1237 * @client_idx: client index 1238 * 1239 * Return: 1240 * job index 1241 * 1242 * Description: 1243 * Get job index by client id 1244 * 1245 **/ 1246 inline mm_jpeg_job_session_t *mm_jpeg_get_session(mm_jpeg_obj *my_obj, uint32_t job_id) 1247 { 1248 mm_jpeg_job_session_t *p_session = NULL; 1249 int client_idx = GET_CLIENT_IDX(job_id); 1250 int session_idx= GET_SESSION_IDX(job_id); 1251 1252 CDBG("%s:%d] client_idx %d session_idx %d", __func__, __LINE__, 1253 client_idx, session_idx); 1254 if ((session_idx >= MM_JPEG_MAX_SESSION) || 1255 (client_idx >= MAX_JPEG_CLIENT_NUM)) { 1256 CDBG_ERROR("%s:%d] invalid job id %x", __func__, __LINE__, 1257 job_id); 1258 return NULL; 1259 } 1260 pthread_mutex_lock(&my_obj->clnt_mgr[client_idx].lock); 1261 p_session = &my_obj->clnt_mgr[client_idx].session[session_idx]; 1262 pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock); 1263 return p_session; 1264 } 1265 1266 /** mm_jpeg_configure_params 1267 * 1268 * Arguments: 1269 * @p_session: encode session 1270 * 1271 * Return: 1272 * none 1273 * 1274 * Description: 1275 * Configure the job specific params 1276 * 1277 **/ 1278 static OMX_ERRORTYPE mm_jpeg_configure_job_params( 1279 mm_jpeg_job_session_t *p_session) 1280 { 1281 OMX_ERRORTYPE ret = OMX_ErrorNone; 1282 OMX_IMAGE_PARAM_QFACTORTYPE q_factor; 1283 mm_jpeg_encode_params_t *p_params = &p_session->params; 1284 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1285 1286 /* common config */ 1287 ret = mm_jpeg_session_config_common(p_session); 1288 if (OMX_ErrorNone != ret) { 1289 CDBG_ERROR("%s:%d] config common failed", __func__, __LINE__); 1290 1291 } 1292 1293 /* config Main Image crop */ 1294 CDBG("%s:%d] config main crop", __func__, __LINE__); 1295 ret = mm_jpeg_session_config_main_crop(p_session); 1296 if (OMX_ErrorNone != ret) { 1297 CDBG_ERROR("%s: config crop failed", __func__); 1298 return ret; 1299 } 1300 1301 /* set quality */ 1302 memset(&q_factor, 0, sizeof(q_factor)); 1303 q_factor.nPortIndex = 0; 1304 q_factor.nQFactor = p_params->quality; 1305 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexParamQFactor, &q_factor); 1306 CDBG("%s:%d] config QFactor: %d", __func__, __LINE__, (int)q_factor.nQFactor); 1307 if (OMX_ErrorNone != ret) { 1308 CDBG_ERROR("%s:%d] Error setting Q factor %d", __func__, __LINE__, ret); 1309 return ret; 1310 } 1311 1312 /* config thumbnail */ 1313 ret = mm_jpeg_session_config_thumbnail(p_session); 1314 if (OMX_ErrorNone != ret) { 1315 CDBG_ERROR("%s:%d] config thumbnail img failed", __func__, __LINE__); 1316 return ret; 1317 } 1318 1319 return ret; 1320 } 1321 /** mm_jpeg_session_configure: 1322 * 1323 * Arguments: 1324 * @data: encode session 1325 * 1326 * Return: 1327 * none 1328 * 1329 * Description: 1330 * Configure the session 1331 * 1332 **/ 1333 static OMX_ERRORTYPE mm_jpeg_session_configure(mm_jpeg_job_session_t *p_session) 1334 { 1335 OMX_ERRORTYPE ret = OMX_ErrorNone; 1336 mm_jpeg_encode_params_t *p_params = &p_session->params; 1337 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1338 mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj; 1339 1340 CDBG("%s:%d] E ", __func__, __LINE__); 1341 1342 MM_JPEG_CHK_ABORT(p_session, ret, error); 1343 1344 /* config main img */ 1345 ret = mm_jpeg_session_config_main(p_session); 1346 if (OMX_ErrorNone != ret) { 1347 CDBG_ERROR("%s:%d] config main img failed", __func__, __LINE__); 1348 goto error; 1349 } 1350 ret = mm_jpeg_session_change_state(p_session, OMX_StateIdle, 1351 mm_jpeg_session_send_buffers); 1352 if (ret) { 1353 CDBG_ERROR("%s:%d] change state to idle failed %d", 1354 __func__, __LINE__, ret); 1355 goto error; 1356 } 1357 1358 ret = mm_jpeg_session_change_state(p_session, OMX_StateExecuting, 1359 NULL); 1360 if (ret) { 1361 CDBG_ERROR("%s:%d] change state to executing failed %d", 1362 __func__, __LINE__, ret); 1363 goto error; 1364 } 1365 1366 error: 1367 CDBG("%s:%d] X ret %d", __func__, __LINE__, ret); 1368 return ret; 1369 } 1370 1371 /** mm_jpeg_session_encode: 1372 * 1373 * Arguments: 1374 * @p_session: encode session 1375 * 1376 * Return: 1377 * OMX_ERRORTYPE 1378 * 1379 * Description: 1380 * Start the encoding 1381 * 1382 **/ 1383 static inline void mm_jpeg_job_done(mm_jpeg_job_session_t *p_session) 1384 { 1385 mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj; 1386 mm_jpeg_job_q_node_t *node = NULL; 1387 1388 /*Destroy job related params*/ 1389 mm_jpeg_destroy_job(p_session); 1390 1391 /*remove the job*/ 1392 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, 1393 p_session->jobId); 1394 if (node) { 1395 free(node); 1396 } 1397 p_session->encoding = OMX_FALSE; 1398 1399 /* wake up jobMgr thread to work on new job if there is any */ 1400 cam_sem_post(&my_obj->job_mgr.job_sem); 1401 } 1402 1403 /** mm_jpeg_session_encode: 1404 * 1405 * Arguments: 1406 * @p_session: encode session 1407 * 1408 * Return: 1409 * OMX_ERRORTYPE 1410 * 1411 * Description: 1412 * Start the encoding 1413 * 1414 **/ 1415 static OMX_ERRORTYPE mm_jpeg_session_encode(mm_jpeg_job_session_t *p_session) 1416 { 1417 OMX_ERRORTYPE ret = OMX_ErrorNone; 1418 mm_jpeg_encode_params_t *p_params = &p_session->params; 1419 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 1420 int dest_idx = 0; 1421 mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj; 1422 1423 pthread_mutex_lock(&p_session->lock); 1424 p_session->abort_flag = OMX_FALSE; 1425 p_session->encoding = OMX_FALSE; 1426 pthread_mutex_unlock(&p_session->lock); 1427 1428 if (OMX_FALSE == p_session->config) { 1429 ret = mm_jpeg_session_configure(p_session); 1430 if (ret) { 1431 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1432 goto error; 1433 } 1434 p_session->config = OMX_TRUE; 1435 } 1436 1437 ret = mm_jpeg_configure_job_params(p_session); 1438 if (ret) { 1439 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1440 goto error; 1441 } 1442 pthread_mutex_lock(&p_session->lock); 1443 p_session->encoding = OMX_TRUE; 1444 pthread_mutex_unlock(&p_session->lock); 1445 1446 MM_JPEG_CHK_ABORT(p_session, ret, error); 1447 1448 #ifdef MM_JPEG_DUMP_INPUT 1449 DUMP_TO_FILE("/data/mm_jpeg_int.yuv", 1450 p_session->p_in_omx_buf[p_jobparams->src_index]->pBuffer, 1451 (int)p_session->p_in_omx_buf[p_jobparams->src_index]->nAllocLen); 1452 #endif 1453 1454 ret = OMX_EmptyThisBuffer(p_session->omx_handle, 1455 p_session->p_in_omx_buf[p_jobparams->src_index]); 1456 if (ret) { 1457 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1458 goto error; 1459 } 1460 1461 if (p_session->params.encode_thumbnail) { 1462 ret = OMX_EmptyThisBuffer(p_session->omx_handle, 1463 p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]); 1464 if (ret) { 1465 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1466 goto error; 1467 } 1468 } 1469 1470 ret = OMX_FillThisBuffer(p_session->omx_handle, 1471 p_session->p_out_omx_buf[p_jobparams->dst_index]); 1472 if (ret) { 1473 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1474 goto error; 1475 } 1476 1477 MM_JPEG_CHK_ABORT(p_session, ret, error); 1478 1479 error: 1480 1481 CDBG("%s:%d] X ", __func__, __LINE__); 1482 return ret; 1483 } 1484 1485 /** mm_jpeg_process_encoding_job: 1486 * 1487 * Arguments: 1488 * @my_obj: jpeg client 1489 * @job_node: job node 1490 * 1491 * Return: 1492 * 0 for success -1 otherwise 1493 * 1494 * Description: 1495 * Start the encoding job 1496 * 1497 **/ 1498 int32_t mm_jpeg_process_encoding_job(mm_jpeg_obj *my_obj, mm_jpeg_job_q_node_t* job_node) 1499 { 1500 int32_t rc = 0; 1501 OMX_ERRORTYPE ret = OMX_ErrorNone; 1502 mm_jpeg_job_session_t *p_session = NULL; 1503 mm_jpeg_job_q_node_t *node = NULL; 1504 1505 /* check if valid session */ 1506 p_session = mm_jpeg_get_session(my_obj, job_node->enc_info.job_id); 1507 if (NULL == p_session) { 1508 CDBG_ERROR("%s:%d] invalid job id %x", __func__, __LINE__, 1509 job_node->enc_info.job_id); 1510 return -1; 1511 } 1512 1513 /* sent encode cmd to OMX, queue job into ongoing queue */ 1514 rc = mm_jpeg_queue_enq(&my_obj->ongoing_job_q, job_node); 1515 if (rc) { 1516 CDBG_ERROR("%s:%d] jpeg enqueue failed %d", 1517 __func__, __LINE__, ret); 1518 goto error; 1519 } 1520 1521 p_session->encode_job = job_node->enc_info.encode_job; 1522 p_session->jobId = job_node->enc_info.job_id; 1523 ret = mm_jpeg_session_encode(p_session); 1524 if (ret) { 1525 CDBG_ERROR("%s:%d] encode session failed", __func__, __LINE__); 1526 goto error; 1527 } 1528 1529 CDBG("%s:%d] Success X ", __func__, __LINE__); 1530 return rc; 1531 1532 error: 1533 1534 if ((OMX_ErrorNone != ret) && 1535 (NULL != p_session->params.jpeg_cb)) { 1536 p_session->job_status = JPEG_JOB_STATUS_ERROR; 1537 CDBG("%s:%d] send jpeg error callback %d", __func__, __LINE__, 1538 p_session->job_status); 1539 p_session->params.jpeg_cb(p_session->job_status, 1540 p_session->client_hdl, 1541 p_session->jobId, 1542 NULL, 1543 p_session->params.userdata); 1544 } 1545 1546 /*remove the job*/ 1547 mm_jpeg_job_done(p_session); 1548 CDBG("%s:%d] Error X ", __func__, __LINE__); 1549 1550 return rc; 1551 } 1552 1553 /** mm_jpeg_jobmgr_thread: 1554 * 1555 * Arguments: 1556 * @my_obj: jpeg object 1557 * 1558 * Return: 1559 * 0 for success else failure 1560 * 1561 * Description: 1562 * job manager thread main function 1563 * 1564 **/ 1565 static void *mm_jpeg_jobmgr_thread(void *data) 1566 { 1567 int rc = 0; 1568 int running = 1; 1569 uint32_t num_ongoing_jobs = 0; 1570 mm_jpeg_obj *my_obj = (mm_jpeg_obj*)data; 1571 mm_jpeg_job_cmd_thread_t *cmd_thread = &my_obj->job_mgr; 1572 mm_jpeg_job_q_node_t* node = NULL; 1573 prctl(PR_SET_NAME, (unsigned long)"mm_jpeg_thread", 0, 0, 0); 1574 1575 do { 1576 do { 1577 rc = cam_sem_wait(&cmd_thread->job_sem); 1578 if (rc != 0 && errno != EINVAL) { 1579 CDBG_ERROR("%s: cam_sem_wait error (%s)", 1580 __func__, strerror(errno)); 1581 return NULL; 1582 } 1583 } while (rc != 0); 1584 1585 /* check ongoing q size */ 1586 num_ongoing_jobs = mm_jpeg_queue_get_size(&my_obj->ongoing_job_q); 1587 if (num_ongoing_jobs >= NUM_MAX_JPEG_CNCURRENT_JOBS) { 1588 CDBG("%s:%d] ongoing job already reach max %d", __func__, 1589 __LINE__, num_ongoing_jobs); 1590 continue; 1591 } 1592 1593 pthread_mutex_lock(&my_obj->job_lock); 1594 /* can go ahead with new work */ 1595 node = (mm_jpeg_job_q_node_t*)mm_jpeg_queue_deq(&cmd_thread->job_queue); 1596 if (node != NULL) { 1597 switch (node->type) { 1598 case MM_JPEG_CMD_TYPE_JOB: 1599 rc = mm_jpeg_process_encoding_job(my_obj, node); 1600 break; 1601 case MM_JPEG_CMD_TYPE_EXIT: 1602 default: 1603 /* free node */ 1604 free(node); 1605 /* set running flag to false */ 1606 running = 0; 1607 break; 1608 } 1609 } 1610 pthread_mutex_unlock(&my_obj->job_lock); 1611 1612 } while (running); 1613 return NULL; 1614 } 1615 1616 /** mm_jpeg_jobmgr_thread_launch: 1617 * 1618 * Arguments: 1619 * @my_obj: jpeg object 1620 * 1621 * Return: 1622 * 0 for success else failure 1623 * 1624 * Description: 1625 * launches the job manager thread 1626 * 1627 **/ 1628 int32_t mm_jpeg_jobmgr_thread_launch(mm_jpeg_obj *my_obj) 1629 { 1630 int32_t rc = 0; 1631 mm_jpeg_job_cmd_thread_t *job_mgr = &my_obj->job_mgr; 1632 1633 cam_sem_init(&job_mgr->job_sem, 0); 1634 mm_jpeg_queue_init(&job_mgr->job_queue); 1635 1636 /* launch the thread */ 1637 pthread_create(&job_mgr->pid, 1638 NULL, 1639 mm_jpeg_jobmgr_thread, 1640 (void *)my_obj); 1641 return rc; 1642 } 1643 1644 /** mm_jpeg_jobmgr_thread_release: 1645 * 1646 * Arguments: 1647 * @my_obj: jpeg object 1648 * 1649 * Return: 1650 * 0 for success else failure 1651 * 1652 * Description: 1653 * Releases the job manager thread 1654 * 1655 **/ 1656 int32_t mm_jpeg_jobmgr_thread_release(mm_jpeg_obj * my_obj) 1657 { 1658 int32_t rc = 0; 1659 mm_jpeg_job_cmd_thread_t * cmd_thread = &my_obj->job_mgr; 1660 mm_jpeg_job_q_node_t* node = 1661 (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t)); 1662 if (NULL == node) { 1663 CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__); 1664 return -1; 1665 } 1666 1667 memset(node, 0, sizeof(mm_jpeg_job_q_node_t)); 1668 node->type = MM_JPEG_CMD_TYPE_EXIT; 1669 1670 mm_jpeg_queue_enq(&cmd_thread->job_queue, node); 1671 cam_sem_post(&cmd_thread->job_sem); 1672 1673 /* wait until cmd thread exits */ 1674 if (pthread_join(cmd_thread->pid, NULL) != 0) { 1675 CDBG("%s: pthread dead already", __func__); 1676 } 1677 mm_jpeg_queue_deinit(&cmd_thread->job_queue); 1678 1679 cam_sem_destroy(&cmd_thread->job_sem); 1680 memset(cmd_thread, 0, sizeof(mm_jpeg_job_cmd_thread_t)); 1681 return rc; 1682 } 1683 1684 /** mm_jpeg_init: 1685 * 1686 * Arguments: 1687 * @my_obj: jpeg object 1688 * 1689 * Return: 1690 * 0 for success else failure 1691 * 1692 * Description: 1693 * Initializes the jpeg client 1694 * 1695 **/ 1696 int32_t mm_jpeg_init(mm_jpeg_obj *my_obj) 1697 { 1698 int32_t rc = 0; 1699 1700 /* init locks */ 1701 pthread_mutex_init(&my_obj->job_lock, NULL); 1702 1703 /* init ongoing job queue */ 1704 rc = mm_jpeg_queue_init(&my_obj->ongoing_job_q); 1705 if (0 != rc) { 1706 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1707 return -1; 1708 } 1709 1710 /* init job semaphore and launch jobmgr thread */ 1711 CDBG("%s:%d] Launch jobmgr thread rc %d", __func__, __LINE__, rc); 1712 rc = mm_jpeg_jobmgr_thread_launch(my_obj); 1713 if (0 != rc) { 1714 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1715 return -1; 1716 } 1717 1718 /* load OMX */ 1719 if (OMX_ErrorNone != OMX_Init()) { 1720 /* roll back in error case */ 1721 CDBG_ERROR("%s:%d] OMX_Init failed (%d)", __func__, __LINE__, rc); 1722 mm_jpeg_jobmgr_thread_release(my_obj); 1723 mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 1724 pthread_mutex_destroy(&my_obj->job_lock); 1725 } 1726 1727 return rc; 1728 } 1729 1730 /** mm_jpeg_deinit: 1731 * 1732 * Arguments: 1733 * @my_obj: jpeg object 1734 * 1735 * Return: 1736 * 0 for success else failure 1737 * 1738 * Description: 1739 * Deinits the jpeg client 1740 * 1741 **/ 1742 int32_t mm_jpeg_deinit(mm_jpeg_obj *my_obj) 1743 { 1744 int32_t rc = 0; 1745 1746 /* release jobmgr thread */ 1747 rc = mm_jpeg_jobmgr_thread_release(my_obj); 1748 if (0 != rc) { 1749 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1750 } 1751 1752 /* unload OMX engine */ 1753 OMX_Deinit(); 1754 1755 /* deinit ongoing job and cb queue */ 1756 rc = mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 1757 if (0 != rc) { 1758 CDBG_ERROR("%s:%d] Error", __func__, __LINE__); 1759 } 1760 1761 /* destroy locks */ 1762 pthread_mutex_destroy(&my_obj->job_lock); 1763 1764 return rc; 1765 } 1766 1767 /** mm_jpeg_new_client: 1768 * 1769 * Arguments: 1770 * @my_obj: jpeg object 1771 * 1772 * Return: 1773 * 0 for success else failure 1774 * 1775 * Description: 1776 * Create new jpeg client 1777 * 1778 **/ 1779 uint32_t mm_jpeg_new_client(mm_jpeg_obj *my_obj) 1780 { 1781 uint32_t client_hdl = 0; 1782 uint8_t idx; 1783 int i = 0; 1784 1785 if (my_obj->num_clients >= MAX_JPEG_CLIENT_NUM) { 1786 CDBG_ERROR("%s: num of clients reached limit", __func__); 1787 return client_hdl; 1788 } 1789 1790 for (idx = 0; idx < MAX_JPEG_CLIENT_NUM; idx++) { 1791 if (0 == my_obj->clnt_mgr[idx].is_used) { 1792 break; 1793 } 1794 } 1795 1796 if (idx < MAX_JPEG_CLIENT_NUM) { 1797 /* client session avail */ 1798 /* generate client handler by index */ 1799 client_hdl = mm_jpeg_util_generate_handler(idx); 1800 1801 /* update client session */ 1802 my_obj->clnt_mgr[idx].is_used = 1; 1803 my_obj->clnt_mgr[idx].client_handle = client_hdl; 1804 1805 pthread_mutex_init(&my_obj->clnt_mgr[idx].lock, NULL); 1806 for (i = 0; i < MM_JPEG_MAX_SESSION; i++) { 1807 memset(&my_obj->clnt_mgr[idx].session[i], 0x0, sizeof(mm_jpeg_job_session_t)); 1808 } 1809 1810 /* increse client count */ 1811 my_obj->num_clients++; 1812 } 1813 1814 return client_hdl; 1815 } 1816 1817 /** mm_jpeg_start_job: 1818 * 1819 * Arguments: 1820 * @my_obj: jpeg object 1821 * @client_hdl: client handle 1822 * @job: pointer to encode job 1823 * @jobId: job id 1824 * 1825 * Return: 1826 * 0 for success else failure 1827 * 1828 * Description: 1829 * Start the encoding job 1830 * 1831 **/ 1832 int32_t mm_jpeg_start_job(mm_jpeg_obj *my_obj, 1833 mm_jpeg_job_t *job, 1834 uint32_t *job_id) 1835 { 1836 int32_t rc = -1; 1837 uint8_t session_idx = 0; 1838 uint8_t client_idx = 0; 1839 mm_jpeg_job_q_node_t* node = NULL; 1840 mm_jpeg_job_session_t *p_session = NULL; 1841 mm_jpeg_encode_job_t *p_jobparams = &job->encode_job; 1842 1843 *job_id = 0; 1844 1845 /* check if valid session */ 1846 session_idx = GET_SESSION_IDX(p_jobparams->session_id); 1847 client_idx = GET_CLIENT_IDX(p_jobparams->session_id); 1848 CDBG("%s:%d] session_idx %d client idx %d", __func__, __LINE__, 1849 session_idx, client_idx); 1850 1851 if ((session_idx >= MM_JPEG_MAX_SESSION) || 1852 (client_idx >= MAX_JPEG_CLIENT_NUM)) { 1853 CDBG_ERROR("%s:%d] invalid session id %x", __func__, __LINE__, 1854 job->encode_job.session_id); 1855 return rc; 1856 } 1857 1858 p_session = &my_obj->clnt_mgr[client_idx].session[session_idx]; 1859 if (OMX_FALSE == p_session->active) { 1860 CDBG_ERROR("%s:%d] session not active %x", __func__, __LINE__, 1861 job->encode_job.session_id); 1862 return rc; 1863 } 1864 1865 if ((p_jobparams->src_index >= p_session->params.num_src_bufs) || 1866 (p_jobparams->dst_index >= p_session->params.num_dst_bufs)) { 1867 CDBG_ERROR("%s:%d] invalid buffer indices", __func__, __LINE__); 1868 return rc; 1869 } 1870 1871 /* enqueue new job into todo job queue */ 1872 node = (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t)); 1873 if (NULL == node) { 1874 CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__); 1875 return -1; 1876 } 1877 1878 *job_id = job->encode_job.session_id | 1879 ((p_session->job_hist++ % JOB_HIST_MAX) << 16); 1880 1881 memset(node, 0, sizeof(mm_jpeg_job_q_node_t)); 1882 node->enc_info.encode_job = job->encode_job; 1883 node->enc_info.job_id = *job_id; 1884 node->enc_info.client_handle = p_session->client_hdl; 1885 node->type = MM_JPEG_CMD_TYPE_JOB; 1886 1887 rc = mm_jpeg_queue_enq(&my_obj->job_mgr.job_queue, node); 1888 if (0 == rc) { 1889 cam_sem_post(&my_obj->job_mgr.job_sem); 1890 } 1891 1892 return rc; 1893 } 1894 1895 /** mm_jpeg_abort_job: 1896 * 1897 * Arguments: 1898 * @my_obj: jpeg object 1899 * @client_hdl: client handle 1900 * @jobId: job id 1901 * 1902 * Return: 1903 * 0 for success else failure 1904 * 1905 * Description: 1906 * Abort the encoding session 1907 * 1908 **/ 1909 int32_t mm_jpeg_abort_job(mm_jpeg_obj *my_obj, 1910 uint32_t jobId) 1911 { 1912 int32_t rc = -1; 1913 uint8_t clnt_idx = 0; 1914 mm_jpeg_job_q_node_t *node = NULL; 1915 OMX_BOOL ret = OMX_FALSE; 1916 mm_jpeg_job_session_t *p_session = NULL; 1917 1918 CDBG("%s:%d] ", __func__, __LINE__); 1919 pthread_mutex_lock(&my_obj->job_lock); 1920 1921 /* abort job if in todo queue */ 1922 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->job_mgr.job_queue, jobId); 1923 if (NULL != node) { 1924 free(node); 1925 goto abort_done; 1926 } 1927 1928 /* abort job if in ongoing queue */ 1929 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, jobId); 1930 if (NULL != node) { 1931 /* find job that is OMX ongoing, ask OMX to abort the job */ 1932 p_session = mm_jpeg_get_session(my_obj, node->enc_info.job_id); 1933 if (p_session) { 1934 mm_jpeg_session_abort(p_session); 1935 } else { 1936 CDBG_ERROR("%s:%d] Invalid job id 0x%x", __func__, __LINE__, 1937 node->enc_info.job_id); 1938 } 1939 free(node); 1940 goto abort_done; 1941 } 1942 1943 abort_done: 1944 pthread_mutex_unlock(&my_obj->job_lock); 1945 1946 return rc; 1947 } 1948 1949 /** mm_jpeg_create_session: 1950 * 1951 * Arguments: 1952 * @my_obj: jpeg object 1953 * @client_hdl: client handle 1954 * @p_params: pointer to encode params 1955 * @p_session_id: session id 1956 * 1957 * Return: 1958 * 0 for success else failure 1959 * 1960 * Description: 1961 * Start the encoding session 1962 * 1963 **/ 1964 int32_t mm_jpeg_create_session(mm_jpeg_obj *my_obj, 1965 uint32_t client_hdl, 1966 mm_jpeg_encode_params_t *p_params, 1967 uint32_t* p_session_id) 1968 { 1969 int32_t rc = 0; 1970 OMX_ERRORTYPE ret = OMX_ErrorNone; 1971 uint8_t clnt_idx = 0; 1972 int session_idx = -1; 1973 mm_jpeg_job_session_t *p_session = NULL; 1974 *p_session_id = 0; 1975 1976 /* validate the parameters */ 1977 if ((p_params->num_src_bufs > MM_JPEG_MAX_BUF) 1978 || (p_params->num_dst_bufs > MM_JPEG_MAX_BUF)) { 1979 CDBG_ERROR("%s:%d] invalid num buffers", __func__, __LINE__); 1980 return -1; 1981 } 1982 1983 /* check if valid client */ 1984 clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl); 1985 if (clnt_idx >= MAX_JPEG_CLIENT_NUM) { 1986 CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl); 1987 return -1; 1988 } 1989 1990 session_idx = mm_jpeg_get_new_session_idx(my_obj, clnt_idx, &p_session); 1991 if (session_idx < 0) { 1992 CDBG_ERROR("%s:%d] invalid session id (%d)", __func__, __LINE__, session_idx); 1993 return -1; 1994 } 1995 1996 ret = mm_jpeg_session_create(p_session); 1997 if (OMX_ErrorNone != ret) { 1998 p_session->active = OMX_FALSE; 1999 CDBG_ERROR("%s:%d] jpeg session create failed", __func__, __LINE__); 2000 return ret; 2001 } 2002 2003 *p_session_id = (JOB_ID_MAGICVAL << 24) | (session_idx << 8) | clnt_idx; 2004 2005 /*copy the params*/ 2006 p_session->params = *p_params; 2007 p_session->client_hdl = client_hdl; 2008 p_session->sessionId = *p_session_id; 2009 p_session->jpeg_obj = (void*)my_obj; /* save a ptr to jpeg_obj */ 2010 CDBG("%s:%d] session id %x", __func__, __LINE__, *p_session_id); 2011 2012 return ret; 2013 } 2014 /** mm_jpeg_destroy_job 2015 * 2016 * Arguments: 2017 * @p_session: Session obj 2018 * 2019 * Return: 2020 * 0 for success else failure 2021 * 2022 * Description: 2023 * Destroy the job based paramenters 2024 * 2025 **/ 2026 int32_t mm_jpeg_destroy_job(mm_jpeg_job_session_t *p_session) 2027 { 2028 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; 2029 int i = 0, rc = 0; 2030 2031 CDBG_HIGH("%s:%d] Exif entry count %d %d", __func__, __LINE__, 2032 (int)p_jobparams->exif_info.numOfEntries, 2033 (int)p_session->exif_count_local); 2034 for (i = 0; i < p_session->exif_count_local; i++) { 2035 rc = releaseExifEntry(&p_session->exif_info_local[i]); 2036 if (rc) { 2037 CDBG_ERROR("%s:%d] Exif release failed (%d)", __func__, __LINE__, rc); 2038 } 2039 } 2040 p_session->exif_count_local = 0; 2041 2042 return rc; 2043 } 2044 2045 /** mm_jpeg_destroy_session: 2046 * 2047 * Arguments: 2048 * @my_obj: jpeg object 2049 * @session_id: session index 2050 * 2051 * Return: 2052 * 0 for success else failure 2053 * 2054 * Description: 2055 * Destroy the encoding session 2056 * 2057 **/ 2058 int32_t mm_jpeg_destroy_session(mm_jpeg_obj *my_obj, 2059 mm_jpeg_job_session_t *p_session) 2060 { 2061 int32_t rc = 0; 2062 uint8_t clnt_idx = 0; 2063 mm_jpeg_job_q_node_t *node = NULL; 2064 OMX_BOOL ret = OMX_FALSE; 2065 uint32_t session_id = p_session->sessionId; 2066 2067 if (NULL == p_session) { 2068 CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__); 2069 return rc; 2070 } 2071 2072 pthread_mutex_lock(&my_obj->job_lock); 2073 2074 /* abort job if in todo queue */ 2075 CDBG("%s:%d] abort todo jobs", __func__, __LINE__); 2076 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); 2077 while (NULL != node) { 2078 free(node); 2079 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); 2080 } 2081 2082 /* abort job if in ongoing queue */ 2083 CDBG("%s:%d] abort ongoing jobs", __func__, __LINE__); 2084 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); 2085 while (NULL != node) { 2086 free(node); 2087 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); 2088 } 2089 2090 /* abort the current session */ 2091 mm_jpeg_session_abort(p_session); 2092 mm_jpeg_session_destroy(p_session); 2093 mm_jpeg_remove_session_idx(my_obj, session_id); 2094 pthread_mutex_unlock(&my_obj->job_lock); 2095 2096 /* wake up jobMgr thread to work on new job if there is any */ 2097 cam_sem_post(&my_obj->job_mgr.job_sem); 2098 CDBG("%s:%d] X", __func__, __LINE__); 2099 2100 return rc; 2101 } 2102 2103 /** mm_jpeg_destroy_session: 2104 * 2105 * Arguments: 2106 * @my_obj: jpeg object 2107 * @session_id: session index 2108 * 2109 * Return: 2110 * 0 for success else failure 2111 * 2112 * Description: 2113 * Destroy the encoding session 2114 * 2115 **/ 2116 int32_t mm_jpeg_destroy_session_unlocked(mm_jpeg_obj *my_obj, 2117 mm_jpeg_job_session_t *p_session) 2118 { 2119 int32_t rc = -1; 2120 uint8_t clnt_idx = 0; 2121 mm_jpeg_job_q_node_t *node = NULL; 2122 OMX_BOOL ret = OMX_FALSE; 2123 uint32_t session_id = p_session->sessionId; 2124 2125 if (NULL == p_session) { 2126 CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__); 2127 return rc; 2128 } 2129 2130 /* abort job if in todo queue */ 2131 CDBG("%s:%d] abort todo jobs", __func__, __LINE__); 2132 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); 2133 while (NULL != node) { 2134 free(node); 2135 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); 2136 } 2137 2138 /* abort job if in ongoing queue */ 2139 CDBG("%s:%d] abort ongoing jobs", __func__, __LINE__); 2140 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); 2141 while (NULL != node) { 2142 free(node); 2143 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); 2144 } 2145 2146 /* abort the current session */ 2147 mm_jpeg_session_abort(p_session); 2148 mm_jpeg_remove_session_idx(my_obj, session_id); 2149 2150 return rc; 2151 } 2152 2153 /** mm_jpeg_destroy_session: 2154 * 2155 * Arguments: 2156 * @my_obj: jpeg object 2157 * @session_id: session index 2158 * 2159 * Return: 2160 * 0 for success else failure 2161 * 2162 * Description: 2163 * Destroy the encoding session 2164 * 2165 **/ 2166 int32_t mm_jpeg_destroy_session_by_id(mm_jpeg_obj *my_obj, uint32_t session_id) 2167 { 2168 mm_jpeg_job_session_t *p_session = mm_jpeg_get_session(my_obj, session_id); 2169 2170 return mm_jpeg_destroy_session(my_obj, p_session); 2171 } 2172 2173 /** mm_jpeg_close: 2174 * 2175 * Arguments: 2176 * @my_obj: jpeg object 2177 * @client_hdl: client handle 2178 * 2179 * Return: 2180 * 0 for success else failure 2181 * 2182 * Description: 2183 * Close the jpeg client 2184 * 2185 **/ 2186 int32_t mm_jpeg_close(mm_jpeg_obj *my_obj, uint32_t client_hdl) 2187 { 2188 int32_t rc = -1; 2189 uint8_t clnt_idx = 0; 2190 mm_jpeg_job_q_node_t *node = NULL; 2191 OMX_BOOL ret = OMX_FALSE; 2192 int i = 0; 2193 2194 /* check if valid client */ 2195 clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl); 2196 if (clnt_idx >= MAX_JPEG_CLIENT_NUM) { 2197 CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl); 2198 return rc; 2199 } 2200 2201 CDBG("%s:%d] E", __func__, __LINE__); 2202 2203 /* abort all jobs from the client */ 2204 pthread_mutex_lock(&my_obj->job_lock); 2205 2206 CDBG("%s:%d] ", __func__, __LINE__); 2207 2208 for (i = 0; i < MM_JPEG_MAX_SESSION; i++) { 2209 if (OMX_TRUE == my_obj->clnt_mgr[clnt_idx].session[i].active) 2210 mm_jpeg_destroy_session_unlocked(my_obj, 2211 &my_obj->clnt_mgr[clnt_idx].session[i]); 2212 } 2213 2214 CDBG("%s:%d] ", __func__, __LINE__); 2215 2216 pthread_mutex_unlock(&my_obj->job_lock); 2217 CDBG("%s:%d] ", __func__, __LINE__); 2218 2219 /* invalidate client session */ 2220 pthread_mutex_destroy(&my_obj->clnt_mgr[clnt_idx].lock); 2221 memset(&my_obj->clnt_mgr[clnt_idx], 0, sizeof(mm_jpeg_client_t)); 2222 2223 rc = 0; 2224 CDBG("%s:%d] X", __func__, __LINE__); 2225 return rc; 2226 } 2227 2228 OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent, 2229 OMX_PTR pAppData, 2230 OMX_BUFFERHEADERTYPE *pBuffer) 2231 { 2232 OMX_ERRORTYPE ret = OMX_ErrorNone; 2233 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData; 2234 2235 CDBG("%s:%d] count %d ", __func__, __LINE__, p_session->ebd_count); 2236 pthread_mutex_lock(&p_session->lock); 2237 p_session->ebd_count++; 2238 pthread_mutex_unlock(&p_session->lock); 2239 return 0; 2240 } 2241 2242 OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent, 2243 OMX_PTR pAppData, 2244 OMX_BUFFERHEADERTYPE *pBuffer) 2245 { 2246 OMX_ERRORTYPE ret = OMX_ErrorNone; 2247 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData; 2248 uint32_t i = 0; 2249 int rc = 0; 2250 mm_jpeg_output_t output_buf; 2251 2252 CDBG("%s:%d] count %d ", __func__, __LINE__, p_session->fbd_count); 2253 2254 if (OMX_TRUE == p_session->abort_flag) { 2255 pthread_cond_signal(&p_session->cond); 2256 return ret; 2257 } 2258 2259 pthread_mutex_lock(&p_session->lock); 2260 p_session->fbd_count++; 2261 if (NULL != p_session->params.jpeg_cb) { 2262 p_session->job_status = JPEG_JOB_STATUS_DONE; 2263 output_buf.buf_filled_len = (uint32_t)pBuffer->nFilledLen; 2264 output_buf.buf_vaddr = pBuffer->pBuffer; 2265 output_buf.fd = 0; 2266 CDBG("%s:%d] send jpeg callback %d", __func__, __LINE__, 2267 p_session->job_status); 2268 p_session->params.jpeg_cb(p_session->job_status, 2269 p_session->client_hdl, 2270 p_session->jobId, 2271 &output_buf, 2272 p_session->params.userdata); 2273 2274 /* remove from ready queue */ 2275 mm_jpeg_job_done(p_session); 2276 } 2277 pthread_mutex_unlock(&p_session->lock); 2278 CDBG("%s:%d] ", __func__, __LINE__); 2279 2280 return ret; 2281 } 2282 2283 OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent, 2284 OMX_PTR pAppData, 2285 OMX_EVENTTYPE eEvent, 2286 OMX_U32 nData1, 2287 OMX_U32 nData2, 2288 OMX_PTR pEventData) 2289 { 2290 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData; 2291 2292 CDBG("%s:%d] %d %d %d", __func__, __LINE__, eEvent, (int)nData1, 2293 (int)nData2); 2294 2295 pthread_mutex_lock(&p_session->lock); 2296 2297 if (OMX_TRUE == p_session->abort_flag) { 2298 pthread_cond_signal(&p_session->cond); 2299 pthread_mutex_unlock(&p_session->lock); 2300 return OMX_ErrorNone; 2301 } 2302 2303 if (eEvent == OMX_EventError) { 2304 p_session->error_flag = OMX_ErrorHardware; 2305 if (p_session->encoding == OMX_TRUE) { 2306 CDBG("%s:%d] Error during encoding", __func__, __LINE__); 2307 2308 /* send jpeg callback */ 2309 if (NULL != p_session->params.jpeg_cb) { 2310 p_session->job_status = JPEG_JOB_STATUS_ERROR; 2311 CDBG("%s:%d] send jpeg error callback %d", __func__, __LINE__, 2312 p_session->job_status); 2313 p_session->params.jpeg_cb(p_session->job_status, 2314 p_session->client_hdl, 2315 p_session->jobId, 2316 NULL, 2317 p_session->params.userdata); 2318 } 2319 2320 /* remove from ready queue */ 2321 mm_jpeg_job_done(p_session); 2322 } 2323 pthread_cond_signal(&p_session->cond); 2324 } else if (eEvent == OMX_EventCmdComplete) { 2325 if (p_session->state_change_pending == OMX_TRUE) { 2326 p_session->state_change_pending = OMX_FALSE; 2327 pthread_cond_signal(&p_session->cond); 2328 } 2329 } 2330 2331 pthread_mutex_unlock(&p_session->lock); 2332 CDBG("%s:%d]", __func__, __LINE__); 2333 return OMX_ErrorNone; 2334 } 2335 2336 /* remove the first job from the queue with matching client handle */ 2337 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id( 2338 mm_jpeg_queue_t* queue, uint32_t client_hdl) 2339 { 2340 mm_jpeg_q_node_t* node = NULL; 2341 mm_jpeg_job_q_node_t* data = NULL; 2342 mm_jpeg_job_q_node_t* job_node = NULL; 2343 struct cam_list *head = NULL; 2344 struct cam_list *pos = NULL; 2345 2346 pthread_mutex_lock(&queue->lock); 2347 head = &queue->head.list; 2348 pos = head->next; 2349 while(pos != head) { 2350 node = member_of(pos, mm_jpeg_q_node_t, list); 2351 data = (mm_jpeg_job_q_node_t *)node->data; 2352 2353 if (data && (data->enc_info.client_handle == client_hdl)) { 2354 CDBG_HIGH("%s:%d] found matching client handle", __func__, __LINE__); 2355 job_node = data; 2356 cam_list_del_node(&node->list); 2357 queue->size--; 2358 free(node); 2359 CDBG_HIGH("%s: queue size = %d", __func__, queue->size); 2360 break; 2361 } 2362 pos = pos->next; 2363 } 2364 2365 pthread_mutex_unlock(&queue->lock); 2366 2367 return job_node; 2368 } 2369 2370 /* remove the first job from the queue with matching session id */ 2371 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_session_id( 2372 mm_jpeg_queue_t* queue, uint32_t session_id) 2373 { 2374 mm_jpeg_q_node_t* node = NULL; 2375 mm_jpeg_job_q_node_t* data = NULL; 2376 mm_jpeg_job_q_node_t* job_node = NULL; 2377 struct cam_list *head = NULL; 2378 struct cam_list *pos = NULL; 2379 2380 pthread_mutex_lock(&queue->lock); 2381 head = &queue->head.list; 2382 pos = head->next; 2383 while(pos != head) { 2384 node = member_of(pos, mm_jpeg_q_node_t, list); 2385 data = (mm_jpeg_job_q_node_t *)node->data; 2386 2387 if (data && (data->enc_info.encode_job.session_id == session_id)) { 2388 CDBG_HIGH("%s:%d] found matching session id", __func__, __LINE__); 2389 job_node = data; 2390 cam_list_del_node(&node->list); 2391 queue->size--; 2392 free(node); 2393 CDBG_HIGH("%s: queue size = %d", __func__, queue->size); 2394 break; 2395 } 2396 pos = pos->next; 2397 } 2398 2399 pthread_mutex_unlock(&queue->lock); 2400 2401 return job_node; 2402 } 2403 2404 /* remove job from the queue with matching job id */ 2405 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id( 2406 mm_jpeg_queue_t* queue, uint32_t job_id) 2407 { 2408 mm_jpeg_q_node_t* node = NULL; 2409 mm_jpeg_job_q_node_t* data = NULL; 2410 mm_jpeg_job_q_node_t* job_node = NULL; 2411 struct cam_list *head = NULL; 2412 struct cam_list *pos = NULL; 2413 2414 pthread_mutex_lock(&queue->lock); 2415 head = &queue->head.list; 2416 pos = head->next; 2417 while(pos != head) { 2418 node = member_of(pos, mm_jpeg_q_node_t, list); 2419 data = (mm_jpeg_job_q_node_t *)node->data; 2420 2421 if (data && (data->enc_info.job_id == job_id)) { 2422 CDBG_HIGH("%s:%d] found matching job id", __func__, __LINE__); 2423 job_node = data; 2424 cam_list_del_node(&node->list); 2425 queue->size--; 2426 free(node); 2427 break; 2428 } 2429 pos = pos->next; 2430 } 2431 2432 pthread_mutex_unlock(&queue->lock); 2433 2434 return job_node; 2435 } 2436 2437 /* remove job from the queue with matching job id */ 2438 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_unlk( 2439 mm_jpeg_queue_t* queue, uint32_t job_id) 2440 { 2441 mm_jpeg_q_node_t* node = NULL; 2442 mm_jpeg_job_q_node_t* data = NULL; 2443 mm_jpeg_job_q_node_t* job_node = NULL; 2444 struct cam_list *head = NULL; 2445 struct cam_list *pos = NULL; 2446 2447 head = &queue->head.list; 2448 pos = head->next; 2449 while(pos != head) { 2450 node = member_of(pos, mm_jpeg_q_node_t, list); 2451 data = (mm_jpeg_job_q_node_t *)node->data; 2452 2453 if (data && (data->enc_info.job_id == job_id)) { 2454 job_node = data; 2455 cam_list_del_node(&node->list); 2456 queue->size--; 2457 free(node); 2458 break; 2459 } 2460 pos = pos->next; 2461 } 2462 2463 return job_node; 2464 } 2465