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