mm_jpeg.c revision edc7d18eca9cc3d053d0c41059366e06dd524334
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
126OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent,
127    OMX_PTR pAppData,
128    OMX_BUFFERHEADERTYPE* pBuffer);
129OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent,
130    OMX_PTR pAppData,
131    OMX_BUFFERHEADERTYPE* pBuffer);
132OMX_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 **/
151static 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 **/
245mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id(
246  mm_jpeg_queue_t* queue, uint32_t client_hdl);
247mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id(
248  mm_jpeg_queue_t* queue, uint32_t job_id);
249mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_session_id(
250  mm_jpeg_queue_t* queue, uint32_t session_id);
251mm_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 **/
258typedef OMX_ERRORTYPE (*mm_jpeg_transition_func_t)(void *);
259
260
261/** mm_jpeg_queue_func_t:
262 *
263 * Intermediate function for queue operation
264 **/
265typedef 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 **/
279OMX_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 **/
340OMX_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 **/
392OMX_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 **/
461OMX_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 **/
505void 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 **/
549OMX_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 **/
609OMX_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 **/
652int 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 **/
689OMX_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 */
814OMX_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 **/
855OMX_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 **/
1026OMX_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 **/
1110OMX_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 **/
1149OMX_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 **/
1239OMX_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 **/
1291inline 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 **/
1323inline 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 **/
1347inline 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 **/
1379static 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 **/
1434static 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
1467error:
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 **/
1484static 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 **/
1516static 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
1580error:
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 **/
1599int32_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
1633error:
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 **/
1666static 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 **/
1729int32_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 **/
1757int32_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 **/
1797int32_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 **/
1843int32_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 **/
1880uint32_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 **/
1933int32_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 **/
2010int32_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
2044abort_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 **/
2065int32_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 **/
2127int32_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 **/
2159int32_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 **/
2217int32_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 **/
2267int32_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 **/
2287int32_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
2329OMX_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
2343OMX_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
2384OMX_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 */
2438mm_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 */
2472mm_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 */
2506mm_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 */
2539mm_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