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