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