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