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