mm_jpeg.c revision ce69270a348f6002c378cc821bedd54ae486c7a7
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/** mm_jpeg_encoding_mode:
581 *
582 *  Arguments:
583 *    @p_session: job session
584 *
585 *  Return:
586 *       OMX error values
587 *
588 *  Description:
589 *       Configure the serial or parallel encoding
590 *       mode
591 *
592 **/
593OMX_ERRORTYPE mm_jpeg_encoding_mode(
594  mm_jpeg_job_session_t* p_session)
595{
596  OMX_ERRORTYPE rc = 0;
597  int32_t i = 0;
598  OMX_INDEXTYPE indextype;
599  QOMX_ENCODING_MODE encoding_mode;
600  int32_t totalSize = 0;
601  mm_jpeg_encode_params_t *p_params = &p_session->params;
602  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
603
604  rc = OMX_GetExtensionIndex(p_session->omx_handle,
605    QOMX_IMAGE_EXT_ENCODING_MODE_NAME, &indextype);
606  if (rc != OMX_ErrorNone) {
607    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
608    return rc;
609  }
610
611  CDBG_HIGH("%s:%d] OMX_Serial_Encoding = %d, OMX_Parallel_Encoding = %d ", __func__, __LINE__,
612    (int)OMX_Serial_Encoding,
613    (int)OMX_Parallel_Encoding);
614
615  encoding_mode = OMX_Serial_Encoding;
616  rc = OMX_SetParameter(p_session->omx_handle, indextype, &encoding_mode);
617  if (rc != OMX_ErrorNone) {
618    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
619    return rc;
620  }
621  return rc;
622}
623
624/** map_jpeg_format:
625 *
626 *  Arguments:
627 *    @color_fmt: color format
628 *
629 *  Return:
630 *       OMX color format
631 *
632 *  Description:
633 *       Map mmjpeg color format to OMX color format
634 *
635 **/
636int map_jpeg_format(mm_jpeg_color_format color_fmt)
637{
638  switch (color_fmt) {
639  case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2:
640    return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar;
641  case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2:
642    return (int)OMX_COLOR_FormatYUV420SemiPlanar;
643  case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1:
644    return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar;
645  case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1:
646    return (int)OMX_COLOR_FormatYUV422SemiPlanar;
647  case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V2:
648    return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar_h1v2;
649  case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V2:
650    return (int)OMX_QCOM_IMG_COLOR_FormatYUV422SemiPlanar_h1v2;
651  case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V1:
652    return (int)OMX_QCOM_IMG_COLOR_FormatYVU444SemiPlanar;
653  case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V1:
654    return (int)OMX_QCOM_IMG_COLOR_FormatYUV444SemiPlanar;
655  default:
656    CDBG_ERROR("%s:%d] invalid format %d", __func__, __LINE__, color_fmt);
657    return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar;
658  }
659}
660
661/** mm_jpeg_session_config_port:
662 *
663 *  Arguments:
664 *    @p_session: job session
665 *
666 *  Return:
667 *       OMX error values
668 *
669 *  Description:
670 *       Configure OMX ports
671 *
672 **/
673OMX_ERRORTYPE mm_jpeg_session_config_ports(mm_jpeg_job_session_t* p_session)
674{
675  OMX_ERRORTYPE ret = OMX_ErrorNone;
676  mm_jpeg_encode_params_t *p_params = &p_session->params;
677  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
678
679  mm_jpeg_buf_t *p_src_buf =
680    &p_params->src_main_buf[p_jobparams->src_index];
681
682  p_session->inputPort.nPortIndex = 0;
683  p_session->outputPort.nPortIndex = 1;
684  p_session->inputTmbPort.nPortIndex = 2;
685
686  ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
687    &p_session->inputPort);
688  if (ret) {
689    CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
690    return ret;
691  }
692
693  ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
694    &p_session->inputTmbPort);
695  if (ret) {
696    CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
697    return ret;
698  }
699
700  ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
701    &p_session->outputPort);
702  if (ret) {
703    CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
704    return ret;
705  }
706
707  p_session->inputPort.format.image.nFrameWidth =
708    p_jobparams->main_dim.src_dim.width;
709  p_session->inputPort.format.image.nFrameHeight =
710    p_jobparams->main_dim.src_dim.height;
711  p_session->inputPort.format.image.nStride =
712    p_src_buf->offset.mp[0].stride;
713  p_session->inputPort.format.image.nSliceHeight =
714    p_src_buf->offset.mp[0].scanline;
715  p_session->inputPort.format.image.eColorFormat =
716    map_jpeg_format(p_params->color_format);
717  p_session->inputPort.nBufferSize =
718    p_params->src_main_buf[p_jobparams->src_index].buf_size;
719  p_session->inputPort.nBufferCountActual = p_params->num_src_bufs;
720  ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
721    &p_session->inputPort);
722  if (ret) {
723    CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
724    return ret;
725  }
726
727  if (p_session->params.encode_thumbnail) {
728    mm_jpeg_buf_t *p_tmb_buf =
729      &p_params->src_thumb_buf[p_jobparams->thumb_index];
730    p_session->inputTmbPort.format.image.nFrameWidth =
731      p_jobparams->thumb_dim.src_dim.width;
732    p_session->inputTmbPort.format.image.nFrameHeight =
733      p_jobparams->thumb_dim.src_dim.height;
734    p_session->inputTmbPort.format.image.nStride =
735      p_tmb_buf->offset.mp[0].stride;
736    p_session->inputTmbPort.format.image.nSliceHeight =
737      p_tmb_buf->offset.mp[0].scanline;
738    p_session->inputTmbPort.format.image.eColorFormat =
739      map_jpeg_format(p_params->color_format);
740    p_session->inputTmbPort.nBufferSize =
741      p_params->src_thumb_buf[p_jobparams->thumb_index].buf_size;
742    p_session->inputTmbPort.nBufferCountActual = p_params->num_tmb_bufs;
743    ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
744      &p_session->inputTmbPort);
745
746    if (ret) {
747      CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
748      return ret;
749    }
750
751    // Enable thumbnail port
752    ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortEnable,
753        p_session->inputTmbPort.nPortIndex, NULL);
754
755    if (ret) {
756      CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
757      return ret;
758    }
759  } else {
760    // Disable thumbnail port
761    ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortDisable,
762        p_session->inputTmbPort.nPortIndex, NULL);
763
764    if (ret) {
765      CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
766      return ret;
767    }
768  }
769
770  p_session->outputPort.nBufferSize =
771    p_params->dest_buf[p_jobparams->dst_index].buf_size;
772  p_session->outputPort.nBufferCountActual = p_params->num_dst_bufs;
773  ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
774    &p_session->outputPort);
775  if (ret) {
776    CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
777    return ret;
778  }
779
780  return ret;
781}
782
783/** mm_jpeg_omx_config_thumbnail:
784 *
785 *  Arguments:
786 *    @p_session: job session
787 *
788 *  Return:
789 *       OMX error values
790 *
791 *  Description:
792 *       Configure OMX ports
793 *
794 **/
795OMX_ERRORTYPE mm_jpeg_session_config_thumbnail(mm_jpeg_job_session_t* p_session)
796{
797  OMX_ERRORTYPE ret = OMX_ErrorNone;
798  QOMX_THUMBNAIL_INFO thumbnail_info;
799  OMX_INDEXTYPE thumb_indextype;
800  OMX_BOOL encode_thumbnail = OMX_FALSE;
801  mm_jpeg_encode_params_t *p_params = &p_session->params;
802  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
803  mm_jpeg_dim_t *p_thumb_dim = &p_jobparams->thumb_dim;
804  mm_jpeg_dim_t *p_main_dim = &p_jobparams->main_dim;
805  QOMX_YUV_FRAME_INFO *p_frame_info = &thumbnail_info.tmbOffset;
806  mm_jpeg_buf_t *p_tmb_buf = &p_params->src_thumb_buf[p_jobparams->thumb_index];
807
808  CDBG_HIGH("%s:%d] encode_thumbnail %d", __func__, __LINE__,
809    p_params->encode_thumbnail);
810  if (OMX_FALSE == p_params->encode_thumbnail) {
811    return ret;
812  }
813
814  if ((p_thumb_dim->dst_dim.width == 0) || (p_thumb_dim->dst_dim.height == 0)) {
815    CDBG_ERROR("%s:%d] Error invalid output dim for thumbnail",
816      __func__, __LINE__);
817    return OMX_ErrorBadParameter;
818  }
819
820  if ((p_thumb_dim->src_dim.width == 0) || (p_thumb_dim->src_dim.height == 0)) {
821    CDBG_ERROR("%s:%d] Error invalid input dim for thumbnail",
822      __func__, __LINE__);
823    return OMX_ErrorBadParameter;
824  }
825
826  if ((p_thumb_dim->crop.width == 0) || (p_thumb_dim->crop.height == 0)) {
827    p_thumb_dim->crop.width = p_thumb_dim->src_dim.width;
828    p_thumb_dim->crop.height = p_thumb_dim->src_dim.height;
829  }
830
831  /* check crop boundary */
832  if ((p_thumb_dim->crop.width + p_thumb_dim->crop.left > p_thumb_dim->src_dim.width) ||
833    (p_thumb_dim->crop.height + p_thumb_dim->crop.top > p_thumb_dim->src_dim.height)) {
834    CDBG_ERROR("%s:%d] invalid crop boundary (%d, %d) offset (%d, %d) out of (%d, %d)",
835      __func__, __LINE__,
836      p_thumb_dim->crop.width,
837      p_thumb_dim->crop.height,
838      p_thumb_dim->crop.left,
839      p_thumb_dim->crop.top,
840      p_thumb_dim->src_dim.width,
841      p_thumb_dim->src_dim.height);
842    return OMX_ErrorBadParameter;
843  }
844
845  memset(&thumbnail_info, 0x0, sizeof(QOMX_THUMBNAIL_INFO));
846  ret = OMX_GetExtensionIndex(p_session->omx_handle,
847    QOMX_IMAGE_EXT_THUMBNAIL_NAME,
848    &thumb_indextype);
849  if (ret) {
850    CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
851    return ret;
852  }
853
854  /* fill thumbnail info */
855  thumbnail_info.scaling_enabled = 1;
856  thumbnail_info.input_width = p_thumb_dim->src_dim.width;
857  thumbnail_info.input_height = p_thumb_dim->src_dim.height;
858  thumbnail_info.crop_info.nWidth = p_thumb_dim->crop.width;
859  thumbnail_info.crop_info.nHeight = p_thumb_dim->crop.height;
860  thumbnail_info.crop_info.nLeft = p_thumb_dim->crop.left;
861  thumbnail_info.crop_info.nTop = p_thumb_dim->crop.top;
862
863  if ((p_main_dim->src_dim.width < p_thumb_dim->src_dim.width) ||
864    (p_main_dim->src_dim.height < p_thumb_dim->src_dim.height)) {
865    CDBG_ERROR("%s:%d] Improper thumbnail dim %dx%d resetting to %dx%d",
866      __func__, __LINE__,
867      p_thumb_dim->src_dim.width,
868      p_thumb_dim->src_dim.height,
869      p_main_dim->src_dim.width,
870      p_main_dim->src_dim.height);
871    thumbnail_info.input_width = p_main_dim->src_dim.width;
872    thumbnail_info.input_height = p_main_dim->src_dim.height;
873    if ((thumbnail_info.crop_info.nWidth > thumbnail_info.input_width)
874      || (thumbnail_info.crop_info.nHeight > thumbnail_info.input_height)) {
875      thumbnail_info.crop_info.nLeft = 0;
876      thumbnail_info.crop_info.nTop = 0;
877      thumbnail_info.crop_info.nWidth = thumbnail_info.input_width;
878      thumbnail_info.crop_info.nHeight = thumbnail_info.input_height;
879    }
880  }
881
882  if ((p_thumb_dim->dst_dim.width > p_thumb_dim->src_dim.width)
883    || (p_thumb_dim->dst_dim.height > p_thumb_dim->src_dim.height)) {
884    CDBG_ERROR("%s:%d] Incorrect thumbnail dim %dx%d resetting to %dx%d",
885      __func__, __LINE__,
886      p_thumb_dim->dst_dim.width,
887      p_thumb_dim->dst_dim.height,
888      p_thumb_dim->src_dim.width,
889      p_thumb_dim->src_dim.height);
890    thumbnail_info.output_width = p_thumb_dim->src_dim.width;
891    thumbnail_info.output_height = p_thumb_dim->src_dim.height;
892  } else {
893    thumbnail_info.output_width = p_thumb_dim->dst_dim.width;
894    thumbnail_info.output_height = p_thumb_dim->dst_dim.height;
895  }
896
897  memset(p_frame_info, 0x0, sizeof(*p_frame_info));
898
899  p_frame_info->cbcrStartOffset[0] = p_tmb_buf->offset.mp[0].len;
900  p_frame_info->cbcrStartOffset[1] = p_tmb_buf->offset.mp[1].len;
901  p_frame_info->yOffset = p_tmb_buf->offset.mp[0].offset;
902  p_frame_info->cbcrOffset[0] = p_tmb_buf->offset.mp[1].offset;
903  p_frame_info->cbcrOffset[1] = p_tmb_buf->offset.mp[2].offset;
904
905  ret = OMX_SetParameter(p_session->omx_handle, thumb_indextype,
906    &thumbnail_info);
907  if (ret) {
908    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
909    return ret;
910  }
911
912  return ret;
913}
914
915/** mm_jpeg_session_config_main_crop:
916 *
917 *  Arguments:
918 *    @p_session: job session
919 *
920 *  Return:
921 *       OMX error values
922 *
923 *  Description:
924 *       Configure main image crop
925 *
926 **/
927OMX_ERRORTYPE mm_jpeg_session_config_main_crop(mm_jpeg_job_session_t *p_session)
928{
929  OMX_CONFIG_RECTTYPE rect_type_in, rect_type_out;
930  OMX_ERRORTYPE ret = OMX_ErrorNone;
931  mm_jpeg_encode_params_t *p_params = &p_session->params;
932  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
933  mm_jpeg_dim_t *dim = &p_jobparams->main_dim;
934
935  if ((dim->crop.width == 0) || (dim->crop.height == 0)) {
936    dim->crop.width = dim->src_dim.width;
937    dim->crop.height = dim->src_dim.height;
938  }
939  /* error check first */
940  if ((dim->crop.width + dim->crop.left > dim->src_dim.width) ||
941    (dim->crop.height + dim->crop.top > dim->src_dim.height)) {
942    CDBG_ERROR("%s:%d] invalid crop boundary (%d, %d) out of (%d, %d)",
943      __func__, __LINE__,
944      dim->crop.width + dim->crop.left,
945      dim->crop.height + dim->crop.top,
946      dim->src_dim.width,
947      dim->src_dim.height);
948    return OMX_ErrorBadParameter;
949  }
950
951  memset(&rect_type_in, 0, sizeof(rect_type_in));
952  memset(&rect_type_out, 0, sizeof(rect_type_out));
953  rect_type_in.nPortIndex = 0;
954  rect_type_out.nPortIndex = 0;
955
956  if ((dim->src_dim.width != dim->crop.width) ||
957    (dim->src_dim.height != dim->crop.height) ||
958    (dim->src_dim.width != dim->dst_dim.width) ||
959    (dim->src_dim.height != dim->dst_dim.height)) {
960    /* Scaler information */
961    rect_type_in.nWidth = CEILING2(dim->crop.width);
962    rect_type_in.nHeight = CEILING2(dim->crop.height);
963    rect_type_in.nLeft = dim->crop.left;
964    rect_type_in.nTop = dim->crop.top;
965
966    if (dim->dst_dim.width && dim->dst_dim.height) {
967      rect_type_out.nWidth = dim->dst_dim.width;
968      rect_type_out.nHeight = dim->dst_dim.height;
969    }
970  }
971
972  ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonInputCrop,
973    &rect_type_in);
974  if (OMX_ErrorNone != ret) {
975    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
976    return ret;
977  }
978
979  CDBG("%s:%d] OMX_IndexConfigCommonInputCrop w = %d, h = %d, l = %d, t = %d,"
980    " port_idx = %d", __func__, __LINE__,
981    (int)rect_type_in.nWidth, (int)rect_type_in.nHeight,
982    (int)rect_type_in.nLeft, (int)rect_type_in.nTop,
983    (int)rect_type_in.nPortIndex);
984
985  ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonOutputCrop,
986    &rect_type_out);
987  if (OMX_ErrorNone != ret) {
988    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
989    return ret;
990  }
991  CDBG("%s:%d] OMX_IndexConfigCommonOutputCrop w = %d, h = %d,"
992    " port_idx = %d", __func__, __LINE__,
993    (int)rect_type_out.nWidth, (int)rect_type_out.nHeight,
994    (int)rect_type_out.nPortIndex);
995
996  return ret;
997}
998
999/** mm_jpeg_session_config_main:
1000 *
1001 *  Arguments:
1002 *    @p_session: job session
1003 *
1004 *  Return:
1005 *       OMX error values
1006 *
1007 *  Description:
1008 *       Configure main image
1009 *
1010 **/
1011OMX_ERRORTYPE mm_jpeg_session_config_main(mm_jpeg_job_session_t *p_session)
1012{
1013  OMX_ERRORTYPE rc = OMX_ErrorNone;
1014  OMX_IMAGE_PARAM_QFACTORTYPE q_factor;
1015  mm_jpeg_encode_params_t *p_params = &p_session->params;
1016  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
1017
1018  /* config port */
1019  CDBG("%s:%d] config port", __func__, __LINE__);
1020  rc = mm_jpeg_session_config_ports(p_session);
1021  if (OMX_ErrorNone != rc) {
1022    CDBG_ERROR("%s: config port failed", __func__);
1023    return rc;
1024  }
1025
1026  /* config buffer offset */
1027  CDBG("%s:%d] config main buf offset", __func__, __LINE__);
1028  rc = mm_jpeg_session_config_main_buffer_offset(p_session);
1029  if (OMX_ErrorNone != rc) {
1030    CDBG_ERROR("%s: config buffer offset failed", __func__);
1031    return rc;
1032  }
1033
1034  /* config crop */
1035  CDBG("%s:%d] config main crop", __func__, __LINE__);
1036  rc = mm_jpeg_session_config_main_crop(p_session);
1037  if (OMX_ErrorNone != rc) {
1038    CDBG_ERROR("%s: config crop failed", __func__);
1039    return rc;
1040  }
1041
1042  /* set quality */
1043  memset(&q_factor, 0, sizeof(q_factor));
1044  q_factor.nPortIndex = 0;
1045  q_factor.nQFactor = p_params->quality;
1046  rc = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamQFactor, &q_factor);
1047  CDBG("%s:%d] config QFactor: %d", __func__, __LINE__, (int)q_factor.nQFactor);
1048  if (OMX_ErrorNone != rc) {
1049    CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
1050    return rc;
1051  }
1052
1053  return rc;
1054}
1055
1056/** mm_jpeg_session_config_common:
1057 *
1058 *  Arguments:
1059 *    @p_session: job session
1060 *
1061 *  Return:
1062 *       OMX error values
1063 *
1064 *  Description:
1065 *       Configure common parameters
1066 *
1067 **/
1068OMX_ERRORTYPE mm_jpeg_session_config_common(mm_jpeg_job_session_t *p_session)
1069{
1070  OMX_ERRORTYPE rc = OMX_ErrorNone;
1071  int i;
1072  OMX_INDEXTYPE exif_idx;
1073  OMX_CONFIG_ROTATIONTYPE rotate;
1074  mm_jpeg_encode_params_t *p_params = &p_session->params;
1075  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
1076  QOMX_EXIF_INFO exif_info;
1077
1078  /* set rotation */
1079  memset(&rotate, 0, sizeof(rotate));
1080  rotate.nPortIndex = 1;
1081  rotate.nRotation = p_jobparams->rotation;
1082  rc = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonRotate,
1083    &rotate);
1084  if (OMX_ErrorNone != rc) {
1085      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
1086      return rc;
1087  }
1088  CDBG("%s:%d] Set rotation to %d at port_idx = %d", __func__, __LINE__,
1089    (int)p_jobparams->rotation, (int)rotate.nPortIndex);
1090
1091  /* Set Exif data*/
1092  memset(&p_session->exif_info_all[0],  0,  sizeof(p_session->exif_info_all));
1093
1094  exif_info.numOfEntries = p_params->exif_info.numOfEntries;
1095  exif_info.exif_data = &p_session->exif_info_all[0];
1096  /*If Exif data has been passed copy it*/
1097  if (p_params->exif_info.numOfEntries > 0) {
1098    CDBG("%s:%d] Num of exif entries passed from HAL: %d", __func__, __LINE__,
1099      p_params->exif_info.numOfEntries);
1100    memcpy(exif_info.exif_data, p_params->exif_info.exif_data,
1101      sizeof(QEXIF_INFO_DATA) * p_params->exif_info.numOfEntries);
1102  }
1103
1104  if (exif_info.numOfEntries > 0) {
1105    /* set exif tags */
1106    CDBG("%s:%d] Set exif tags count %d", __func__, __LINE__,
1107      (int)exif_info.numOfEntries);
1108    rc = OMX_GetExtensionIndex(p_session->omx_handle, QOMX_IMAGE_EXT_EXIF_NAME,
1109      &exif_idx);
1110    if (OMX_ErrorNone != rc) {
1111      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
1112      return rc;
1113    }
1114
1115    rc = OMX_SetParameter(p_session->omx_handle, exif_idx,
1116      &exif_info);
1117    if (OMX_ErrorNone != rc) {
1118      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
1119      return rc;
1120    }
1121  }
1122
1123  return rc;
1124}
1125
1126/** mm_jpeg_session_abort:
1127 *
1128 *  Arguments:
1129 *    @p_session: jpeg session
1130 *
1131 *  Return:
1132 *       OMX_BOOL
1133 *
1134 *  Description:
1135 *       Abort ongoing job
1136 *
1137 **/
1138OMX_BOOL mm_jpeg_session_abort(mm_jpeg_job_session_t *p_session)
1139{
1140  OMX_ERRORTYPE ret = OMX_ErrorNone;
1141
1142  CDBG("%s:%d] E", __func__, __LINE__);
1143  pthread_mutex_lock(&p_session->lock);
1144  if (OMX_TRUE == p_session->abort_flag) {
1145    pthread_mutex_unlock(&p_session->lock);
1146    CDBG("%s:%d] **** ALREADY ABORTED", __func__, __LINE__);
1147    return 0;
1148  }
1149  p_session->abort_flag = OMX_TRUE;
1150  if (OMX_TRUE == p_session->encoding) {
1151    p_session->state_change_pending = OMX_TRUE;
1152
1153    CDBG("%s:%d] **** ABORTING", __func__, __LINE__);
1154
1155    ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet,
1156    OMX_StateIdle, NULL);
1157
1158    if (ret != OMX_ErrorNone) {
1159      CDBG("%s:%d] OMX_SendCommand returned error %d", __func__, __LINE__, ret);
1160      pthread_mutex_unlock(&p_session->lock);
1161      return 1;
1162    }
1163
1164    CDBG("%s:%d] before wait", __func__, __LINE__);
1165    pthread_cond_wait(&p_session->cond, &p_session->lock);
1166    CDBG("%s:%d] after wait", __func__, __LINE__);
1167  }
1168  pthread_mutex_unlock(&p_session->lock);
1169  CDBG("%s:%d] X", __func__, __LINE__);
1170  return 0;
1171}
1172
1173/** mm_jpeg_get_job_idx:
1174 *
1175 *  Arguments:
1176 *    @my_obj: jpeg object
1177 *    @client_idx: client index
1178 *
1179 *  Return:
1180 *       job index
1181 *
1182 *  Description:
1183 *       Get job index by client id
1184 *
1185 **/
1186inline int mm_jpeg_get_new_session_idx(mm_jpeg_obj *my_obj, int client_idx,
1187  mm_jpeg_job_session_t **pp_session)
1188{
1189  int i = 0;
1190  int index = -1;
1191  for (i = 0; i < MM_JPEG_MAX_SESSION; i++) {
1192    pthread_mutex_lock(&my_obj->clnt_mgr[client_idx].lock);
1193    if (!my_obj->clnt_mgr[client_idx].session[i].active) {
1194      *pp_session = &my_obj->clnt_mgr[client_idx].session[i];
1195      my_obj->clnt_mgr[client_idx].session[i].active = OMX_TRUE;
1196      index = i;
1197      pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock);
1198      break;
1199    }
1200    pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock);
1201  }
1202  return index;
1203}
1204
1205/** mm_jpeg_get_job_idx:
1206 *
1207 *  Arguments:
1208 *    @my_obj: jpeg object
1209 *    @client_idx: client index
1210 *
1211 *  Return:
1212 *       job index
1213 *
1214 *  Description:
1215 *       Get job index by client id
1216 *
1217 **/
1218inline void mm_jpeg_remove_session_idx(mm_jpeg_obj *my_obj, uint32_t job_id)
1219{
1220  int client_idx =  GET_CLIENT_IDX(job_id);
1221  int session_idx= GET_SESSION_IDX(job_id);
1222  CDBG("%s:%d] client_idx %d session_idx %d", __func__, __LINE__,
1223    client_idx, session_idx);
1224  pthread_mutex_lock(&my_obj->clnt_mgr[client_idx].lock);
1225  my_obj->clnt_mgr[client_idx].session[session_idx].active = OMX_FALSE;
1226  pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock);
1227}
1228
1229/** mm_jpeg_get_session_idx:
1230 *
1231 *  Arguments:
1232 *    @my_obj: jpeg object
1233 *    @client_idx: client index
1234 *
1235 *  Return:
1236 *       job index
1237 *
1238 *  Description:
1239 *       Get job index by client id
1240 *
1241 **/
1242inline mm_jpeg_job_session_t *mm_jpeg_get_session(mm_jpeg_obj *my_obj, uint32_t job_id)
1243{
1244  mm_jpeg_job_session_t *p_session = NULL;
1245  int client_idx =  GET_CLIENT_IDX(job_id);
1246  int session_idx= GET_SESSION_IDX(job_id);
1247
1248  CDBG("%s:%d] client_idx %d session_idx %d", __func__, __LINE__,
1249    client_idx, session_idx);
1250  if ((session_idx >= MM_JPEG_MAX_SESSION) ||
1251    (client_idx >= MAX_JPEG_CLIENT_NUM)) {
1252    CDBG_ERROR("%s:%d] invalid job id %x", __func__, __LINE__,
1253      job_id);
1254    return NULL;
1255  }
1256  pthread_mutex_lock(&my_obj->clnt_mgr[client_idx].lock);
1257  p_session = &my_obj->clnt_mgr[client_idx].session[session_idx];
1258  pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock);
1259  return p_session;
1260}
1261
1262/** mm_jpeg_session_configure:
1263 *
1264 *  Arguments:
1265 *    @data: encode session
1266 *
1267 *  Return:
1268 *       none
1269 *
1270 *  Description:
1271 *       Configure the session
1272 *
1273 **/
1274static OMX_ERRORTYPE mm_jpeg_session_configure(mm_jpeg_job_session_t *p_session)
1275{
1276  OMX_ERRORTYPE ret = OMX_ErrorNone;
1277  mm_jpeg_encode_params_t *p_params = &p_session->params;
1278  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
1279  mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj;
1280
1281  CDBG("%s:%d] E ", __func__, __LINE__);
1282
1283  MM_JPEG_CHK_ABORT(p_session, ret, error);
1284
1285  /* config main img */
1286  ret = mm_jpeg_session_config_main(p_session);
1287  if (OMX_ErrorNone != ret) {
1288    CDBG_ERROR("%s:%d] config main img failed", __func__, __LINE__);
1289    goto error;
1290  }
1291
1292  /* config thumbnail */
1293  ret = mm_jpeg_session_config_thumbnail(p_session);
1294  if (OMX_ErrorNone != ret) {
1295    CDBG_ERROR("%s:%d] config thumbnail img failed", __func__, __LINE__);
1296    goto error;
1297  }
1298
1299  /* config encoding mode */
1300  CDBG("%s:%d] config encoding mode", __func__, __LINE__);
1301  ret = mm_jpeg_encoding_mode(p_session);
1302  if (OMX_ErrorNone != ret) {
1303    CDBG_ERROR("%s: config encoding mode failed", __func__);
1304    return ret;
1305  }
1306
1307  /* common config */
1308  ret = mm_jpeg_session_config_common(p_session);
1309  if (OMX_ErrorNone != ret) {
1310    CDBG_ERROR("%s:%d] config common failed", __func__, __LINE__);
1311    goto error;
1312  }
1313
1314  ret = mm_jpeg_session_change_state(p_session, OMX_StateIdle,
1315    mm_jpeg_session_send_buffers);
1316  if (ret) {
1317    CDBG_ERROR("%s:%d] change state to idle failed %d",
1318      __func__, __LINE__, ret);
1319    goto error;
1320  }
1321
1322  ret = mm_jpeg_session_change_state(p_session, OMX_StateExecuting,
1323    NULL);
1324  if (ret) {
1325    CDBG_ERROR("%s:%d] change state to executing failed %d",
1326      __func__, __LINE__, ret);
1327    goto error;
1328  }
1329
1330error:
1331  CDBG("%s:%d] X ret %d", __func__, __LINE__, ret);
1332  return ret;
1333}
1334
1335/** mm_jpeg_session_encode:
1336 *
1337 *  Arguments:
1338 *    @p_session: encode session
1339 *
1340 *  Return:
1341 *       OMX_ERRORTYPE
1342 *
1343 *  Description:
1344 *       Start the encoding
1345 *
1346 **/
1347static inline void mm_jpeg_job_done(mm_jpeg_job_session_t *p_session)
1348{
1349  mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj;
1350  mm_jpeg_job_q_node_t *node = NULL;
1351
1352  /*remove the job*/
1353  node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q,
1354    p_session->jobId);
1355  if (node) {
1356    free(node);
1357  }
1358  p_session->encoding = OMX_FALSE;
1359
1360  /* wake up jobMgr thread to work on new job if there is any */
1361  cam_sem_post(&my_obj->job_mgr.job_sem);
1362}
1363
1364/** mm_jpeg_session_encode:
1365 *
1366 *  Arguments:
1367 *    @p_session: encode session
1368 *
1369 *  Return:
1370 *       OMX_ERRORTYPE
1371 *
1372 *  Description:
1373 *       Start the encoding
1374 *
1375 **/
1376static OMX_ERRORTYPE mm_jpeg_session_encode(mm_jpeg_job_session_t *p_session)
1377{
1378  OMX_ERRORTYPE ret = OMX_ErrorNone;
1379  mm_jpeg_encode_params_t *p_params = &p_session->params;
1380  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
1381  int dest_idx = 0;
1382  mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj;
1383
1384  pthread_mutex_lock(&p_session->lock);
1385  p_session->abort_flag = OMX_FALSE;
1386  p_session->encoding = OMX_FALSE;
1387  pthread_mutex_unlock(&p_session->lock);
1388
1389  if (OMX_FALSE == p_session->config) {
1390    ret = mm_jpeg_session_configure(p_session);
1391    if (ret) {
1392      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1393      goto error;
1394    }
1395    p_session->config = OMX_TRUE;
1396  }
1397
1398  pthread_mutex_lock(&p_session->lock);
1399  p_session->encoding = OMX_TRUE;
1400  pthread_mutex_unlock(&p_session->lock);
1401
1402  MM_JPEG_CHK_ABORT(p_session, ret, error);
1403
1404#ifdef MM_JPEG_DUMP_INPUT
1405  DUMP_TO_FILE("/data/mm_jpeg_int.yuv",
1406    p_session->p_in_omx_buf[p_jobparams->src_index]->pBuffer,
1407    (int)p_session->p_in_omx_buf[p_jobparams->src_index]->nAllocLen);
1408#endif
1409
1410  ret = OMX_EmptyThisBuffer(p_session->omx_handle,
1411    p_session->p_in_omx_buf[p_jobparams->src_index]);
1412  if (ret) {
1413    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1414    goto error;
1415  }
1416
1417  if (p_session->params.encode_thumbnail) {
1418    ret = OMX_EmptyThisBuffer(p_session->omx_handle,
1419        p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]);
1420    if (ret) {
1421      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1422      goto error;
1423    }
1424  }
1425
1426  ret = OMX_FillThisBuffer(p_session->omx_handle,
1427    p_session->p_out_omx_buf[p_jobparams->dst_index]);
1428  if (ret) {
1429    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1430    goto error;
1431  }
1432
1433  MM_JPEG_CHK_ABORT(p_session, ret, error);
1434
1435error:
1436
1437  CDBG("%s:%d] X ", __func__, __LINE__);
1438  return ret;
1439}
1440
1441/** mm_jpeg_process_encoding_job:
1442 *
1443 *  Arguments:
1444 *    @my_obj: jpeg client
1445 *    @job_node: job node
1446 *
1447 *  Return:
1448 *       0 for success -1 otherwise
1449 *
1450 *  Description:
1451 *       Start the encoding job
1452 *
1453 **/
1454int32_t mm_jpeg_process_encoding_job(mm_jpeg_obj *my_obj, mm_jpeg_job_q_node_t* job_node)
1455{
1456  int32_t rc = 0;
1457  OMX_ERRORTYPE ret = OMX_ErrorNone;
1458  mm_jpeg_job_session_t *p_session = NULL;
1459  mm_jpeg_job_q_node_t *node = NULL;
1460
1461  /* check if valid session */
1462  p_session = mm_jpeg_get_session(my_obj, job_node->enc_info.job_id);
1463  if (NULL == p_session) {
1464    CDBG_ERROR("%s:%d] invalid job id %x", __func__, __LINE__,
1465      job_node->enc_info.job_id);
1466    return -1;
1467  }
1468
1469  /* sent encode cmd to OMX, queue job into ongoing queue */
1470  rc = mm_jpeg_queue_enq(&my_obj->ongoing_job_q, job_node);
1471  if (rc) {
1472    CDBG_ERROR("%s:%d] jpeg enqueue failed %d",
1473      __func__, __LINE__, ret);
1474    goto error;
1475  }
1476
1477  p_session->encode_job = job_node->enc_info.encode_job;
1478  p_session->jobId = job_node->enc_info.job_id;
1479  ret = mm_jpeg_session_encode(p_session);
1480  if (ret) {
1481    CDBG_ERROR("%s:%d] encode session failed", __func__, __LINE__);
1482    goto error;
1483  }
1484
1485  CDBG("%s:%d] Success X ", __func__, __LINE__);
1486  return rc;
1487
1488error:
1489
1490  if ((OMX_ErrorNone != ret) &&
1491    (NULL != p_session->params.jpeg_cb)) {
1492    p_session->job_status = JPEG_JOB_STATUS_ERROR;
1493    CDBG("%s:%d] send jpeg error callback %d", __func__, __LINE__,
1494      p_session->job_status);
1495    p_session->params.jpeg_cb(p_session->job_status,
1496      p_session->client_hdl,
1497      p_session->jobId,
1498      NULL,
1499      p_session->params.userdata);
1500  }
1501
1502  /*remove the job*/
1503  mm_jpeg_job_done(p_session);
1504  CDBG("%s:%d] Error X ", __func__, __LINE__);
1505
1506  return rc;
1507}
1508
1509/** mm_jpeg_jobmgr_thread:
1510 *
1511 *  Arguments:
1512 *    @my_obj: jpeg object
1513 *
1514 *  Return:
1515 *       0 for success else failure
1516 *
1517 *  Description:
1518 *       job manager thread main function
1519 *
1520 **/
1521static void *mm_jpeg_jobmgr_thread(void *data)
1522{
1523  int rc = 0;
1524  int running = 1;
1525  uint32_t num_ongoing_jobs = 0;
1526  mm_jpeg_obj *my_obj = (mm_jpeg_obj*)data;
1527  mm_jpeg_job_cmd_thread_t *cmd_thread = &my_obj->job_mgr;
1528  mm_jpeg_job_q_node_t* node = NULL;
1529
1530  do {
1531    do {
1532      rc = cam_sem_wait(&cmd_thread->job_sem);
1533      if (rc != 0 && errno != EINVAL) {
1534        CDBG_ERROR("%s: cam_sem_wait error (%s)",
1535          __func__, strerror(errno));
1536        return NULL;
1537      }
1538    } while (rc != 0);
1539
1540    /* check ongoing q size */
1541    num_ongoing_jobs = mm_jpeg_queue_get_size(&my_obj->ongoing_job_q);
1542    if (num_ongoing_jobs >= NUM_MAX_JPEG_CNCURRENT_JOBS) {
1543      CDBG("%s:%d] ongoing job already reach max %d", __func__,
1544        __LINE__, num_ongoing_jobs);
1545      continue;
1546    }
1547
1548    pthread_mutex_lock(&my_obj->job_lock);
1549    /* can go ahead with new work */
1550    node = (mm_jpeg_job_q_node_t*)mm_jpeg_queue_deq(&cmd_thread->job_queue);
1551    if (node != NULL) {
1552      switch (node->type) {
1553      case MM_JPEG_CMD_TYPE_JOB:
1554        rc = mm_jpeg_process_encoding_job(my_obj, node);
1555        break;
1556      case MM_JPEG_CMD_TYPE_EXIT:
1557      default:
1558        /* free node */
1559        free(node);
1560        /* set running flag to false */
1561        running = 0;
1562        break;
1563      }
1564    }
1565    pthread_mutex_unlock(&my_obj->job_lock);
1566
1567  } while (running);
1568  return NULL;
1569}
1570
1571/** mm_jpeg_jobmgr_thread_launch:
1572 *
1573 *  Arguments:
1574 *    @my_obj: jpeg object
1575 *
1576 *  Return:
1577 *       0 for success else failure
1578 *
1579 *  Description:
1580 *       launches the job manager thread
1581 *
1582 **/
1583int32_t mm_jpeg_jobmgr_thread_launch(mm_jpeg_obj *my_obj)
1584{
1585  int32_t rc = 0;
1586  mm_jpeg_job_cmd_thread_t *job_mgr = &my_obj->job_mgr;
1587
1588  cam_sem_init(&job_mgr->job_sem, 0);
1589  mm_jpeg_queue_init(&job_mgr->job_queue);
1590
1591  /* launch the thread */
1592  pthread_create(&job_mgr->pid,
1593    NULL,
1594    mm_jpeg_jobmgr_thread,
1595    (void *)my_obj);
1596  return rc;
1597}
1598
1599/** mm_jpeg_jobmgr_thread_release:
1600 *
1601 *  Arguments:
1602 *    @my_obj: jpeg object
1603 *
1604 *  Return:
1605 *       0 for success else failure
1606 *
1607 *  Description:
1608 *       Releases the job manager thread
1609 *
1610 **/
1611int32_t mm_jpeg_jobmgr_thread_release(mm_jpeg_obj * my_obj)
1612{
1613  int32_t rc = 0;
1614  mm_jpeg_job_cmd_thread_t * cmd_thread = &my_obj->job_mgr;
1615  mm_jpeg_job_q_node_t* node =
1616    (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t));
1617  if (NULL == node) {
1618    CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__);
1619    return -1;
1620  }
1621
1622  memset(node, 0, sizeof(mm_jpeg_job_q_node_t));
1623  node->type = MM_JPEG_CMD_TYPE_EXIT;
1624
1625  mm_jpeg_queue_enq(&cmd_thread->job_queue, node);
1626  cam_sem_post(&cmd_thread->job_sem);
1627
1628  /* wait until cmd thread exits */
1629  if (pthread_join(cmd_thread->pid, NULL) != 0) {
1630    CDBG("%s: pthread dead already", __func__);
1631  }
1632  mm_jpeg_queue_deinit(&cmd_thread->job_queue);
1633
1634  cam_sem_destroy(&cmd_thread->job_sem);
1635  memset(cmd_thread, 0, sizeof(mm_jpeg_job_cmd_thread_t));
1636  return rc;
1637}
1638
1639/** mm_jpeg_init:
1640 *
1641 *  Arguments:
1642 *    @my_obj: jpeg object
1643 *
1644 *  Return:
1645 *       0 for success else failure
1646 *
1647 *  Description:
1648 *       Initializes the jpeg client
1649 *
1650 **/
1651int32_t mm_jpeg_init(mm_jpeg_obj *my_obj)
1652{
1653  int32_t rc = 0;
1654
1655  /* init locks */
1656  pthread_mutex_init(&my_obj->job_lock, NULL);
1657
1658  /* init ongoing job queue */
1659  rc = mm_jpeg_queue_init(&my_obj->ongoing_job_q);
1660  if (0 != rc) {
1661    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1662    return -1;
1663  }
1664
1665  /* init job semaphore and launch jobmgr thread */
1666  CDBG("%s:%d] Launch jobmgr thread rc %d", __func__, __LINE__, rc);
1667  rc = mm_jpeg_jobmgr_thread_launch(my_obj);
1668  if (0 != rc) {
1669    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1670    return -1;
1671  }
1672
1673  /* load OMX */
1674  if (OMX_ErrorNone != OMX_Init()) {
1675    /* roll back in error case */
1676    CDBG_ERROR("%s:%d] OMX_Init failed (%d)", __func__, __LINE__, rc);
1677    mm_jpeg_jobmgr_thread_release(my_obj);
1678    mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
1679    pthread_mutex_destroy(&my_obj->job_lock);
1680  }
1681
1682  return rc;
1683}
1684
1685/** mm_jpeg_deinit:
1686 *
1687 *  Arguments:
1688 *    @my_obj: jpeg object
1689 *
1690 *  Return:
1691 *       0 for success else failure
1692 *
1693 *  Description:
1694 *       Deinits the jpeg client
1695 *
1696 **/
1697int32_t mm_jpeg_deinit(mm_jpeg_obj *my_obj)
1698{
1699  int32_t rc = 0;
1700
1701  /* release jobmgr thread */
1702  rc = mm_jpeg_jobmgr_thread_release(my_obj);
1703  if (0 != rc) {
1704    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1705  }
1706
1707  /* unload OMX engine */
1708  OMX_Deinit();
1709
1710  /* deinit ongoing job and cb queue */
1711  rc = mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
1712  if (0 != rc) {
1713    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1714  }
1715
1716  /* destroy locks */
1717  pthread_mutex_destroy(&my_obj->job_lock);
1718
1719  return rc;
1720}
1721
1722/** mm_jpeg_new_client:
1723 *
1724 *  Arguments:
1725 *    @my_obj: jpeg object
1726 *
1727 *  Return:
1728 *       0 for success else failure
1729 *
1730 *  Description:
1731 *       Create new jpeg client
1732 *
1733 **/
1734uint32_t mm_jpeg_new_client(mm_jpeg_obj *my_obj)
1735{
1736  uint32_t client_hdl = 0;
1737  uint8_t idx;
1738  int i = 0;
1739
1740  if (my_obj->num_clients >= MAX_JPEG_CLIENT_NUM) {
1741    CDBG_ERROR("%s: num of clients reached limit", __func__);
1742    return client_hdl;
1743  }
1744
1745  for (idx = 0; idx < MAX_JPEG_CLIENT_NUM; idx++) {
1746    if (0 == my_obj->clnt_mgr[idx].is_used) {
1747      break;
1748    }
1749  }
1750
1751  if (idx < MAX_JPEG_CLIENT_NUM) {
1752    /* client session avail */
1753    /* generate client handler by index */
1754    client_hdl = mm_jpeg_util_generate_handler(idx);
1755
1756    /* update client session */
1757    my_obj->clnt_mgr[idx].is_used = 1;
1758    my_obj->clnt_mgr[idx].client_handle = client_hdl;
1759
1760    pthread_mutex_init(&my_obj->clnt_mgr[idx].lock, NULL);
1761    for (i = 0; i < MM_JPEG_MAX_SESSION; i++) {
1762      memset(&my_obj->clnt_mgr[idx].session[i], 0x0, sizeof(mm_jpeg_job_session_t));
1763    }
1764
1765    /* increse client count */
1766    my_obj->num_clients++;
1767  }
1768
1769  return client_hdl;
1770}
1771
1772/** mm_jpeg_start_job:
1773 *
1774 *  Arguments:
1775 *    @my_obj: jpeg object
1776 *    @client_hdl: client handle
1777 *    @job: pointer to encode job
1778 *    @jobId: job id
1779 *
1780 *  Return:
1781 *       0 for success else failure
1782 *
1783 *  Description:
1784 *       Start the encoding job
1785 *
1786 **/
1787int32_t mm_jpeg_start_job(mm_jpeg_obj *my_obj,
1788  mm_jpeg_job_t *job,
1789  uint32_t *job_id)
1790{
1791  int32_t rc = -1;
1792  uint8_t session_idx = 0;
1793  uint8_t client_idx = 0;
1794  mm_jpeg_job_q_node_t* node = NULL;
1795  mm_jpeg_job_session_t *p_session = NULL;
1796  mm_jpeg_encode_job_t *p_jobparams  = &job->encode_job;
1797
1798  *job_id = 0;
1799
1800  /* check if valid session */
1801  session_idx = GET_SESSION_IDX(p_jobparams->session_id);
1802  client_idx = GET_CLIENT_IDX(p_jobparams->session_id);
1803  CDBG("%s:%d] session_idx %d client idx %d", __func__, __LINE__,
1804    session_idx, client_idx);
1805
1806  if ((session_idx >= MM_JPEG_MAX_SESSION) ||
1807    (client_idx >= MAX_JPEG_CLIENT_NUM)) {
1808    CDBG_ERROR("%s:%d] invalid session id %x", __func__, __LINE__,
1809      job->encode_job.session_id);
1810    return rc;
1811  }
1812
1813  p_session = &my_obj->clnt_mgr[client_idx].session[session_idx];
1814  if (OMX_FALSE == p_session->active) {
1815    CDBG_ERROR("%s:%d] session not active %x", __func__, __LINE__,
1816      job->encode_job.session_id);
1817    return rc;
1818  }
1819
1820  if ((p_jobparams->src_index >= p_session->params.num_src_bufs) ||
1821    (p_jobparams->dst_index >= p_session->params.num_dst_bufs)) {
1822    CDBG_ERROR("%s:%d] invalid buffer indices", __func__, __LINE__);
1823    return rc;
1824  }
1825
1826  /* enqueue new job into todo job queue */
1827  node = (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t));
1828  if (NULL == node) {
1829    CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__);
1830    return -1;
1831  }
1832
1833  *job_id = job->encode_job.session_id |
1834    ((p_session->job_hist++ % JOB_HIST_MAX) << 16);
1835
1836  memset(node, 0, sizeof(mm_jpeg_job_q_node_t));
1837  node->enc_info.encode_job = job->encode_job;
1838  node->enc_info.job_id = *job_id;
1839  node->enc_info.client_handle = p_session->client_hdl;
1840  node->type = MM_JPEG_CMD_TYPE_JOB;
1841
1842  rc = mm_jpeg_queue_enq(&my_obj->job_mgr.job_queue, node);
1843  if (0 == rc) {
1844    cam_sem_post(&my_obj->job_mgr.job_sem);
1845  }
1846
1847  return rc;
1848}
1849
1850/** mm_jpeg_abort_job:
1851 *
1852 *  Arguments:
1853 *    @my_obj: jpeg object
1854 *    @client_hdl: client handle
1855 *    @jobId: job id
1856 *
1857 *  Return:
1858 *       0 for success else failure
1859 *
1860 *  Description:
1861 *       Abort the encoding session
1862 *
1863 **/
1864int32_t mm_jpeg_abort_job(mm_jpeg_obj *my_obj,
1865  uint32_t jobId)
1866{
1867  int32_t rc = -1;
1868  uint8_t clnt_idx = 0;
1869  mm_jpeg_job_q_node_t *node = NULL;
1870  OMX_BOOL ret = OMX_FALSE;
1871  mm_jpeg_job_session_t *p_session = NULL;
1872
1873  CDBG("%s:%d] ", __func__, __LINE__);
1874  pthread_mutex_lock(&my_obj->job_lock);
1875
1876  /* abort job if in todo queue */
1877  node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->job_mgr.job_queue, jobId);
1878  if (NULL != node) {
1879    free(node);
1880    goto abort_done;
1881  }
1882
1883  /* abort job if in ongoing queue */
1884  node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, jobId);
1885  if (NULL != node) {
1886    /* find job that is OMX ongoing, ask OMX to abort the job */
1887    p_session = mm_jpeg_get_session(my_obj, node->enc_info.job_id);
1888    if (p_session) {
1889      mm_jpeg_session_abort(p_session);
1890    } else {
1891      CDBG_ERROR("%s:%d] Invalid job id 0x%x", __func__, __LINE__,
1892        node->enc_info.job_id);
1893    }
1894    free(node);
1895    goto abort_done;
1896  }
1897
1898abort_done:
1899  pthread_mutex_unlock(&my_obj->job_lock);
1900
1901  return rc;
1902}
1903
1904/** mm_jpeg_create_session:
1905 *
1906 *  Arguments:
1907 *    @my_obj: jpeg object
1908 *    @client_hdl: client handle
1909 *    @p_params: pointer to encode params
1910 *    @p_session_id: session id
1911 *
1912 *  Return:
1913 *       0 for success else failure
1914 *
1915 *  Description:
1916 *       Start the encoding session
1917 *
1918 **/
1919int32_t mm_jpeg_create_session(mm_jpeg_obj *my_obj,
1920  uint32_t client_hdl,
1921  mm_jpeg_encode_params_t *p_params,
1922  uint32_t* p_session_id)
1923{
1924  int32_t rc = 0;
1925  OMX_ERRORTYPE ret = OMX_ErrorNone;
1926  uint8_t clnt_idx = 0;
1927  int session_idx = -1;
1928  mm_jpeg_job_session_t *p_session = NULL;
1929  *p_session_id = 0;
1930
1931  /* validate the parameters */
1932  if ((p_params->num_src_bufs > MM_JPEG_MAX_BUF)
1933    || (p_params->num_dst_bufs > MM_JPEG_MAX_BUF)) {
1934    CDBG_ERROR("%s:%d] invalid num buffers", __func__, __LINE__);
1935    return -1;
1936  }
1937
1938  /* check if valid client */
1939  clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl);
1940  if (clnt_idx >= MAX_JPEG_CLIENT_NUM) {
1941    CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl);
1942    return -1;
1943  }
1944
1945  session_idx = mm_jpeg_get_new_session_idx(my_obj, clnt_idx, &p_session);
1946  if (session_idx < 0) {
1947    CDBG_ERROR("%s:%d] invalid session id (%d)", __func__, __LINE__, session_idx);
1948    return -1;
1949  }
1950
1951  ret = mm_jpeg_session_create(p_session);
1952  if (OMX_ErrorNone != ret) {
1953    p_session->active = OMX_FALSE;
1954    CDBG_ERROR("%s:%d] jpeg session create failed", __func__, __LINE__);
1955    return ret;
1956  }
1957
1958  *p_session_id = (JOB_ID_MAGICVAL << 24) | (session_idx << 8) | clnt_idx;
1959
1960  /*copy the params*/
1961  p_session->params = *p_params;
1962  p_session->client_hdl = client_hdl;
1963  p_session->sessionId = *p_session_id;
1964  p_session->jpeg_obj = (void*)my_obj; /* save a ptr to jpeg_obj */
1965  CDBG("%s:%d] session id %x", __func__, __LINE__, *p_session_id);
1966
1967  return ret;
1968}
1969
1970/** mm_jpeg_destroy_session:
1971 *
1972 *  Arguments:
1973 *    @my_obj: jpeg object
1974 *    @session_id: session index
1975 *
1976 *  Return:
1977 *       0 for success else failure
1978 *
1979 *  Description:
1980 *       Destroy the encoding session
1981 *
1982 **/
1983int32_t mm_jpeg_destroy_session(mm_jpeg_obj *my_obj,
1984  mm_jpeg_job_session_t *p_session)
1985{
1986  int32_t rc = 0;
1987  uint8_t clnt_idx = 0;
1988  mm_jpeg_job_q_node_t *node = NULL;
1989  OMX_BOOL ret = OMX_FALSE;
1990  uint32_t session_id = p_session->sessionId;
1991
1992  if (NULL == p_session) {
1993    CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__);
1994    return rc;
1995  }
1996
1997  pthread_mutex_lock(&my_obj->job_lock);
1998
1999  /* abort job if in todo queue */
2000  CDBG("%s:%d] abort todo jobs", __func__, __LINE__);
2001  node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
2002  while (NULL != node) {
2003    free(node);
2004    node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
2005  }
2006
2007  /* abort job if in ongoing queue */
2008  CDBG("%s:%d] abort ongoing jobs", __func__, __LINE__);
2009  node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
2010  while (NULL != node) {
2011    free(node);
2012    node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
2013  }
2014
2015  /* abort the current session */
2016  mm_jpeg_session_abort(p_session);
2017  mm_jpeg_session_destroy(p_session);
2018  mm_jpeg_remove_session_idx(my_obj, session_id);
2019  pthread_mutex_unlock(&my_obj->job_lock);
2020
2021  /* wake up jobMgr thread to work on new job if there is any */
2022  cam_sem_post(&my_obj->job_mgr.job_sem);
2023  CDBG("%s:%d] X", __func__, __LINE__);
2024
2025  return rc;
2026}
2027
2028/** mm_jpeg_destroy_session:
2029 *
2030 *  Arguments:
2031 *    @my_obj: jpeg object
2032 *    @session_id: session index
2033 *
2034 *  Return:
2035 *       0 for success else failure
2036 *
2037 *  Description:
2038 *       Destroy the encoding session
2039 *
2040 **/
2041int32_t mm_jpeg_destroy_session_unlocked(mm_jpeg_obj *my_obj,
2042  mm_jpeg_job_session_t *p_session)
2043{
2044  int32_t rc = -1;
2045  uint8_t clnt_idx = 0;
2046  mm_jpeg_job_q_node_t *node = NULL;
2047  OMX_BOOL ret = OMX_FALSE;
2048  uint32_t session_id = p_session->sessionId;
2049
2050  if (NULL == p_session) {
2051    CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__);
2052    return rc;
2053  }
2054
2055  /* abort job if in todo queue */
2056  CDBG("%s:%d] abort todo jobs", __func__, __LINE__);
2057  node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
2058  while (NULL != node) {
2059    free(node);
2060    node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
2061  }
2062
2063  /* abort job if in ongoing queue */
2064  CDBG("%s:%d] abort ongoing jobs", __func__, __LINE__);
2065  node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
2066  while (NULL != node) {
2067    free(node);
2068    node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
2069  }
2070
2071  /* abort the current session */
2072  mm_jpeg_session_abort(p_session);
2073  mm_jpeg_remove_session_idx(my_obj, session_id);
2074
2075  return rc;
2076}
2077
2078/** mm_jpeg_destroy_session:
2079 *
2080 *  Arguments:
2081 *    @my_obj: jpeg object
2082 *    @session_id: session index
2083 *
2084 *  Return:
2085 *       0 for success else failure
2086 *
2087 *  Description:
2088 *       Destroy the encoding session
2089 *
2090 **/
2091int32_t mm_jpeg_destroy_session_by_id(mm_jpeg_obj *my_obj, uint32_t session_id)
2092{
2093  mm_jpeg_job_session_t *p_session = mm_jpeg_get_session(my_obj, session_id);
2094
2095  return mm_jpeg_destroy_session(my_obj, p_session);
2096}
2097
2098/** mm_jpeg_close:
2099 *
2100 *  Arguments:
2101 *    @my_obj: jpeg object
2102 *    @client_hdl: client handle
2103 *
2104 *  Return:
2105 *       0 for success else failure
2106 *
2107 *  Description:
2108 *       Close the jpeg client
2109 *
2110 **/
2111int32_t mm_jpeg_close(mm_jpeg_obj *my_obj, uint32_t client_hdl)
2112{
2113  int32_t rc = -1;
2114  uint8_t clnt_idx = 0;
2115  mm_jpeg_job_q_node_t *node = NULL;
2116  OMX_BOOL ret = OMX_FALSE;
2117  int i = 0;
2118
2119  /* check if valid client */
2120  clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl);
2121  if (clnt_idx >= MAX_JPEG_CLIENT_NUM) {
2122    CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl);
2123    return rc;
2124  }
2125
2126  CDBG("%s:%d] E", __func__, __LINE__);
2127
2128  /* abort all jobs from the client */
2129  pthread_mutex_lock(&my_obj->job_lock);
2130
2131  CDBG("%s:%d] ", __func__, __LINE__);
2132
2133  for (i = 0; i < MM_JPEG_MAX_SESSION; i++) {
2134    if (OMX_TRUE == my_obj->clnt_mgr[clnt_idx].session[i].active)
2135      mm_jpeg_destroy_session_unlocked(my_obj,
2136        &my_obj->clnt_mgr[clnt_idx].session[i]);
2137  }
2138
2139  CDBG("%s:%d] ", __func__, __LINE__);
2140
2141  pthread_mutex_unlock(&my_obj->job_lock);
2142  CDBG("%s:%d] ", __func__, __LINE__);
2143
2144  /* invalidate client session */
2145  pthread_mutex_destroy(&my_obj->clnt_mgr[clnt_idx].lock);
2146  memset(&my_obj->clnt_mgr[clnt_idx], 0, sizeof(mm_jpeg_client_t));
2147
2148  rc = 0;
2149  CDBG("%s:%d] X", __func__, __LINE__);
2150  return rc;
2151}
2152
2153OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent,
2154  OMX_PTR pAppData,
2155  OMX_BUFFERHEADERTYPE *pBuffer)
2156{
2157  OMX_ERRORTYPE ret = OMX_ErrorNone;
2158  mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
2159
2160  CDBG("%s:%d] count %d ", __func__, __LINE__, p_session->ebd_count);
2161  pthread_mutex_lock(&p_session->lock);
2162  p_session->ebd_count++;
2163  pthread_mutex_unlock(&p_session->lock);
2164  return 0;
2165}
2166
2167OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent,
2168  OMX_PTR pAppData,
2169  OMX_BUFFERHEADERTYPE *pBuffer)
2170{
2171  OMX_ERRORTYPE ret = OMX_ErrorNone;
2172  mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
2173  uint32_t i = 0;
2174  int rc = 0;
2175  mm_jpeg_output_t output_buf;
2176
2177  CDBG("%s:%d] count %d ", __func__, __LINE__, p_session->fbd_count);
2178
2179  if (OMX_TRUE == p_session->abort_flag) {
2180    pthread_cond_signal(&p_session->cond);
2181    return ret;
2182  }
2183
2184  pthread_mutex_lock(&p_session->lock);
2185  p_session->fbd_count++;
2186  if (NULL != p_session->params.jpeg_cb) {
2187    p_session->job_status = JPEG_JOB_STATUS_DONE;
2188    output_buf.buf_filled_len = (uint32_t)pBuffer->nFilledLen;
2189    output_buf.buf_vaddr = pBuffer->pBuffer;
2190    output_buf.fd = 0;
2191    CDBG("%s:%d] send jpeg callback %d", __func__, __LINE__,
2192      p_session->job_status);
2193    p_session->params.jpeg_cb(p_session->job_status,
2194      p_session->client_hdl,
2195      p_session->jobId,
2196      &output_buf,
2197      p_session->params.userdata);
2198
2199    /* remove from ready queue */
2200    mm_jpeg_job_done(p_session);
2201  }
2202  pthread_mutex_unlock(&p_session->lock);
2203  CDBG("%s:%d] ", __func__, __LINE__);
2204
2205  return ret;
2206}
2207
2208OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent,
2209  OMX_PTR pAppData,
2210  OMX_EVENTTYPE eEvent,
2211  OMX_U32 nData1,
2212  OMX_U32 nData2,
2213  OMX_PTR pEventData)
2214{
2215  mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
2216
2217  CDBG("%s:%d] %d %d %d", __func__, __LINE__, eEvent, (int)nData1,
2218    (int)nData2);
2219
2220  pthread_mutex_lock(&p_session->lock);
2221
2222  if (OMX_TRUE == p_session->abort_flag) {
2223    pthread_cond_signal(&p_session->cond);
2224    pthread_mutex_unlock(&p_session->lock);
2225    return OMX_ErrorNone;
2226  }
2227
2228  if (eEvent == OMX_EventError) {
2229    p_session->error_flag = OMX_ErrorHardware;
2230    if (p_session->encoding == OMX_TRUE) {
2231      CDBG("%s:%d] Error during encoding", __func__, __LINE__);
2232
2233      /* send jpeg callback */
2234      if (NULL != p_session->params.jpeg_cb) {
2235        p_session->job_status = JPEG_JOB_STATUS_ERROR;
2236        CDBG("%s:%d] send jpeg error callback %d", __func__, __LINE__,
2237          p_session->job_status);
2238        p_session->params.jpeg_cb(p_session->job_status,
2239          p_session->client_hdl,
2240          p_session->jobId,
2241          NULL,
2242          p_session->params.userdata);
2243      }
2244
2245      /* remove from ready queue */
2246      mm_jpeg_job_done(p_session);
2247    }
2248    pthread_cond_signal(&p_session->cond);
2249  } else if (eEvent == OMX_EventCmdComplete) {
2250    if (p_session->state_change_pending == OMX_TRUE) {
2251      p_session->state_change_pending = OMX_FALSE;
2252      pthread_cond_signal(&p_session->cond);
2253    }
2254  }
2255
2256  pthread_mutex_unlock(&p_session->lock);
2257  CDBG("%s:%d]", __func__, __LINE__);
2258  return OMX_ErrorNone;
2259}
2260
2261/* remove the first job from the queue with matching client handle */
2262mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id(
2263  mm_jpeg_queue_t* queue, uint32_t client_hdl)
2264{
2265  mm_jpeg_q_node_t* node = NULL;
2266  mm_jpeg_job_q_node_t* data = NULL;
2267  mm_jpeg_job_q_node_t* job_node = NULL;
2268  struct cam_list *head = NULL;
2269  struct cam_list *pos = NULL;
2270
2271  pthread_mutex_lock(&queue->lock);
2272  head = &queue->head.list;
2273  pos = head->next;
2274  while(pos != head) {
2275    node = member_of(pos, mm_jpeg_q_node_t, list);
2276    data = (mm_jpeg_job_q_node_t *)node->data;
2277
2278    if (data && (data->enc_info.client_handle == client_hdl)) {
2279      CDBG_ERROR("%s:%d] found matching client handle", __func__, __LINE__);
2280      job_node = data;
2281      cam_list_del_node(&node->list);
2282      queue->size--;
2283      free(node);
2284      CDBG_ERROR("%s: queue size = %d", __func__, queue->size);
2285      break;
2286    }
2287    pos = pos->next;
2288  }
2289
2290  pthread_mutex_unlock(&queue->lock);
2291
2292  return job_node;
2293}
2294
2295/* remove the first job from the queue with matching session id */
2296mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_session_id(
2297  mm_jpeg_queue_t* queue, uint32_t session_id)
2298{
2299  mm_jpeg_q_node_t* node = NULL;
2300  mm_jpeg_job_q_node_t* data = NULL;
2301  mm_jpeg_job_q_node_t* job_node = NULL;
2302  struct cam_list *head = NULL;
2303  struct cam_list *pos = NULL;
2304
2305  pthread_mutex_lock(&queue->lock);
2306  head = &queue->head.list;
2307  pos = head->next;
2308  while(pos != head) {
2309    node = member_of(pos, mm_jpeg_q_node_t, list);
2310    data = (mm_jpeg_job_q_node_t *)node->data;
2311
2312    if (data && (data->enc_info.encode_job.session_id == session_id)) {
2313      CDBG_ERROR("%s:%d] found matching session id", __func__, __LINE__);
2314      job_node = data;
2315      cam_list_del_node(&node->list);
2316      queue->size--;
2317      free(node);
2318      CDBG_ERROR("%s: queue size = %d", __func__, queue->size);
2319      break;
2320    }
2321    pos = pos->next;
2322  }
2323
2324  pthread_mutex_unlock(&queue->lock);
2325
2326  return job_node;
2327}
2328
2329/* remove job from the queue with matching job id */
2330mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id(
2331  mm_jpeg_queue_t* queue, uint32_t job_id)
2332{
2333  mm_jpeg_q_node_t* node = NULL;
2334  mm_jpeg_job_q_node_t* data = NULL;
2335  mm_jpeg_job_q_node_t* job_node = NULL;
2336  struct cam_list *head = NULL;
2337  struct cam_list *pos = NULL;
2338
2339  pthread_mutex_lock(&queue->lock);
2340  head = &queue->head.list;
2341  pos = head->next;
2342  while(pos != head) {
2343    node = member_of(pos, mm_jpeg_q_node_t, list);
2344    data = (mm_jpeg_job_q_node_t *)node->data;
2345
2346    if (data && (data->enc_info.job_id == job_id)) {
2347      CDBG_ERROR("%s:%d] found matching job id", __func__, __LINE__);
2348      job_node = data;
2349      cam_list_del_node(&node->list);
2350      queue->size--;
2351      free(node);
2352      break;
2353    }
2354    pos = pos->next;
2355  }
2356
2357  pthread_mutex_unlock(&queue->lock);
2358
2359  return job_node;
2360}
2361
2362/* remove job from the queue with matching job id */
2363mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_unlk(
2364  mm_jpeg_queue_t* queue, uint32_t job_id)
2365{
2366  mm_jpeg_q_node_t* node = NULL;
2367  mm_jpeg_job_q_node_t* data = NULL;
2368  mm_jpeg_job_q_node_t* job_node = NULL;
2369  struct cam_list *head = NULL;
2370  struct cam_list *pos = NULL;
2371
2372  head = &queue->head.list;
2373  pos = head->next;
2374  while(pos != head) {
2375    node = member_of(pos, mm_jpeg_q_node_t, list);
2376    data = (mm_jpeg_job_q_node_t *)node->data;
2377
2378    if (data && (data->enc_info.job_id == job_id)) {
2379      job_node = data;
2380      cam_list_del_node(&node->list);
2381      queue->size--;
2382      free(node);
2383      break;
2384    }
2385    pos = pos->next;
2386  }
2387
2388  return job_node;
2389}
2390