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