mm_jpeg.c revision f11b21ef2a1403f259cc039c930ce922683d510a
1/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 *     * Redistributions of source code must retain the above copyright
7 *       notice, this list of conditions and the following disclaimer.
8 *     * Redistributions in binary form must reproduce the above
9 *       copyright notice, this list of conditions and the following
10 *       disclaimer in the documentation and/or other materials provided
11 *       with the distribution.
12 *     * Neither the name of The Linux Foundation nor the names of its
13 *       contributors may be used to endorse or promote products derived
14 *       from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#define ATRACE_TAG ATRACE_TAG_CAMERA
31
32#include <pthread.h>
33#include <errno.h>
34#include <sys/ioctl.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <sys/prctl.h>
38#include <fcntl.h>
39#include <poll.h>
40#include <cutils/trace.h>
41#include <math.h>
42
43#include "mm_jpeg_dbg.h"
44#include "mm_jpeg_interface.h"
45#include "mm_jpeg.h"
46#include "mm_jpeg_inlines.h"
47
48#ifdef LOAD_ADSP_RPC_LIB
49#include <dlfcn.h>
50#include <stdlib.h>
51#endif
52
53#define ENCODING_MODE_PARALLEL 1
54
55#define META_KEYFILE QCAMERA_DUMP_FRM_LOCATION"metadata.key"
56
57/**
58 * minimal resolution needed for normal mode of ops
59 */
60#define MM_JPEG_MIN_NOM_RESOLUTION 7680000 /*8MP*/
61
62OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent,
63    OMX_PTR pAppData,
64    OMX_BUFFERHEADERTYPE* pBuffer);
65OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent,
66    OMX_PTR pAppData,
67    OMX_BUFFERHEADERTYPE* pBuffer);
68OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent,
69    OMX_PTR pAppData,
70    OMX_EVENTTYPE eEvent,
71    OMX_U32 nData1,
72    OMX_U32 nData2,
73    OMX_PTR pEventData);
74
75static int32_t mm_jpegenc_destroy_job(mm_jpeg_job_session_t *p_session);
76static void mm_jpegenc_job_done(mm_jpeg_job_session_t *p_session);
77mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_dst_ptr(
78  mm_jpeg_queue_t* queue, void * dst_ptr);
79static OMX_ERRORTYPE mm_jpeg_session_configure(mm_jpeg_job_session_t *p_session);
80
81/** mm_jpeg_session_send_buffers:
82 *
83 *  Arguments:
84 *    @data: job session
85 *
86 *  Return:
87 *       OMX error values
88 *
89 *  Description:
90 *       Send the buffers to OMX layer
91 *
92 **/
93OMX_ERRORTYPE mm_jpeg_session_send_buffers(void *data)
94{
95  uint32_t i = 0;
96  mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data;
97  OMX_ERRORTYPE ret = OMX_ErrorNone;
98  QOMX_BUFFER_INFO lbuffer_info;
99  mm_jpeg_encode_params_t *p_params = &p_session->params;
100
101  memset(&lbuffer_info, 0x0, sizeof(QOMX_BUFFER_INFO));
102  for (i = 0; i < p_params->num_src_bufs; i++) {
103    CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
104    lbuffer_info.fd = (OMX_U32)p_params->src_main_buf[i].fd;
105    ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_in_omx_buf[i]), 0,
106      &lbuffer_info, p_params->src_main_buf[i].buf_size,
107      p_params->src_main_buf[i].buf_vaddr);
108    if (ret) {
109      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
110      return ret;
111    }
112  }
113
114  for (i = 0; i < p_params->num_tmb_bufs; i++) {
115    CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
116    lbuffer_info.fd = (OMX_U32)p_params->src_thumb_buf[i].fd;
117    ret = OMX_UseBuffer(p_session->omx_handle,
118        &(p_session->p_in_omx_thumb_buf[i]), 2,
119        &lbuffer_info, p_params->src_thumb_buf[i].buf_size,
120        p_params->src_thumb_buf[i].buf_vaddr);
121    if (ret) {
122      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
123      return ret;
124    }
125  }
126
127  for (i = 0; i < p_params->num_dst_bufs; i++) {
128    CDBG("%s:%d] Dest buffer %d", __func__, __LINE__, i);
129    ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_out_omx_buf[i]),
130      1, NULL, p_params->dest_buf[i].buf_size,
131      p_params->dest_buf[i].buf_vaddr);
132    if (ret) {
133      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
134      return ret;
135    }
136  }
137  CDBG("%s:%d]", __func__, __LINE__);
138  return ret;
139}
140
141
142/** mm_jpeg_session_free_buffers:
143 *
144 *  Arguments:
145 *    @data: job session
146 *
147 *  Return:
148 *       OMX error values
149 *
150 *  Description:
151 *       Free the buffers from OMX layer
152 *
153 **/
154OMX_ERRORTYPE mm_jpeg_session_free_buffers(void *data)
155{
156  OMX_ERRORTYPE ret = OMX_ErrorNone;
157  uint32_t i = 0;
158  mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data;
159  mm_jpeg_encode_params_t *p_params = &p_session->params;
160
161  for (i = 0; i < p_params->num_src_bufs; i++) {
162    CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
163    ret = OMX_FreeBuffer(p_session->omx_handle, 0, p_session->p_in_omx_buf[i]);
164    if (ret) {
165      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
166      return ret;
167    }
168  }
169
170  for (i = 0; i < p_params->num_tmb_bufs; i++) {
171    CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
172    ret = OMX_FreeBuffer(p_session->omx_handle, 2, p_session->p_in_omx_thumb_buf[i]);
173    if (ret) {
174      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
175      return ret;
176    }
177  }
178
179  for (i = 0; i < p_params->num_dst_bufs; i++) {
180    CDBG("%s:%d] Dest buffer %d", __func__, __LINE__, i);
181    ret = OMX_FreeBuffer(p_session->omx_handle, 1, p_session->p_out_omx_buf[i]);
182    if (ret) {
183      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
184      return ret;
185    }
186  }
187  CDBG("%s:%d]", __func__, __LINE__);
188  return ret;
189}
190
191
192
193
194/** mm_jpeg_session_change_state:
195 *
196 *  Arguments:
197 *    @p_session: job session
198 *    @new_state: new state to be transitioned to
199 *    @p_exec: transition function
200 *
201 *  Return:
202 *       OMX error values
203 *
204 *  Description:
205 *       This method is used for state transition
206 *
207 **/
208OMX_ERRORTYPE mm_jpeg_session_change_state(mm_jpeg_job_session_t* p_session,
209  OMX_STATETYPE new_state,
210  mm_jpeg_transition_func_t p_exec)
211{
212  OMX_ERRORTYPE ret = OMX_ErrorNone;
213  OMX_STATETYPE current_state;
214  CDBG("%s:%d] new_state %d p_exec %p", __func__, __LINE__,
215    new_state, p_exec);
216
217
218  pthread_mutex_lock(&p_session->lock);
219
220  ret = OMX_GetState(p_session->omx_handle, &current_state);
221
222  if (ret) {
223    pthread_mutex_unlock(&p_session->lock);
224    return ret;
225  }
226
227  if (current_state == new_state) {
228    pthread_mutex_unlock(&p_session->lock);
229    return OMX_ErrorNone;
230  }
231
232  p_session->state_change_pending = OMX_TRUE;
233  pthread_mutex_unlock(&p_session->lock);
234  ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet,
235    new_state, NULL);
236  pthread_mutex_lock(&p_session->lock);
237  if (ret) {
238    CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
239    pthread_mutex_unlock(&p_session->lock);
240    return OMX_ErrorIncorrectStateTransition;
241  }
242  CDBG("%s:%d] ", __func__, __LINE__);
243  if ((OMX_ErrorNone != p_session->error_flag) &&
244      (OMX_ErrorOverflow != p_session->error_flag)) {
245    CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, p_session->error_flag);
246    pthread_mutex_unlock(&p_session->lock);
247    return p_session->error_flag;
248  }
249  if (p_exec) {
250    ret = p_exec(p_session);
251    if (ret) {
252      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
253      pthread_mutex_unlock(&p_session->lock);
254      return ret;
255    }
256  }
257  CDBG("%s:%d] ", __func__, __LINE__);
258  if (p_session->state_change_pending) {
259    CDBG("%s:%d] before wait", __func__, __LINE__);
260    pthread_cond_wait(&p_session->cond, &p_session->lock);
261    CDBG("%s:%d] after wait", __func__, __LINE__);
262  }
263  pthread_mutex_unlock(&p_session->lock);
264  CDBG("%s:%d] ", __func__, __LINE__);
265  return ret;
266}
267
268/** mm_jpeg_session_create:
269 *
270 *  Arguments:
271 *    @p_session: job session
272 *
273 *  Return:
274 *       OMX error types
275 *
276 *  Description:
277 *       Create a jpeg encode session
278 *
279 **/
280OMX_ERRORTYPE mm_jpeg_session_create(mm_jpeg_job_session_t* p_session)
281{
282  OMX_ERRORTYPE rc = OMX_ErrorNone;
283  mm_jpeg_obj *my_obj = (mm_jpeg_obj *) p_session->jpeg_obj;
284  char *omx_lib = "OMX.qcom.image.jpeg.encoder";
285
286  pthread_mutex_init(&p_session->lock, NULL);
287  pthread_cond_init(&p_session->cond, NULL);
288  cirq_reset(&p_session->cb_q);
289  p_session->state_change_pending = OMX_FALSE;
290  p_session->abort_state = MM_JPEG_ABORT_NONE;
291  p_session->error_flag = OMX_ErrorNone;
292  p_session->ebd_count = 0;
293  p_session->fbd_count = 0;
294  p_session->encode_pid = -1;
295  p_session->config = OMX_FALSE;
296  p_session->exif_count_local = 0;
297  p_session->auto_out_buf = OMX_FALSE;
298
299  p_session->omx_callbacks.EmptyBufferDone = mm_jpeg_ebd;
300  p_session->omx_callbacks.FillBufferDone = mm_jpeg_fbd;
301  p_session->omx_callbacks.EventHandler = mm_jpeg_event_handler;
302
303  p_session->thumb_from_main = 0;
304#ifdef MM_JPEG_USE_PIPELINE
305  p_session->thumb_from_main = 1;
306  omx_lib = "OMX.qcom.image.jpeg.encoder_pipeline";
307#endif
308
309  rc = OMX_GetHandle(&p_session->omx_handle,
310      omx_lib,
311      (void *)p_session,
312      &p_session->omx_callbacks);
313  if (OMX_ErrorNone != rc) {
314    CDBG_ERROR("%s:%d] OMX_GetHandle failed (%d)", __func__, __LINE__, rc);
315    return rc;
316  }
317
318  my_obj->num_sessions++;
319
320  return rc;
321}
322
323
324
325/** mm_jpeg_session_destroy:
326 *
327 *  Arguments:
328 *    @p_session: job session
329 *
330 *  Return:
331 *       none
332 *
333 *  Description:
334 *       Destroy a jpeg encode session
335 *
336 **/
337void mm_jpeg_session_destroy(mm_jpeg_job_session_t* p_session)
338{
339  OMX_ERRORTYPE rc = OMX_ErrorNone;
340  OMX_STATETYPE state;
341  mm_jpeg_obj *my_obj = (mm_jpeg_obj *) p_session->jpeg_obj;
342
343  CDBG("%s:%d] E", __func__, __LINE__);
344  if (NULL == p_session->omx_handle) {
345    CDBG_ERROR("%s:%d] invalid handle", __func__, __LINE__);
346    return;
347  }
348
349  rc = OMX_GetState(p_session->omx_handle, &state);
350
351  //Check state before state transition
352  if ((state == OMX_StateExecuting) || (state == OMX_StatePause)) {
353    rc = mm_jpeg_session_change_state(p_session, OMX_StateIdle, NULL);
354    if (rc) {
355      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
356    }
357  }
358
359  rc = OMX_GetState(p_session->omx_handle, &state);
360
361  if (state == OMX_StateIdle) {
362    rc = mm_jpeg_session_change_state(p_session, OMX_StateLoaded,
363      mm_jpeg_session_free_buffers);
364    if (rc) {
365      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
366    }
367  }
368
369  rc = OMX_FreeHandle(p_session->omx_handle);
370  if (0 != rc) {
371    CDBG_ERROR("%s:%d] OMX_FreeHandle failed (%d)", __func__, __LINE__, rc);
372  }
373  p_session->omx_handle = NULL;
374
375  pthread_mutex_destroy(&p_session->lock);
376  pthread_cond_destroy(&p_session->cond);
377
378  if (NULL != p_session->meta_enc_key) {
379    free(p_session->meta_enc_key);
380    p_session->meta_enc_key = NULL;
381  }
382
383  my_obj->num_sessions--;
384
385  // Destroy next session
386  if (p_session->next_session) {
387    mm_jpeg_session_destroy(p_session->next_session);
388  }
389
390  CDBG_HIGH("%s:%d] Session destroy successful. X", __func__, __LINE__);
391}
392
393
394
395/** mm_jpeg_session_config_main_buffer_offset:
396 *
397 *  Arguments:
398 *    @p_session: job session
399 *
400 *  Return:
401 *       OMX error values
402 *
403 *  Description:
404 *       Configure the buffer offsets
405 *
406 **/
407OMX_ERRORTYPE mm_jpeg_session_config_main_buffer_offset(
408  mm_jpeg_job_session_t* p_session)
409{
410  OMX_ERRORTYPE rc = 0;
411  OMX_INDEXTYPE buffer_index;
412  QOMX_YUV_FRAME_INFO frame_info;
413  size_t totalSize = 0;
414  mm_jpeg_encode_params_t *p_params = &p_session->params;
415
416  mm_jpeg_buf_t *p_src_buf =
417    &p_params->src_main_buf[0];
418
419  memset(&frame_info, 0x0, sizeof(QOMX_YUV_FRAME_INFO));
420
421  frame_info.cbcrStartOffset[0] = p_src_buf->offset.mp[0].len;
422  frame_info.cbcrStartOffset[1] = p_src_buf->offset.mp[1].len;
423  frame_info.yOffset = p_src_buf->offset.mp[0].offset;
424  frame_info.cbcrOffset[0] = p_src_buf->offset.mp[1].offset;
425  frame_info.cbcrOffset[1] = p_src_buf->offset.mp[2].offset;
426  totalSize = p_src_buf->buf_size;
427
428  rc = OMX_GetExtensionIndex(p_session->omx_handle,
429    QOMX_IMAGE_EXT_BUFFER_OFFSET_NAME, &buffer_index);
430  if (rc != OMX_ErrorNone) {
431    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
432    return rc;
433  }
434
435  CDBG_HIGH("%s:%d] yOffset = %d, cbcrOffset = (%d %d), totalSize = %zd,"
436    "cbcrStartOffset = (%d %d)", __func__, __LINE__,
437    (int)frame_info.yOffset,
438    (int)frame_info.cbcrOffset[0],
439    (int)frame_info.cbcrOffset[1],
440    totalSize,
441    (int)frame_info.cbcrStartOffset[0],
442    (int)frame_info.cbcrStartOffset[1]);
443
444  rc = OMX_SetParameter(p_session->omx_handle, buffer_index, &frame_info);
445  if (rc != OMX_ErrorNone) {
446    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
447    return rc;
448  }
449  return rc;
450}
451
452/** mm_jpeg_encoding_mode:
453 *
454 *  Arguments:
455 *    @p_session: job session
456 *
457 *  Return:
458 *       OMX error values
459 *
460 *  Description:
461 *       Configure the serial or parallel encoding
462 *       mode
463 *
464 **/
465OMX_ERRORTYPE mm_jpeg_encoding_mode(
466  mm_jpeg_job_session_t* p_session)
467{
468  OMX_ERRORTYPE rc = 0;
469  OMX_INDEXTYPE indextype;
470  QOMX_ENCODING_MODE encoding_mode;
471
472  rc = OMX_GetExtensionIndex(p_session->omx_handle,
473    QOMX_IMAGE_EXT_ENCODING_MODE_NAME, &indextype);
474  if (rc != OMX_ErrorNone) {
475    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
476    return rc;
477  }
478
479  if (ENCODING_MODE_PARALLEL) {
480    encoding_mode = OMX_Parallel_Encoding;
481  } else {
482    encoding_mode = OMX_Serial_Encoding;
483  }
484  CDBG("%s:%d] encoding mode = %d ", __func__, __LINE__,
485    (int)encoding_mode);
486  rc = OMX_SetParameter(p_session->omx_handle, indextype, &encoding_mode);
487  if (rc != OMX_ErrorNone) {
488    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
489    return rc;
490  }
491  return rc;
492}
493
494/** mm_jpeg_get_speed:
495 *
496 *  Arguments:
497 *    @p_session: job session
498 *
499 *  Return:
500 *       ops speed type for jpeg
501 *
502 *  Description:
503 *      Configure normal or high speed jpeg
504 *
505 **/
506QOMX_JPEG_SPEED_MODE mm_jpeg_get_speed(
507  mm_jpeg_job_session_t* p_session)
508{
509  mm_jpeg_encode_params_t *p_params = &p_session->params;
510  cam_dimension_t *p_dim = &p_params->main_dim.src_dim;
511  if (p_params->burst_mode ||
512    (MM_JPEG_MIN_NOM_RESOLUTION < (p_dim->width * p_dim->height))) {
513    return QOMX_JPEG_SPEED_MODE_HIGH;
514  }
515  return QOMX_JPEG_SPEED_MODE_NORMAL;
516}
517
518/** mm_jpeg_speed_mode:
519 *
520 *  Arguments:
521 *    @p_session: job session
522 *
523 *  Return:
524 *       OMX error values
525 *
526 *  Description:
527 *      Configure normal or high speed jpeg
528 *
529 **/
530OMX_ERRORTYPE mm_jpeg_speed_mode(
531  mm_jpeg_job_session_t* p_session)
532{
533  OMX_ERRORTYPE rc = 0;
534  OMX_INDEXTYPE indextype;
535  QOMX_JPEG_SPEED jpeg_speed;
536
537  rc = OMX_GetExtensionIndex(p_session->omx_handle,
538    QOMX_IMAGE_EXT_JPEG_SPEED_NAME, &indextype);
539  if (rc != OMX_ErrorNone) {
540    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
541    return rc;
542  }
543
544  jpeg_speed.speedMode = mm_jpeg_get_speed(p_session);
545  CDBG_HIGH("%s:%d] speed %d", __func__, __LINE__, jpeg_speed.speedMode);
546
547  rc = OMX_SetParameter(p_session->omx_handle, indextype, &jpeg_speed);
548  if (rc != OMX_ErrorNone) {
549    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
550    return rc;
551  }
552  return rc;
553}
554
555
556/** mm_jpeg_mem_ops:
557 *
558 *  Arguments:
559 *    @p_session: job session
560 *
561 *  Return:
562 *       OMX error values
563 *
564 *  Description:
565 *       Configure the serial or parallel encoding
566 *       mode
567 *
568 **/
569OMX_ERRORTYPE mm_jpeg_mem_ops(
570  mm_jpeg_job_session_t* p_session)
571{
572  OMX_ERRORTYPE rc = 0;
573  OMX_INDEXTYPE indextype;
574  QOMX_MEM_OPS mem_ops;
575  mm_jpeg_encode_params_t *p_params = &p_session->params;
576
577  mem_ops.get_memory = p_params->get_memory;
578
579  rc = OMX_GetExtensionIndex(p_session->omx_handle,
580    QOMX_IMAGE_EXT_MEM_OPS_NAME, &indextype);
581  if (rc != OMX_ErrorNone) {
582    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
583    return rc;
584  }
585
586  rc = OMX_SetParameter(p_session->omx_handle, indextype, &mem_ops);
587  if (rc != OMX_ErrorNone) {
588    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
589    return rc;
590  }
591  return rc;
592}
593
594/** mm_jpeg_metadata:
595 *
596 *  Arguments:
597 *    @p_session: job session
598 *
599 *  Return:
600 *       OMX error values
601 *
602 *  Description:
603 *       Pass meta data
604 *
605 **/
606OMX_ERRORTYPE mm_jpeg_metadata(
607  mm_jpeg_job_session_t* p_session)
608{
609  OMX_ERRORTYPE rc = OMX_ErrorNone;
610  OMX_INDEXTYPE indexType;
611  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
612  QOMX_METADATA lMeta;
613
614  rc = OMX_GetExtensionIndex(p_session->omx_handle,
615      QOMX_IMAGE_EXT_METADATA_NAME, &indexType);
616
617  if (rc != OMX_ErrorNone) {
618    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
619    return rc;
620  }
621
622  lMeta.metadata = (OMX_U8 *)p_jobparams->p_metadata;
623  lMeta.metaPayloadSize = sizeof(*p_jobparams->p_metadata);
624  lMeta.mobicat_mask = p_jobparams->mobicat_mask;
625
626  rc = OMX_SetConfig(p_session->omx_handle, indexType, &lMeta);
627  if (rc != OMX_ErrorNone) {
628    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
629    return rc;
630  }
631  return OMX_ErrorNone;
632}
633
634/** mm_jpeg_meta_enc_key:
635 *
636 *  Arguments:
637 *    @p_session: job session
638 *
639 *  Return:
640 *       OMX error values
641 *
642 *  Description:
643 *       Pass metadata encrypt key
644 *
645 **/
646OMX_ERRORTYPE mm_jpeg_meta_enc_key(
647  mm_jpeg_job_session_t* p_session)
648{
649  OMX_ERRORTYPE rc = OMX_ErrorNone;
650  OMX_INDEXTYPE indexType;
651  QOMX_META_ENC_KEY lKey;
652
653  lKey.metaKey = p_session->meta_enc_key;
654  lKey.keyLen = p_session->meta_enc_keylen;
655
656  if ((!lKey.metaKey) || (!lKey.keyLen)){
657    CDBG_ERROR("%s:%d] Key is invalid", __func__, __LINE__);
658    return OMX_ErrorNone;
659  }
660
661  rc = OMX_GetExtensionIndex(p_session->omx_handle,
662      QOMX_IMAGE_EXT_META_ENC_KEY_NAME, &indexType);
663
664  if (rc != OMX_ErrorNone) {
665    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
666    return rc;
667  }
668
669  rc = OMX_SetConfig(p_session->omx_handle, indexType, &lKey);
670  if (rc != OMX_ErrorNone) {
671    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
672    return rc;
673  }
674  return OMX_ErrorNone;
675}
676
677/** map_jpeg_format:
678 *
679 *  Arguments:
680 *    @color_fmt: color format
681 *
682 *  Return:
683 *       OMX color format
684 *
685 *  Description:
686 *       Map mmjpeg color format to OMX color format
687 *
688 **/
689int map_jpeg_format(mm_jpeg_color_format color_fmt)
690{
691  switch (color_fmt) {
692  case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2:
693    return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar;
694  case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2:
695    return (int)OMX_COLOR_FormatYUV420SemiPlanar;
696  case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1:
697    return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar;
698  case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1:
699    return (int)OMX_COLOR_FormatYUV422SemiPlanar;
700  case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V2:
701    return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar_h1v2;
702  case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V2:
703    return (int)OMX_QCOM_IMG_COLOR_FormatYUV422SemiPlanar_h1v2;
704  case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V1:
705    return (int)OMX_QCOM_IMG_COLOR_FormatYVU444SemiPlanar;
706  case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V1:
707    return (int)OMX_QCOM_IMG_COLOR_FormatYUV444SemiPlanar;
708  case MM_JPEG_COLOR_FORMAT_MONOCHROME:
709     return (int)OMX_COLOR_FormatMonochrome;
710  default:
711    CDBG_ERROR("%s:%d] invalid format %d", __func__, __LINE__, color_fmt);
712    return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar;
713  }
714}
715
716/** mm_jpeg_session_config_port:
717 *
718 *  Arguments:
719 *    @p_session: job session
720 *
721 *  Return:
722 *       OMX error values
723 *
724 *  Description:
725 *       Configure OMX ports
726 *
727 **/
728OMX_ERRORTYPE mm_jpeg_session_config_ports(mm_jpeg_job_session_t* p_session)
729{
730  OMX_ERRORTYPE ret = OMX_ErrorNone;
731  mm_jpeg_encode_params_t *p_params = &p_session->params;
732  OMX_CONFIG_ROTATIONTYPE rotate;
733
734  mm_jpeg_buf_t *p_src_buf =
735    &p_params->src_main_buf[0];
736
737  p_session->inputPort.nPortIndex = 0;
738  p_session->outputPort.nPortIndex = 1;
739  p_session->inputTmbPort.nPortIndex = 2;
740
741  ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
742    &p_session->inputPort);
743  if (ret) {
744    CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
745    return ret;
746  }
747
748  ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
749    &p_session->inputTmbPort);
750  if (ret) {
751    CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
752    return ret;
753  }
754
755  ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
756    &p_session->outputPort);
757  if (ret) {
758    CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
759    return ret;
760  }
761
762  p_session->inputPort.format.image.nFrameWidth =
763    (OMX_U32)p_params->main_dim.src_dim.width;
764  p_session->inputPort.format.image.nFrameHeight =
765    (OMX_U32)p_params->main_dim.src_dim.height;
766  p_session->inputPort.format.image.nStride =
767    p_src_buf->offset.mp[0].stride;
768  p_session->inputPort.format.image.nSliceHeight =
769    (OMX_U32)p_src_buf->offset.mp[0].scanline;
770  p_session->inputPort.format.image.eColorFormat =
771    map_jpeg_format(p_params->color_format);
772  p_session->inputPort.nBufferSize =
773    p_params->src_main_buf[0/*p_jobparams->src_index*/].buf_size;
774  p_session->inputPort.nBufferCountActual = (OMX_U32)p_params->num_src_bufs;
775  ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
776    &p_session->inputPort);
777  if (ret) {
778    CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
779    return ret;
780  }
781
782  if (p_session->params.encode_thumbnail) {
783    mm_jpeg_buf_t *p_tmb_buf =
784      &p_params->src_thumb_buf[0];
785    p_session->inputTmbPort.format.image.nFrameWidth =
786      (OMX_U32)p_params->thumb_dim.src_dim.width;
787    p_session->inputTmbPort.format.image.nFrameHeight =
788      (OMX_U32)p_params->thumb_dim.src_dim.height;
789    p_session->inputTmbPort.format.image.nStride =
790      p_tmb_buf->offset.mp[0].stride;
791    p_session->inputTmbPort.format.image.nSliceHeight =
792      (OMX_U32)p_tmb_buf->offset.mp[0].scanline;
793    p_session->inputTmbPort.format.image.eColorFormat =
794      map_jpeg_format(p_params->thumb_color_format);
795    p_session->inputTmbPort.nBufferSize =
796      p_params->src_thumb_buf[0].buf_size;
797    p_session->inputTmbPort.nBufferCountActual = (OMX_U32)p_params->num_tmb_bufs;
798
799    ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
800      &p_session->inputTmbPort);
801
802    if (ret) {
803      CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
804      return ret;
805    }
806
807    // Enable thumbnail port
808    ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortEnable,
809        p_session->inputTmbPort.nPortIndex, NULL);
810
811    if (ret) {
812      CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
813      return ret;
814    }
815  } else {
816    // Disable thumbnail port
817    ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortDisable,
818        p_session->inputTmbPort.nPortIndex, NULL);
819
820    if (ret) {
821      CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
822      return ret;
823    }
824  }
825
826  p_session->outputPort.nBufferSize =
827    p_params->dest_buf[0].buf_size;
828  p_session->outputPort.nBufferCountActual = (OMX_U32)p_params->num_dst_bufs;
829  ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
830    &p_session->outputPort);
831  if (ret) {
832    CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
833    return ret;
834  }
835
836  /* set rotation */
837  memset(&rotate, 0, sizeof(rotate));
838  rotate.nPortIndex = 1;
839  rotate.nRotation = (OMX_S32)p_params->rotation;
840  ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonRotate,
841      &rotate);
842  if (OMX_ErrorNone != ret) {
843    CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
844    return ret;
845  }
846  CDBG("%s:%d] Set rotation to %d at port_idx = %d", __func__, __LINE__,
847      (int)p_params->rotation, (int)rotate.nPortIndex);
848
849  return ret;
850}
851
852/** mm_jpeg_get_thumbnail_crop
853 *
854 *  Arguments:
855 *    @p_thumb_dim: thumbnail dimension
856 *    @p_main_dim: main image dimension
857 *    @crop_width : flag indicating if width needs to be cropped
858 *
859 *  Return:
860 *       OMX error values
861 *
862 *  Description:
863 *    If the main image and thumbnail ascpect ratios are differnt,
864 *    re-calculate the thumbnail crop info to prevent distortion
865 *
866 */
867OMX_ERRORTYPE mm_jpeg_get_thumbnail_crop(mm_jpeg_dim_t *p_thumb_dim,
868  mm_jpeg_dim_t *p_main_dim, uint8_t crop_width) {
869  OMX_ERRORTYPE ret = OMX_ErrorNone;
870  int cropped_width = 0, cropped_height = 0;
871
872  if (crop_width) {
873   //Keep height constant
874   cropped_height = p_thumb_dim->src_dim.height;
875   cropped_width = floor((cropped_height * p_thumb_dim->dst_dim.width) /
876      p_thumb_dim->dst_dim.height);
877  } else {
878    //Keep width constant
879    cropped_width = p_thumb_dim->src_dim.width;
880    cropped_height = floor((cropped_width * p_thumb_dim->dst_dim.height) /
881      p_thumb_dim->dst_dim.width);
882  }
883  p_thumb_dim->crop.left = floor(p_thumb_dim->src_dim.width - cropped_width) / 2;
884  p_thumb_dim->crop.top = floor(p_thumb_dim->src_dim.height - cropped_height) / 2;
885  p_thumb_dim->crop.width = cropped_width;
886  p_thumb_dim->crop.height = cropped_height;
887
888  CDBG_HIGH("%s %d New thumbnail crop: left %d, top %d, crop width %d, crop height %d",
889    __func__, __LINE__, p_thumb_dim->crop.left, p_thumb_dim->crop.top,
890    p_thumb_dim->crop.width, p_thumb_dim->crop.height);
891
892  return ret;
893}
894
895/** mm_jpeg_omx_config_thumbnail:
896 *
897 *  Arguments:
898 *    @p_session: job session
899 *
900 *  Return:
901 *       OMX error values
902 *
903 *  Description:
904 *       Configure OMX ports
905 *
906 **/
907OMX_ERRORTYPE mm_jpeg_session_config_thumbnail(mm_jpeg_job_session_t* p_session)
908{
909  OMX_ERRORTYPE ret = OMX_ErrorNone;
910  QOMX_THUMBNAIL_INFO thumbnail_info;
911  OMX_INDEXTYPE thumb_indextype;
912  mm_jpeg_encode_params_t *p_params = &p_session->params;
913  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
914  mm_jpeg_dim_t *p_thumb_dim = &p_jobparams->thumb_dim;
915  mm_jpeg_dim_t *p_main_dim = &p_jobparams->main_dim;
916  QOMX_YUV_FRAME_INFO *p_frame_info = &thumbnail_info.tmbOffset;
917  mm_jpeg_buf_t *p_tmb_buf = &p_params->src_thumb_buf[p_jobparams->thumb_index];
918
919  CDBG_HIGH("%s:%d] encode_thumbnail %u", __func__, __LINE__,
920    p_params->encode_thumbnail);
921  if (OMX_FALSE == p_params->encode_thumbnail) {
922    return ret;
923  }
924
925  if ((p_thumb_dim->dst_dim.width == 0) || (p_thumb_dim->dst_dim.height == 0)) {
926    CDBG_ERROR("%s:%d] Error invalid output dim for thumbnail",
927      __func__, __LINE__);
928    return OMX_ErrorBadParameter;
929  }
930
931  if ((p_thumb_dim->src_dim.width == 0) || (p_thumb_dim->src_dim.height == 0)) {
932    CDBG_ERROR("%s:%d] Error invalid input dim for thumbnail",
933      __func__, __LINE__);
934    return OMX_ErrorBadParameter;
935  }
936
937  if ((p_thumb_dim->crop.width == 0) || (p_thumb_dim->crop.height == 0)) {
938    p_thumb_dim->crop.width = p_thumb_dim->src_dim.width;
939    p_thumb_dim->crop.height = p_thumb_dim->src_dim.height;
940  }
941
942  /* check crop boundary */
943  if ((p_thumb_dim->crop.width + p_thumb_dim->crop.left > p_thumb_dim->src_dim.width) ||
944    (p_thumb_dim->crop.height + p_thumb_dim->crop.top > p_thumb_dim->src_dim.height)) {
945    CDBG_ERROR("%s:%d] invalid crop boundary (%d, %d) offset (%d, %d) out of (%d, %d)",
946      __func__, __LINE__,
947      p_thumb_dim->crop.width,
948      p_thumb_dim->crop.height,
949      p_thumb_dim->crop.left,
950      p_thumb_dim->crop.top,
951      p_thumb_dim->src_dim.width,
952      p_thumb_dim->src_dim.height);
953    return OMX_ErrorBadParameter;
954  }
955
956  memset(&thumbnail_info, 0x0, sizeof(QOMX_THUMBNAIL_INFO));
957  ret = OMX_GetExtensionIndex(p_session->omx_handle,
958    QOMX_IMAGE_EXT_THUMBNAIL_NAME,
959    &thumb_indextype);
960  if (ret) {
961    CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
962    return ret;
963  }
964
965  /* fill thumbnail info */
966  thumbnail_info.scaling_enabled = 1;
967  thumbnail_info.input_width = (OMX_U32)p_thumb_dim->src_dim.width;
968  thumbnail_info.input_height = (OMX_U32)p_thumb_dim->src_dim.height;
969  thumbnail_info.rotation = (OMX_U32)p_params->thumb_rotation;
970  thumbnail_info.quality = (OMX_U32)p_params->thumb_quality;
971  thumbnail_info.output_width = (OMX_U32)p_thumb_dim->dst_dim.width;
972  thumbnail_info.output_height = (OMX_U32)p_thumb_dim->dst_dim.height;
973
974  if (p_session->thumb_from_main) {
975    if ((p_session->params.thumb_rotation == 90 ||
976      p_session->params.thumb_rotation == 270) &&
977      (p_session->params.rotation == 0 ||
978      p_session->params.rotation == 180)) {
979
980      thumbnail_info.output_width = (OMX_U32)p_thumb_dim->dst_dim.height;
981      thumbnail_info.output_height = (OMX_U32)p_thumb_dim->dst_dim.width;
982      thumbnail_info.rotation = p_session->params.rotation;
983    }
984  } else if ((p_thumb_dim->dst_dim.width > p_thumb_dim->src_dim.width) ||
985    (p_thumb_dim->dst_dim.height > p_thumb_dim->src_dim.height)) {
986    CDBG_ERROR("%s:%d] Incorrect thumbnail dim %dx%d resetting to %dx%d",
987      __func__, __LINE__, p_thumb_dim->dst_dim.width,
988      p_thumb_dim->dst_dim.height, p_thumb_dim->src_dim.width,
989      p_thumb_dim->src_dim.height);
990    thumbnail_info.output_width = (OMX_U32)p_thumb_dim->src_dim.width;
991    thumbnail_info.output_height = (OMX_U32)p_thumb_dim->src_dim.height;
992  }
993
994  //If the main image and thumbnail aspect ratio are different, reset the
995  // thumbnail crop info to avoid distortion
996  double main_aspect_ratio = (double)p_main_dim->dst_dim.width /
997    (double)p_main_dim->dst_dim.height;
998  double thumb_aspect_ratio = (double)thumbnail_info.output_width /
999    (double)thumbnail_info.output_height;
1000
1001  if ((thumb_aspect_ratio - main_aspect_ratio) > ASPECT_TOLERANCE) {
1002    mm_jpeg_get_thumbnail_crop(p_thumb_dim, p_main_dim, 0);
1003  } else if((main_aspect_ratio - thumb_aspect_ratio) > ASPECT_TOLERANCE){
1004    mm_jpeg_get_thumbnail_crop(p_thumb_dim, p_main_dim, 1);
1005  }
1006
1007  //Fill thumbnail crop info
1008  thumbnail_info.crop_info.nWidth = (OMX_U32)p_thumb_dim->crop.width;
1009  thumbnail_info.crop_info.nHeight = (OMX_U32)p_thumb_dim->crop.height;
1010  thumbnail_info.crop_info.nLeft = p_thumb_dim->crop.left;
1011  thumbnail_info.crop_info.nTop = p_thumb_dim->crop.top;
1012
1013  //If main image cropping/scaling is enabled, thumb FOV should be within
1014  //main image FOV
1015  if ((p_main_dim->crop.width != p_main_dim->src_dim.width) ||
1016    (p_main_dim->crop.height != p_main_dim->src_dim.height)) {
1017    if ((p_thumb_dim->crop.left < p_main_dim->crop.left) ||
1018      ((p_thumb_dim->crop.left + p_thumb_dim->crop.width) >
1019      (p_main_dim->crop.left + p_main_dim->crop.width)) ||
1020      (p_thumb_dim->crop.top < p_main_dim->crop.top) ||
1021      ((p_thumb_dim->crop.top + p_thumb_dim->crop.height) >
1022      (p_main_dim->crop.top + p_main_dim->crop.height))) {
1023       //Reset the FOV for the thumbnail
1024       CDBG_HIGH("%s:%d] Resetting the thumbnail FOV wrt main image",
1025         __func__, __LINE__);
1026       thumbnail_info.crop_info.nLeft = p_main_dim->crop.left;
1027       thumbnail_info.crop_info.nTop = p_main_dim->crop.height;
1028       if ((p_thumb_dim->crop.width > p_main_dim->crop.width) ||
1029         (p_thumb_dim->crop.height > p_main_dim->crop.height)) {
1030         thumbnail_info.crop_info.nWidth = p_main_dim->crop.width;
1031         thumbnail_info.crop_info.nHeight = p_main_dim->crop.height;
1032       }
1033     }
1034  }
1035
1036  memset(p_frame_info, 0x0, sizeof(*p_frame_info));
1037
1038  p_frame_info->cbcrStartOffset[0] = p_tmb_buf->offset.mp[0].len;
1039  p_frame_info->cbcrStartOffset[1] = p_tmb_buf->offset.mp[1].len;
1040  p_frame_info->yOffset = p_tmb_buf->offset.mp[0].offset;
1041  p_frame_info->cbcrOffset[0] = p_tmb_buf->offset.mp[1].offset;
1042  p_frame_info->cbcrOffset[1] = p_tmb_buf->offset.mp[2].offset;
1043
1044  ret = OMX_SetConfig(p_session->omx_handle, thumb_indextype,
1045    &thumbnail_info);
1046  if (ret) {
1047    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1048    return ret;
1049  }
1050
1051  return ret;
1052}
1053
1054/** mm_jpeg_session_config_main_crop:
1055 *
1056 *  Arguments:
1057 *    @p_session: job session
1058 *
1059 *  Return:
1060 *       OMX error values
1061 *
1062 *  Description:
1063 *       Configure main image crop
1064 *
1065 **/
1066OMX_ERRORTYPE mm_jpeg_session_config_main_crop(mm_jpeg_job_session_t *p_session)
1067{
1068  OMX_CONFIG_RECTTYPE rect_type_in, rect_type_out;
1069  OMX_ERRORTYPE ret = OMX_ErrorNone;
1070  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
1071  mm_jpeg_dim_t *dim = &p_jobparams->main_dim;
1072
1073  if ((dim->crop.width == 0) || (dim->crop.height == 0)) {
1074    dim->crop.width = dim->src_dim.width;
1075    dim->crop.height = dim->src_dim.height;
1076  }
1077  /* error check first */
1078  if ((dim->crop.width + dim->crop.left > dim->src_dim.width) ||
1079    (dim->crop.height + dim->crop.top > dim->src_dim.height)) {
1080    CDBG_ERROR("%s:%d] invalid crop boundary (%d, %d) out of (%d, %d)",
1081      __func__, __LINE__,
1082      dim->crop.width + dim->crop.left,
1083      dim->crop.height + dim->crop.top,
1084      dim->src_dim.width,
1085      dim->src_dim.height);
1086    return OMX_ErrorBadParameter;
1087  }
1088
1089  memset(&rect_type_in, 0, sizeof(rect_type_in));
1090  memset(&rect_type_out, 0, sizeof(rect_type_out));
1091  rect_type_in.nPortIndex = 0;
1092  rect_type_out.nPortIndex = 0;
1093
1094  if ((dim->src_dim.width != dim->crop.width) ||
1095    (dim->src_dim.height != dim->crop.height) ||
1096    (dim->src_dim.width != dim->dst_dim.width) ||
1097    (dim->src_dim.height != dim->dst_dim.height)) {
1098    /* Scaler information */
1099    rect_type_in.nWidth = CEILING2(dim->crop.width);
1100    rect_type_in.nHeight = CEILING2(dim->crop.height);
1101    rect_type_in.nLeft = dim->crop.left;
1102    rect_type_in.nTop = dim->crop.top;
1103
1104    if (dim->dst_dim.width && dim->dst_dim.height) {
1105      rect_type_out.nWidth = (OMX_U32)dim->dst_dim.width;
1106      rect_type_out.nHeight = (OMX_U32)dim->dst_dim.height;
1107    }
1108  }
1109
1110  ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonInputCrop,
1111    &rect_type_in);
1112  if (OMX_ErrorNone != ret) {
1113    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1114    return ret;
1115  }
1116
1117  CDBG_HIGH("%s:%d] OMX_IndexConfigCommonInputCrop w = %d, h = %d, l = %d, t = %d,"
1118    " port_idx = %d", __func__, __LINE__,
1119    (int)rect_type_in.nWidth, (int)rect_type_in.nHeight,
1120    (int)rect_type_in.nLeft, (int)rect_type_in.nTop,
1121    (int)rect_type_in.nPortIndex);
1122
1123  ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonOutputCrop,
1124    &rect_type_out);
1125  if (OMX_ErrorNone != ret) {
1126    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1127    return ret;
1128  }
1129  CDBG("%s:%d] OMX_IndexConfigCommonOutputCrop w = %d, h = %d,"
1130    " port_idx = %d", __func__, __LINE__,
1131    (int)rect_type_out.nWidth, (int)rect_type_out.nHeight,
1132    (int)rect_type_out.nPortIndex);
1133
1134  return ret;
1135}
1136
1137/** mm_jpeg_session_config_main:
1138 *
1139 *  Arguments:
1140 *    @p_session: job session
1141 *
1142 *  Return:
1143 *       OMX error values
1144 *
1145 *  Description:
1146 *       Configure main image
1147 *
1148 **/
1149OMX_ERRORTYPE mm_jpeg_session_config_main(mm_jpeg_job_session_t *p_session)
1150{
1151  OMX_ERRORTYPE rc = OMX_ErrorNone;
1152
1153  /* config port */
1154  CDBG_HIGH("%s:%d] config port", __func__, __LINE__);
1155  rc = mm_jpeg_session_config_ports(p_session);
1156  if (OMX_ErrorNone != rc) {
1157    CDBG_ERROR("%s: config port failed", __func__);
1158    return rc;
1159  }
1160
1161  /* config buffer offset */
1162  CDBG("%s:%d] config main buf offset", __func__, __LINE__);
1163  rc = mm_jpeg_session_config_main_buffer_offset(p_session);
1164  if (OMX_ErrorNone != rc) {
1165    CDBG_ERROR("%s: config buffer offset failed", __func__);
1166    return rc;
1167  }
1168
1169  /* set the encoding mode */
1170  rc = mm_jpeg_encoding_mode(p_session);
1171  if (OMX_ErrorNone != rc) {
1172    CDBG_ERROR("%s: config encoding mode failed", __func__);
1173    return rc;
1174  }
1175
1176  /* set the metadata encrypt key */
1177  rc = mm_jpeg_meta_enc_key(p_session);
1178  if (OMX_ErrorNone != rc) {
1179    CDBG_ERROR("%s: config session failed", __func__);
1180    return rc;
1181  }
1182
1183  /* set the mem ops */
1184  rc = mm_jpeg_mem_ops(p_session);
1185  if (OMX_ErrorNone != rc) {
1186    CDBG_ERROR("%s: config mem ops failed", __func__);
1187    return rc;
1188  }
1189  /* set the jpeg speed mode */
1190  rc = mm_jpeg_speed_mode(p_session);
1191  if (OMX_ErrorNone != rc) {
1192    CDBG_ERROR("%s: config speed mode failed", __func__);
1193    return rc;
1194  }
1195
1196  return rc;
1197}
1198
1199/** mm_jpeg_session_config_common:
1200 *
1201 *  Arguments:
1202 *    @p_session: job session
1203 *
1204 *  Return:
1205 *       OMX error values
1206 *
1207 *  Description:
1208 *       Configure common parameters
1209 *
1210 **/
1211OMX_ERRORTYPE mm_jpeg_session_config_common(mm_jpeg_job_session_t *p_session)
1212{
1213  OMX_ERRORTYPE rc = OMX_ErrorNone;
1214  OMX_INDEXTYPE exif_idx;
1215  OMX_CONFIG_ROTATIONTYPE rotate;
1216  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
1217  QOMX_EXIF_INFO exif_info;
1218
1219  /* set rotation */
1220  memset(&rotate, 0, sizeof(rotate));
1221  rotate.nPortIndex = 1;
1222  rotate.nRotation = (OMX_S32)p_jobparams->rotation;
1223  rc = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonRotate,
1224    &rotate);
1225  if (OMX_ErrorNone != rc) {
1226      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
1227      return rc;
1228  }
1229  CDBG("%s:%d] Set rotation to %d at port_idx = %d", __func__, __LINE__,
1230    (int)p_jobparams->rotation, (int)rotate.nPortIndex);
1231
1232  /* Set Exif data*/
1233  memset(&p_session->exif_info_local[0], 0, sizeof(p_session->exif_info_local));
1234  rc = OMX_GetExtensionIndex(p_session->omx_handle, QOMX_IMAGE_EXT_EXIF_NAME,
1235    &exif_idx);
1236  if (OMX_ErrorNone != rc) {
1237    CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
1238    return rc;
1239  }
1240
1241  CDBG("%s:%d] Num of exif entries passed from HAL: %d", __func__, __LINE__,
1242      (int)p_jobparams->exif_info.numOfEntries);
1243  if (p_jobparams->exif_info.numOfEntries > 0) {
1244    rc = OMX_SetConfig(p_session->omx_handle, exif_idx,
1245        &p_jobparams->exif_info);
1246    if (OMX_ErrorNone != rc) {
1247      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
1248      return rc;
1249    }
1250  }
1251  /*parse aditional exif data from the metadata*/
1252  exif_info.numOfEntries = 0;
1253  exif_info.exif_data = &p_session->exif_info_local[0];
1254  process_meta_data(p_jobparams->p_metadata, &exif_info,
1255    &p_jobparams->cam_exif_params, p_jobparams->hal_version);
1256  /* After Parse metadata */
1257  p_session->exif_count_local = (int)exif_info.numOfEntries;
1258
1259  if (exif_info.numOfEntries > 0) {
1260    /* set exif tags */
1261    CDBG("%s:%d] exif tags from metadata count %d", __func__, __LINE__,
1262      (int)exif_info.numOfEntries);
1263
1264    rc = OMX_SetConfig(p_session->omx_handle, exif_idx,
1265      &exif_info);
1266    if (OMX_ErrorNone != rc) {
1267      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
1268      return rc;
1269    }
1270  }
1271
1272  return rc;
1273}
1274
1275
1276
1277
1278/** mm_jpeg_session_abort:
1279 *
1280 *  Arguments:
1281 *    @p_session: jpeg session
1282 *
1283 *  Return:
1284 *       OMX_BOOL
1285 *
1286 *  Description:
1287 *       Abort ongoing job
1288 *
1289 **/
1290OMX_BOOL mm_jpeg_session_abort(mm_jpeg_job_session_t *p_session)
1291{
1292  OMX_ERRORTYPE ret = OMX_ErrorNone;
1293  int rc = 0;
1294
1295  CDBG("%s:%d] E", __func__, __LINE__);
1296  pthread_mutex_lock(&p_session->lock);
1297  if (MM_JPEG_ABORT_NONE != p_session->abort_state) {
1298    pthread_mutex_unlock(&p_session->lock);
1299    CDBG_HIGH("%s:%d] **** ALREADY ABORTED", __func__, __LINE__);
1300    return 0;
1301  }
1302  p_session->abort_state = MM_JPEG_ABORT_INIT;
1303  if (OMX_TRUE == p_session->encoding) {
1304    p_session->state_change_pending = OMX_TRUE;
1305
1306    CDBG_HIGH("%s:%d] **** ABORTING", __func__, __LINE__);
1307    pthread_mutex_unlock(&p_session->lock);
1308
1309    ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet,
1310    OMX_StateIdle, NULL);
1311
1312    if (ret != OMX_ErrorNone) {
1313      CDBG_ERROR("%s:%d] OMX_SendCommand returned error %d", __func__, __LINE__, ret);
1314      return 1;
1315    }
1316    rc = mm_jpegenc_destroy_job(p_session);
1317    if (rc != 0) {
1318      CDBG_ERROR("%s:%d] Destroy job returned error %d", __func__, __LINE__, rc);
1319    }
1320
1321    pthread_mutex_lock(&p_session->lock);
1322    if (MM_JPEG_ABORT_INIT == p_session->abort_state) {
1323      CDBG("%s:%d] before wait", __func__, __LINE__);
1324      pthread_cond_wait(&p_session->cond, &p_session->lock);
1325    }
1326    CDBG("%s:%d] after wait", __func__, __LINE__);
1327  }
1328  p_session->abort_state = MM_JPEG_ABORT_DONE;
1329  pthread_mutex_unlock(&p_session->lock);
1330
1331
1332  // Abort next session
1333  if (p_session->next_session) {
1334    mm_jpeg_session_abort(p_session->next_session);
1335  }
1336
1337  CDBG("%s:%d] X", __func__, __LINE__);
1338  return 0;
1339}
1340
1341
1342/** mm_jpeg_configure_params
1343 *
1344 *  Arguments:
1345 *    @p_session: encode session
1346 *
1347 *  Return:
1348 *       none
1349 *
1350 *  Description:
1351 *       Configure the job specific params
1352 *
1353 **/
1354static OMX_ERRORTYPE mm_jpeg_configure_job_params(
1355  mm_jpeg_job_session_t *p_session)
1356{
1357  OMX_ERRORTYPE ret = OMX_ErrorNone;
1358  OMX_IMAGE_PARAM_QFACTORTYPE q_factor;
1359  QOMX_WORK_BUFFER work_buffer;
1360  OMX_INDEXTYPE work_buffer_index;
1361  mm_jpeg_encode_params_t *p_params = &p_session->params;
1362  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
1363  int i;
1364
1365  /* common config */
1366  ret = mm_jpeg_session_config_common(p_session);
1367  if (OMX_ErrorNone != ret) {
1368    CDBG_ERROR("%s:%d] config common failed", __func__, __LINE__);
1369
1370  }
1371
1372  /* config Main Image crop */
1373  CDBG("%s:%d] config main crop", __func__, __LINE__);
1374  ret = mm_jpeg_session_config_main_crop(p_session);
1375  if (OMX_ErrorNone != ret) {
1376    CDBG_ERROR("%s: config crop failed", __func__);
1377    return ret;
1378  }
1379
1380  /* set quality */
1381  memset(&q_factor, 0, sizeof(q_factor));
1382  q_factor.nPortIndex = 0;
1383  q_factor.nQFactor = p_params->quality;
1384  ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexParamQFactor, &q_factor);
1385  CDBG("%s:%d] config QFactor: %d", __func__, __LINE__, (int)q_factor.nQFactor);
1386  if (OMX_ErrorNone != ret) {
1387    CDBG_ERROR("%s:%d] Error setting Q factor %d", __func__, __LINE__, ret);
1388    return ret;
1389  }
1390
1391  /* config thumbnail */
1392  ret = mm_jpeg_session_config_thumbnail(p_session);
1393  if (OMX_ErrorNone != ret) {
1394    CDBG_ERROR("%s:%d] config thumbnail img failed", __func__, __LINE__);
1395    return ret;
1396  }
1397
1398  //Pass the ION buffer to be used as o/p for HW
1399  memset(&work_buffer, 0x0, sizeof(QOMX_WORK_BUFFER));
1400  ret = OMX_GetExtensionIndex(p_session->omx_handle,
1401    QOMX_IMAGE_EXT_WORK_BUFFER_NAME,
1402    &work_buffer_index);
1403  if (ret) {
1404    CDBG_ERROR("%s:%d] Error getting work buffer index %d",
1405      __func__, __LINE__, ret);
1406    return ret;
1407  }
1408  work_buffer.fd = p_session->work_buffer.p_pmem_fd;
1409  work_buffer.vaddr = p_session->work_buffer.addr;
1410  work_buffer.length = (uint32_t)p_session->work_buffer.size;
1411  CDBG_ERROR("%s:%d] Work buffer %d %p WorkBufSize: %d", __func__, __LINE__,
1412    work_buffer.fd, work_buffer.vaddr, work_buffer.length);
1413
1414  ret = OMX_SetConfig(p_session->omx_handle, work_buffer_index,
1415    &work_buffer);
1416  if (ret) {
1417    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1418    return ret;
1419  }
1420
1421  /* set metadata */
1422  ret = mm_jpeg_metadata(p_session);
1423  if (OMX_ErrorNone != ret) {
1424    CDBG_ERROR("%s: config makernote data failed", __func__);
1425    return ret;
1426  }
1427
1428  /* set QTable */
1429  for (i = 0; i < QTABLE_MAX; i++) {
1430    if (p_jobparams->qtable_set[i]) {
1431      ret = OMX_SetConfig(p_session->omx_handle,
1432        OMX_IndexParamQuantizationTable, &p_jobparams->qtable[i]);
1433      if (OMX_ErrorNone != ret) {
1434        CDBG_ERROR("%s:%d] set QTable Error", __func__, __LINE__);
1435        return ret;
1436      }
1437    }
1438  }
1439
1440  return ret;
1441}
1442
1443/** mm_jpeg_session_configure:
1444 *
1445 *  Arguments:
1446 *    @data: encode session
1447 *
1448 *  Return:
1449 *       none
1450 *
1451 *  Description:
1452 *       Configure the session
1453 *
1454 **/
1455static OMX_ERRORTYPE mm_jpeg_session_configure(mm_jpeg_job_session_t *p_session)
1456{
1457  OMX_ERRORTYPE ret = OMX_ErrorNone;
1458
1459  CDBG("%s:%d] E ", __func__, __LINE__);
1460
1461  MM_JPEG_CHK_ABORT(p_session, ret, error);
1462
1463  /* config main img */
1464  ret = mm_jpeg_session_config_main(p_session);
1465  if (OMX_ErrorNone != ret) {
1466    CDBG_ERROR("%s:%d] config main img failed", __func__, __LINE__);
1467    goto error;
1468  }
1469  ret = mm_jpeg_session_change_state(p_session, OMX_StateIdle,
1470    mm_jpeg_session_send_buffers);
1471  if (ret) {
1472    CDBG_ERROR("%s:%d] change state to idle failed %d",
1473      __func__, __LINE__, ret);
1474    goto error;
1475  }
1476
1477  ret = mm_jpeg_session_change_state(p_session, OMX_StateExecuting,
1478    NULL);
1479  if (ret) {
1480    CDBG_ERROR("%s:%d] change state to executing failed %d",
1481      __func__, __LINE__, ret);
1482    goto error;
1483  }
1484
1485error:
1486  CDBG("%s:%d] X ret %d", __func__, __LINE__, ret);
1487  return ret;
1488}
1489
1490
1491
1492
1493
1494
1495/** mm_jpeg_session_encode:
1496 *
1497 *  Arguments:
1498 *    @p_session: encode session
1499 *
1500 *  Return:
1501 *       OMX_ERRORTYPE
1502 *
1503 *  Description:
1504 *       Start the encoding
1505 *
1506 **/
1507static OMX_ERRORTYPE mm_jpeg_session_encode(mm_jpeg_job_session_t *p_session)
1508{
1509  OMX_ERRORTYPE ret = OMX_ErrorNone;
1510  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
1511
1512  pthread_mutex_lock(&p_session->lock);
1513  p_session->abort_state = MM_JPEG_ABORT_NONE;
1514  p_session->encoding = OMX_FALSE;
1515  pthread_mutex_unlock(&p_session->lock);
1516
1517  if (p_session->thumb_from_main) {
1518    if (0 > p_jobparams->src_index) {
1519      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1520      ret = OMX_ErrorUnsupportedIndex;
1521      goto error;
1522    }
1523    p_jobparams->thumb_index = (uint32_t)p_jobparams->src_index;
1524    p_jobparams->thumb_dim.crop = p_jobparams->main_dim.crop;
1525  }
1526
1527  if (OMX_FALSE == p_session->config) {
1528    ret = mm_jpeg_session_configure(p_session);
1529    if (ret) {
1530      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1531      goto error;
1532    }
1533    p_session->config = OMX_TRUE;
1534  }
1535
1536  ret = mm_jpeg_configure_job_params(p_session);
1537  if (ret) {
1538      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1539      goto error;
1540  }
1541  pthread_mutex_lock(&p_session->lock);
1542  p_session->encoding = OMX_TRUE;
1543  pthread_mutex_unlock(&p_session->lock);
1544
1545  MM_JPEG_CHK_ABORT(p_session, ret, error);
1546
1547#ifdef MM_JPEG_DUMP_INPUT
1548  char filename[256];
1549  snprintf(filename, sizeof(filename),
1550      QCAMERA_DUMP_FRM_LOCATION"jpeg/mm_jpeg_int%d.yuv", p_session->ebd_count);
1551  DUMP_TO_FILE(filename,
1552    p_session->p_in_omx_buf[p_jobparams->src_index]->pBuffer,
1553    (size_t)p_session->p_in_omx_buf[p_jobparams->src_index]->nAllocLen);
1554#endif
1555
1556  ret = OMX_EmptyThisBuffer(p_session->omx_handle,
1557    p_session->p_in_omx_buf[p_jobparams->src_index]);
1558  if (ret) {
1559    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1560    goto error;
1561  }
1562
1563  if (p_session->params.encode_thumbnail) {
1564#ifdef MM_JPEG_DUMP_INPUT
1565  char thumb_filename[FILENAME_MAX];
1566  snprintf(thumb_filename, sizeof(thumb_filename),
1567    QCAMERA_DUMP_FRM_LOCATION"jpeg/mm_jpeg_int_t%d.yuv", p_session->ebd_count);
1568  DUMP_TO_FILE(filename,
1569    p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]->pBuffer,
1570    (size_t)p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]->nAllocLen);
1571#endif
1572    ret = OMX_EmptyThisBuffer(p_session->omx_handle,
1573        p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]);
1574    if (ret) {
1575      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1576      goto error;
1577    }
1578  }
1579
1580  ret = OMX_FillThisBuffer(p_session->omx_handle,
1581    p_session->p_out_omx_buf[p_jobparams->dst_index]);
1582  if (ret) {
1583    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1584    goto error;
1585  }
1586
1587  MM_JPEG_CHK_ABORT(p_session, ret, error);
1588
1589error:
1590
1591  CDBG("%s:%d] X ", __func__, __LINE__);
1592  return ret;
1593}
1594
1595/** mm_jpeg_process_encoding_job:
1596 *
1597 *  Arguments:
1598 *    @my_obj: jpeg client
1599 *    @job_node: job node
1600 *
1601 *  Return:
1602 *       0 for success -1 otherwise
1603 *
1604 *  Description:
1605 *       Start the encoding job
1606 *
1607 **/
1608int32_t mm_jpeg_process_encoding_job(mm_jpeg_obj *my_obj, mm_jpeg_job_q_node_t* job_node)
1609{
1610  mm_jpeg_q_data_t qdata;
1611  int32_t rc = 0;
1612  OMX_ERRORTYPE ret = OMX_ErrorNone;
1613  mm_jpeg_job_session_t *p_session = NULL;
1614  uint32_t buf_idx;
1615
1616  /* check if valid session */
1617  p_session = mm_jpeg_get_session(my_obj, job_node->enc_info.job_id);
1618  if (NULL == p_session) {
1619    CDBG_ERROR("%s:%d] invalid job id %x", __func__, __LINE__,
1620        job_node->enc_info.job_id);
1621    return -1;
1622  }
1623
1624  CDBG("%s:%d] before dequeue session %d",
1625                __func__, __LINE__, ret);
1626
1627  /* dequeue available omx handle */
1628  qdata = mm_jpeg_queue_deq(p_session->session_handle_q);
1629  p_session = qdata.p;
1630
1631  if (NULL == p_session) {
1632    CDBG_HIGH("%s:%d] No available sessions %d",
1633          __func__, __LINE__, ret);
1634    /* No available handles */
1635    qdata.p = job_node;
1636    mm_jpeg_queue_enq_head(&my_obj->job_mgr.job_queue, qdata);
1637
1638    CDBG_HIGH("%s:%d]end enqueue %d",
1639              __func__, __LINE__, ret);
1640    return rc;
1641
1642  }
1643
1644  p_session->auto_out_buf = OMX_FALSE;
1645  if (job_node->enc_info.encode_job.dst_index < 0) {
1646    /* dequeue available output buffer idx */
1647    qdata = mm_jpeg_queue_deq(p_session->out_buf_q);
1648    buf_idx = qdata.u32;
1649
1650    if (0U == buf_idx) {
1651      CDBG_ERROR("%s:%d] No available output buffers %d",
1652          __func__, __LINE__, ret);
1653      return OMX_ErrorUndefined;
1654    }
1655
1656    buf_idx--;
1657
1658    job_node->enc_info.encode_job.dst_index = (int32_t)buf_idx;
1659    p_session->auto_out_buf = OMX_TRUE;
1660  }
1661
1662  /* sent encode cmd to OMX, queue job into ongoing queue */
1663  qdata.p = job_node;
1664  rc = mm_jpeg_queue_enq(&my_obj->ongoing_job_q, qdata);
1665  if (rc) {
1666    CDBG_ERROR("%s:%d] jpeg enqueue failed %d",
1667      __func__, __LINE__, ret);
1668    goto error;
1669  }
1670
1671  p_session->encode_job = job_node->enc_info.encode_job;
1672  p_session->jobId = job_node->enc_info.job_id;
1673  ret = mm_jpeg_session_encode(p_session);
1674  if (ret) {
1675    CDBG_ERROR("%s:%d] encode session failed", __func__, __LINE__);
1676    goto error;
1677  }
1678
1679  CDBG_HIGH("%s:%d] Success X ", __func__, __LINE__);
1680  return rc;
1681
1682error:
1683
1684  if ((OMX_ErrorNone != ret) &&
1685    (NULL != p_session->params.jpeg_cb)) {
1686    p_session->job_status = JPEG_JOB_STATUS_ERROR;
1687    CDBG_ERROR("%s:%d] send jpeg error callback %d", __func__, __LINE__,
1688      p_session->job_status);
1689    p_session->params.jpeg_cb(p_session->job_status,
1690      p_session->client_hdl,
1691      p_session->jobId,
1692      NULL,
1693      p_session->params.userdata);
1694  }
1695
1696  /*remove the job*/
1697  mm_jpegenc_job_done(p_session);
1698  CDBG("%s:%d] Error X ", __func__, __LINE__);
1699
1700  return rc;
1701}
1702
1703
1704
1705/** mm_jpeg_jobmgr_thread:
1706 *
1707 *  Arguments:
1708 *    @my_obj: jpeg object
1709 *
1710 *  Return:
1711 *       0 for success else failure
1712 *
1713 *  Description:
1714 *       job manager thread main function
1715 *
1716 **/
1717static void *mm_jpeg_jobmgr_thread(void *data)
1718{
1719  mm_jpeg_q_data_t qdata;
1720  int rc = 0;
1721  int running = 1;
1722  uint32_t num_ongoing_jobs = 0;
1723  mm_jpeg_obj *my_obj = (mm_jpeg_obj*)data;
1724  mm_jpeg_job_cmd_thread_t *cmd_thread = &my_obj->job_mgr;
1725  mm_jpeg_job_q_node_t* node = NULL;
1726  prctl(PR_SET_NAME, (unsigned long)"mm_jpeg_thread", 0, 0, 0);
1727
1728  do {
1729    do {
1730      rc = cam_sem_wait(&cmd_thread->job_sem);
1731      if (rc != 0 && errno != EINVAL) {
1732        CDBG_ERROR("%s: cam_sem_wait error (%s)",
1733          __func__, strerror(errno));
1734        return NULL;
1735      }
1736    } while (rc != 0);
1737
1738    /* check ongoing q size */
1739    num_ongoing_jobs = mm_jpeg_queue_get_size(&my_obj->ongoing_job_q);
1740    if (num_ongoing_jobs >= NUM_MAX_JPEG_CNCURRENT_JOBS) {
1741      CDBG("%s:%d] ongoing job already reach max %d", __func__,
1742        __LINE__, num_ongoing_jobs);
1743      continue;
1744    }
1745
1746    pthread_mutex_lock(&my_obj->job_lock);
1747    /* can go ahead with new work */
1748    qdata = mm_jpeg_queue_deq(&cmd_thread->job_queue);
1749    node = (mm_jpeg_job_q_node_t*)qdata.p;
1750    if (node != NULL) {
1751      switch (node->type) {
1752      case MM_JPEG_CMD_TYPE_JOB:
1753        rc = mm_jpeg_process_encoding_job(my_obj, node);
1754        break;
1755      case MM_JPEG_CMD_TYPE_DECODE_JOB:
1756        rc = mm_jpegdec_process_decoding_job(my_obj, node);
1757        break;
1758      case MM_JPEG_CMD_TYPE_EXIT:
1759      default:
1760        /* free node */
1761        free(node);
1762        /* set running flag to false */
1763        running = 0;
1764        break;
1765      }
1766    }
1767    pthread_mutex_unlock(&my_obj->job_lock);
1768
1769  } while (running);
1770  return NULL;
1771}
1772
1773/** mm_jpeg_jobmgr_thread_launch:
1774 *
1775 *  Arguments:
1776 *    @my_obj: jpeg object
1777 *
1778 *  Return:
1779 *       0 for success else failure
1780 *
1781 *  Description:
1782 *       launches the job manager thread
1783 *
1784 **/
1785int32_t mm_jpeg_jobmgr_thread_launch(mm_jpeg_obj *my_obj)
1786{
1787  int32_t rc = 0;
1788  mm_jpeg_job_cmd_thread_t *job_mgr = &my_obj->job_mgr;
1789
1790  cam_sem_init(&job_mgr->job_sem, 0);
1791  mm_jpeg_queue_init(&job_mgr->job_queue);
1792
1793  /* launch the thread */
1794  pthread_create(&job_mgr->pid,
1795    NULL,
1796    mm_jpeg_jobmgr_thread,
1797    (void *)my_obj);
1798  pthread_setname_np(job_mgr->pid, "CAM_jpeg_jobmgr");
1799  return rc;
1800}
1801
1802/** mm_jpeg_jobmgr_thread_release:
1803 *
1804 *  Arguments:
1805 *    @my_obj: jpeg object
1806 *
1807 *  Return:
1808 *       0 for success else failure
1809 *
1810 *  Description:
1811 *       Releases the job manager thread
1812 *
1813 **/
1814int32_t mm_jpeg_jobmgr_thread_release(mm_jpeg_obj * my_obj)
1815{
1816  mm_jpeg_q_data_t qdata;
1817  int32_t rc = 0;
1818  mm_jpeg_job_cmd_thread_t * cmd_thread = &my_obj->job_mgr;
1819  mm_jpeg_job_q_node_t* node =
1820    (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t));
1821  if (NULL == node) {
1822    CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__);
1823    return -1;
1824  }
1825
1826  memset(node, 0, sizeof(mm_jpeg_job_q_node_t));
1827  node->type = MM_JPEG_CMD_TYPE_EXIT;
1828
1829  qdata.p = node;
1830  mm_jpeg_queue_enq(&cmd_thread->job_queue, qdata);
1831  cam_sem_post(&cmd_thread->job_sem);
1832
1833  /* wait until cmd thread exits */
1834  if (pthread_join(cmd_thread->pid, NULL) != 0) {
1835    CDBG("%s: pthread dead already", __func__);
1836  }
1837  mm_jpeg_queue_deinit(&cmd_thread->job_queue);
1838
1839  cam_sem_destroy(&cmd_thread->job_sem);
1840  memset(cmd_thread, 0, sizeof(mm_jpeg_job_cmd_thread_t));
1841  return rc;
1842}
1843
1844/** mm_jpeg_init:
1845 *
1846 *  Arguments:
1847 *    @my_obj: jpeg object
1848 *
1849 *  Return:
1850 *       0 for success else failure
1851 *
1852 *  Description:
1853 *       Initializes the jpeg client
1854 *
1855 **/
1856int32_t mm_jpeg_init(mm_jpeg_obj *my_obj)
1857{
1858  int32_t rc = 0;
1859  uint32_t work_buf_size;
1860  unsigned int i = 0;
1861  unsigned int initial_workbufs_cnt = 1;
1862
1863  /* init locks */
1864  pthread_mutex_init(&my_obj->job_lock, NULL);
1865
1866  /* init ongoing job queue */
1867  rc = mm_jpeg_queue_init(&my_obj->ongoing_job_q);
1868  if (0 != rc) {
1869    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1870    pthread_mutex_destroy(&my_obj->job_lock);
1871    return -1;
1872  }
1873
1874
1875  /* init job semaphore and launch jobmgr thread */
1876  CDBG("%s:%d] Launch jobmgr thread rc %d", __func__, __LINE__, rc);
1877  rc = mm_jpeg_jobmgr_thread_launch(my_obj);
1878  if (0 != rc) {
1879    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1880    mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
1881    pthread_mutex_destroy(&my_obj->job_lock);
1882    return -1;
1883  }
1884
1885  /* set work buf size from max picture size */
1886  if (my_obj->max_pic_w <= 0 || my_obj->max_pic_h <= 0) {
1887    CDBG_ERROR("%s:%d] Width and height are not valid "
1888      "dimensions, cannot calc work buf size",__func__, __LINE__);
1889    mm_jpeg_jobmgr_thread_release(my_obj);
1890    mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
1891    pthread_mutex_destroy(&my_obj->job_lock);
1892    return -1;
1893  }
1894  work_buf_size = CEILING64((uint32_t)my_obj->max_pic_w) *
1895    CEILING64((uint32_t)my_obj->max_pic_h) * 3U / 2U;
1896  for (i = 0; i < initial_workbufs_cnt; i++) {
1897    my_obj->ionBuffer[i].size = CEILING32(work_buf_size);
1898    CDBG_HIGH("Max picture size %d x %d, WorkBufSize = %zu",
1899        my_obj->max_pic_w, my_obj->max_pic_h, my_obj->ionBuffer[i].size);
1900
1901    my_obj->ionBuffer[i].addr = (uint8_t *)buffer_allocate(&my_obj->ionBuffer[i], 1);
1902    if (NULL == my_obj->ionBuffer[i].addr) {
1903      while (i--) {
1904        buffer_deallocate(&my_obj->ionBuffer[i]);
1905      }
1906      mm_jpeg_jobmgr_thread_release(my_obj);
1907      mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
1908      pthread_mutex_destroy(&my_obj->job_lock);
1909      CDBG_ERROR("%s:%d] Ion allocation failed",__func__, __LINE__);
1910      return -1;
1911    }
1912  }
1913
1914  my_obj->work_buf_cnt = i;
1915
1916  /* load OMX */
1917  if (OMX_ErrorNone != OMX_Init()) {
1918    /* roll back in error case */
1919    CDBG_ERROR("%s:%d] OMX_Init failed (%d)", __func__, __LINE__, rc);
1920    for (i = 0; i < initial_workbufs_cnt; i++) {
1921      buffer_deallocate(&my_obj->ionBuffer[i]);
1922    }
1923    mm_jpeg_jobmgr_thread_release(my_obj);
1924    mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
1925    pthread_mutex_destroy(&my_obj->job_lock);
1926  }
1927
1928#ifdef LOAD_ADSP_RPC_LIB
1929  my_obj->adsprpc_lib_handle = dlopen("libadsprpc.so", RTLD_NOW);
1930  if (NULL == my_obj->adsprpc_lib_handle) {
1931    CDBG_ERROR("%s:%d] Cannot load the library", __func__, __LINE__);
1932    /* not returning error here bcoz even if this loading fails
1933        we can go ahead with SW JPEG enc */
1934  }
1935#endif
1936
1937  return rc;
1938}
1939
1940/** mm_jpeg_deinit:
1941 *
1942 *  Arguments:
1943 *    @my_obj: jpeg object
1944 *
1945 *  Return:
1946 *       0 for success else failure
1947 *
1948 *  Description:
1949 *       Deinits the jpeg client
1950 *
1951 **/
1952int32_t mm_jpeg_deinit(mm_jpeg_obj *my_obj)
1953{
1954  int32_t rc = 0;
1955  uint32_t i = 0;
1956
1957  /* release jobmgr thread */
1958  rc = mm_jpeg_jobmgr_thread_release(my_obj);
1959  if (0 != rc) {
1960    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1961  }
1962
1963  /* unload OMX engine */
1964  OMX_Deinit();
1965
1966  /* deinit ongoing job and cb queue */
1967  rc = mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
1968  if (0 != rc) {
1969    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1970  }
1971
1972  for (i = 0; i < my_obj->work_buf_cnt; i++) {
1973    /*Release the ION buffer*/
1974    rc = buffer_deallocate(&my_obj->ionBuffer[i]);
1975    if (0 != rc) {
1976      CDBG_ERROR("%s:%d] Error releasing ION buffer", __func__, __LINE__);
1977    }
1978  }
1979
1980  /* destroy locks */
1981  pthread_mutex_destroy(&my_obj->job_lock);
1982
1983  return rc;
1984}
1985
1986/** mm_jpeg_new_client:
1987 *
1988 *  Arguments:
1989 *    @my_obj: jpeg object
1990 *
1991 *  Return:
1992 *       0 for success else failure
1993 *
1994 *  Description:
1995 *       Create new jpeg client
1996 *
1997 **/
1998uint32_t mm_jpeg_new_client(mm_jpeg_obj *my_obj)
1999{
2000  uint32_t client_hdl = 0;
2001  uint8_t idx;
2002  int i = 0;
2003
2004  if (my_obj->num_clients >= MAX_JPEG_CLIENT_NUM) {
2005    CDBG_ERROR("%s: num of clients reached limit", __func__);
2006    return client_hdl;
2007  }
2008
2009  for (idx = 0; idx < MAX_JPEG_CLIENT_NUM; idx++) {
2010    if (0 == my_obj->clnt_mgr[idx].is_used) {
2011      break;
2012    }
2013  }
2014
2015  if (idx < MAX_JPEG_CLIENT_NUM) {
2016    /* client session avail */
2017    /* generate client handler by index */
2018    client_hdl = mm_jpeg_util_generate_handler(idx);
2019
2020    /* update client session */
2021    my_obj->clnt_mgr[idx].is_used = 1;
2022    my_obj->clnt_mgr[idx].client_handle = client_hdl;
2023
2024    pthread_mutex_init(&my_obj->clnt_mgr[idx].lock, NULL);
2025    for (i = 0; i < MM_JPEG_MAX_SESSION; i++) {
2026      memset(&my_obj->clnt_mgr[idx].session[i], 0x0, sizeof(mm_jpeg_job_session_t));
2027    }
2028
2029    /* increse client count */
2030    my_obj->num_clients++;
2031  }
2032
2033  return client_hdl;
2034}
2035
2036/** mm_jpeg_start_job:
2037 *
2038 *  Arguments:
2039 *    @my_obj: jpeg object
2040 *    @client_hdl: client handle
2041 *    @job: pointer to encode job
2042 *    @jobId: job id
2043 *
2044 *  Return:
2045 *       0 for success else failure
2046 *
2047 *  Description:
2048 *       Start the encoding job
2049 *
2050 **/
2051int32_t mm_jpeg_start_job(mm_jpeg_obj *my_obj,
2052  mm_jpeg_job_t *job,
2053  uint32_t *job_id)
2054{
2055  mm_jpeg_q_data_t qdata;
2056  int32_t rc = -1;
2057  uint8_t session_idx = 0;
2058  uint8_t client_idx = 0;
2059  mm_jpeg_job_q_node_t* node = NULL;
2060  mm_jpeg_job_session_t *p_session = NULL;
2061  mm_jpeg_encode_job_t *p_jobparams  = &job->encode_job;
2062
2063  *job_id = 0;
2064
2065  /* check if valid session */
2066  session_idx = GET_SESSION_IDX(p_jobparams->session_id);
2067  client_idx = GET_CLIENT_IDX(p_jobparams->session_id);
2068  CDBG_HIGH("%s:%d] session_idx %d client idx %d", __func__, __LINE__,
2069    session_idx, client_idx);
2070
2071  if ((session_idx >= MM_JPEG_MAX_SESSION) ||
2072    (client_idx >= MAX_JPEG_CLIENT_NUM)) {
2073    CDBG_ERROR("%s:%d] invalid session id %x", __func__, __LINE__,
2074      job->encode_job.session_id);
2075    return rc;
2076  }
2077
2078  p_session = &my_obj->clnt_mgr[client_idx].session[session_idx];
2079  if (OMX_FALSE == p_session->active) {
2080    CDBG_ERROR("%s:%d] session not active %x", __func__, __LINE__,
2081      job->encode_job.session_id);
2082    return rc;
2083  }
2084
2085  if ((p_jobparams->src_index >= (int32_t)p_session->params.num_src_bufs) ||
2086    (p_jobparams->dst_index >= (int32_t)p_session->params.num_dst_bufs)) {
2087    CDBG_ERROR("%s:%d] invalid buffer indices", __func__, __LINE__);
2088    return rc;
2089  }
2090
2091  /* enqueue new job into todo job queue */
2092  node = (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t));
2093  if (NULL == node) {
2094    CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__);
2095    return -1;
2096  }
2097
2098  ATRACE_INT("Camera:JPEG",
2099      (int32_t)((uint32_t)session_idx<<16 | ++p_session->job_index));
2100
2101  *job_id = job->encode_job.session_id |
2102    (((uint32_t)p_session->job_hist++ % JOB_HIST_MAX) << 16);
2103
2104  memset(node, 0, sizeof(mm_jpeg_job_q_node_t));
2105  node->enc_info.encode_job = job->encode_job;
2106  if (p_session->thumb_from_main) {
2107    node->enc_info.encode_job.thumb_dim.src_dim =
2108      node->enc_info.encode_job.main_dim.src_dim;
2109    node->enc_info.encode_job.thumb_dim.crop =
2110      node->enc_info.encode_job.main_dim.crop;
2111  }
2112  node->enc_info.job_id = *job_id;
2113  node->enc_info.client_handle = p_session->client_hdl;
2114  node->type = MM_JPEG_CMD_TYPE_JOB;
2115
2116
2117
2118  qdata.p = node;
2119  rc = mm_jpeg_queue_enq(&my_obj->job_mgr.job_queue, qdata);
2120  if (0 == rc) {
2121      cam_sem_post(&my_obj->job_mgr.job_sem);
2122  }
2123
2124  CDBG_HIGH("%s:%d] X", __func__, __LINE__);
2125
2126  return rc;
2127}
2128
2129
2130
2131/** mm_jpeg_abort_job:
2132 *
2133 *  Arguments:
2134 *    @my_obj: jpeg object
2135 *    @client_hdl: client handle
2136 *    @jobId: job id
2137 *
2138 *  Return:
2139 *       0 for success else failure
2140 *
2141 *  Description:
2142 *       Abort the encoding session
2143 *
2144 **/
2145int32_t mm_jpeg_abort_job(mm_jpeg_obj *my_obj,
2146  uint32_t jobId)
2147{
2148  int32_t rc = -1;
2149  mm_jpeg_job_q_node_t *node = NULL;
2150  mm_jpeg_job_session_t *p_session = NULL;
2151
2152  CDBG("%s:%d] ", __func__, __LINE__);
2153  pthread_mutex_lock(&my_obj->job_lock);
2154
2155  /* abort job if in todo queue */
2156  node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->job_mgr.job_queue, jobId);
2157  if (NULL != node) {
2158    free(node);
2159    goto abort_done;
2160  }
2161
2162  /* abort job if in ongoing queue */
2163  node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, jobId);
2164  if (NULL != node) {
2165    /* find job that is OMX ongoing, ask OMX to abort the job */
2166    p_session = mm_jpeg_get_session(my_obj, node->enc_info.job_id);
2167    if (p_session) {
2168      mm_jpeg_session_abort(p_session);
2169    } else {
2170      CDBG_ERROR("%s:%d] Invalid job id 0x%x", __func__, __LINE__,
2171        node->enc_info.job_id);
2172    }
2173    free(node);
2174    goto abort_done;
2175  }
2176
2177abort_done:
2178  pthread_mutex_unlock(&my_obj->job_lock);
2179
2180  return rc;
2181}
2182
2183
2184#ifdef MM_JPEG_READ_META_KEYFILE
2185static int32_t mm_jpeg_read_meta_keyfile(mm_jpeg_job_session_t *p_session,
2186    const char *filename)
2187{
2188  int rc = 0;
2189  FILE *fp = NULL;
2190  size_t file_size = 0;
2191  fp = fopen(filename, "r");
2192  if (!fp) {
2193    CDBG_ERROR("%s:%d] Key not present", __func__, __LINE__);
2194    return -1;
2195  }
2196  fseek(fp, 0, SEEK_END);
2197  file_size = (size_t)ftell(fp);
2198  fseek(fp, 0, SEEK_SET);
2199
2200  p_session->meta_enc_key = (uint8_t *) malloc((file_size + 1) * sizeof(uint8_t));
2201
2202  if (!p_session->meta_enc_key) {
2203    CDBG_ERROR("%s:%d] error", __func__, __LINE__);
2204    return -1;
2205  }
2206
2207  fread(p_session->meta_enc_key, 1, file_size, fp);
2208  fclose(fp);
2209
2210  p_session->meta_enc_keylen = file_size;
2211
2212  return rc;
2213}
2214#endif // MM_JPEG_READ_META_KEYFILE
2215
2216/** mm_jpeg_create_session:
2217 *
2218 *  Arguments:
2219 *    @my_obj: jpeg object
2220 *    @client_hdl: client handle
2221 *    @p_params: pointer to encode params
2222 *    @p_session_id: session id
2223 *
2224 *  Return:
2225 *       0 for success else failure
2226 *
2227 *  Description:
2228 *       Start the encoding session
2229 *
2230 **/
2231int32_t mm_jpeg_create_session(mm_jpeg_obj *my_obj,
2232  uint32_t client_hdl,
2233  mm_jpeg_encode_params_t *p_params,
2234  uint32_t* p_session_id)
2235{
2236  mm_jpeg_q_data_t qdata;
2237  int32_t rc = 0;
2238  OMX_ERRORTYPE ret = OMX_ErrorNone;
2239  uint8_t clnt_idx = 0;
2240  int session_idx = -1;
2241  mm_jpeg_job_session_t *p_session = NULL;
2242  mm_jpeg_job_session_t * p_prev_session = NULL;
2243  *p_session_id = 0;
2244  uint32_t i = 0;
2245  uint32_t num_omx_sessions;
2246  uint32_t work_buf_size;
2247  mm_jpeg_queue_t *p_session_handle_q, *p_out_buf_q;
2248  uint32_t work_bufs_need;
2249  char trace_tag[32];
2250
2251  /* validate the parameters */
2252  if ((p_params->num_src_bufs > MM_JPEG_MAX_BUF)
2253    || (p_params->num_dst_bufs > MM_JPEG_MAX_BUF)) {
2254    CDBG_ERROR("%s:%d] invalid num buffers", __func__, __LINE__);
2255    return -1;
2256  }
2257
2258  /* check if valid client */
2259  clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl);
2260  if (clnt_idx >= MAX_JPEG_CLIENT_NUM) {
2261    CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl);
2262    return -1;
2263  }
2264
2265  num_omx_sessions = 1;
2266  if (p_params->burst_mode) {
2267    num_omx_sessions = MM_JPEG_CONCURRENT_SESSIONS_COUNT;
2268  }
2269  work_bufs_need = my_obj->num_sessions + num_omx_sessions;
2270  if (work_bufs_need > MM_JPEG_CONCURRENT_SESSIONS_COUNT) {
2271    work_bufs_need = MM_JPEG_CONCURRENT_SESSIONS_COUNT;
2272  }
2273  CDBG_HIGH("%s:%d] >>>> Work bufs need %d", __func__, __LINE__, work_bufs_need);
2274  work_buf_size = CEILING64((uint32_t)my_obj->max_pic_w) *
2275      CEILING64((uint32_t)my_obj->max_pic_h) * 3 / 2;
2276  for (i = my_obj->work_buf_cnt; i < work_bufs_need; i++) {
2277     my_obj->ionBuffer[i].size = CEILING32(work_buf_size);
2278     CDBG_HIGH("Max picture size %d x %d, WorkBufSize = %zu",
2279         my_obj->max_pic_w, my_obj->max_pic_h, my_obj->ionBuffer[i].size);
2280
2281     my_obj->ionBuffer[i].addr = (uint8_t *)buffer_allocate(&my_obj->ionBuffer[i], 1);
2282     if (NULL == my_obj->ionBuffer[i].addr) {
2283       CDBG_ERROR("%s:%d] Ion allocation failed",__func__, __LINE__);
2284       goto error1;
2285     }
2286     my_obj->work_buf_cnt++;
2287  }
2288
2289  /* init omx handle queue */
2290  p_session_handle_q = (mm_jpeg_queue_t *) malloc(sizeof(*p_session_handle_q));
2291  if (NULL == p_session_handle_q) {
2292    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
2293    goto error1;
2294  }
2295  rc = mm_jpeg_queue_init(p_session_handle_q);
2296  if (0 != rc) {
2297    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
2298    free(p_session_handle_q);
2299    goto error1;
2300  }
2301
2302  /* init output buf queue */
2303  p_out_buf_q = (mm_jpeg_queue_t *) malloc(sizeof(*p_out_buf_q));
2304  if (NULL == p_out_buf_q) {
2305    CDBG_ERROR("%s:%d] Error: Cannot allocate memory\n", __func__, __LINE__);
2306    return -1;
2307  }
2308
2309  /* init omx handle queue */
2310  rc = mm_jpeg_queue_init(p_out_buf_q);
2311  if (0 != rc) {
2312    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
2313    free(p_out_buf_q);
2314    goto error1;
2315  }
2316
2317  for (i = 0; i < num_omx_sessions; i++) {
2318    uint32_t buf_idx = 0U;
2319    session_idx = mm_jpeg_get_new_session_idx(my_obj, clnt_idx, &p_session);
2320    if (session_idx < 0 || NULL == p_session) {
2321      CDBG_ERROR("%s:%d] invalid session id (%d)", __func__, __LINE__, session_idx);
2322      goto error2;
2323    }
2324
2325    snprintf(trace_tag, sizeof(trace_tag), "Camera:JPEGsession%d", session_idx);
2326    ATRACE_INT(trace_tag, 1);
2327
2328    p_session->job_index = 0;
2329
2330    p_session->next_session = NULL;
2331
2332    if (p_prev_session) {
2333      p_prev_session->next_session = p_session;
2334    }
2335    p_prev_session = p_session;
2336
2337    buf_idx = my_obj->num_sessions + i;
2338    if (buf_idx < MM_JPEG_CONCURRENT_SESSIONS_COUNT) {
2339      p_session->work_buffer = my_obj->ionBuffer[buf_idx];
2340    } else {
2341      p_session->work_buffer.addr = NULL;
2342      p_session->work_buffer.ion_fd = -1;
2343      p_session->work_buffer.p_pmem_fd = -1;
2344    }
2345
2346    p_session->jpeg_obj = (void*)my_obj; /* save a ptr to jpeg_obj */
2347
2348    ret = mm_jpeg_session_create(p_session);
2349    if (OMX_ErrorNone != ret) {
2350      p_session->active = OMX_FALSE;
2351      CDBG_ERROR("%s:%d] jpeg session create failed", __func__, __LINE__);
2352      goto error2;
2353    }
2354
2355    uint32_t session_id = (JOB_ID_MAGICVAL << 24) |
2356        ((uint32_t)session_idx << 8) | clnt_idx;
2357
2358    if (!*p_session_id) {
2359      *p_session_id = session_id;
2360    }
2361
2362    /*copy the params*/
2363    p_session->params = *p_params;
2364    if (p_session->thumb_from_main) {
2365      memcpy(p_session->params.src_thumb_buf, p_session->params.src_main_buf,
2366        sizeof(p_session->params.src_thumb_buf));
2367      p_session->params.num_tmb_bufs =  p_session->params.num_src_bufs;
2368      if (!p_session->params.encode_thumbnail) {
2369         p_session->params.num_tmb_bufs = 0;
2370      }
2371      p_session->params.thumb_dim.src_dim = p_session->params.main_dim.src_dim;
2372      p_session->params.thumb_dim.crop = p_session->params.main_dim.crop;
2373    }
2374    p_session->client_hdl = client_hdl;
2375    p_session->sessionId = session_id;
2376    p_session->session_handle_q = p_session_handle_q;
2377    p_session->out_buf_q = p_out_buf_q;
2378
2379    qdata.p = p_session;
2380    mm_jpeg_queue_enq(p_session_handle_q, qdata);
2381
2382    p_session->meta_enc_key = NULL;
2383    p_session->meta_enc_keylen = 0;
2384
2385#ifdef MM_JPEG_READ_META_KEYFILE
2386    mm_jpeg_read_meta_keyfile(p_session, META_KEYFILE);
2387#endif
2388
2389    if (OMX_FALSE == p_session->config) {
2390      rc = mm_jpeg_session_configure(p_session);
2391      if (rc) {
2392        CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
2393        goto error2;
2394      }
2395      p_session->config = OMX_TRUE;
2396    }
2397    p_session->num_omx_sessions = num_omx_sessions;
2398
2399    CDBG_HIGH("%s:%d] session id %x", __func__, __LINE__, session_id);
2400  }
2401
2402  // Queue the output buf indexes
2403  for (i = 0; i < p_params->num_dst_bufs; i++) {
2404    qdata.u32 = i + 1;
2405    mm_jpeg_queue_enq(p_out_buf_q, qdata);
2406  }
2407
2408  return rc;
2409
2410error1:
2411  rc = -1;
2412error2:
2413  if (NULL != p_session) {
2414    ATRACE_INT(trace_tag, 0);
2415  }
2416  return rc;
2417}
2418
2419/** mm_jpegenc_destroy_job
2420 *
2421 *  Arguments:
2422 *    @p_session: Session obj
2423 *
2424 *  Return:
2425 *       0 for success else failure
2426 *
2427 *  Description:
2428 *       Destroy the job based paramenters
2429 *
2430 **/
2431static int32_t mm_jpegenc_destroy_job(mm_jpeg_job_session_t *p_session)
2432{
2433  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
2434  int i = 0, rc = 0;
2435
2436  CDBG_HIGH("%s:%d] Exif entry count %d %d", __func__, __LINE__,
2437    (int)p_jobparams->exif_info.numOfEntries,
2438    (int)p_session->exif_count_local);
2439  for (i = 0; i < p_session->exif_count_local; i++) {
2440    rc = releaseExifEntry(&p_session->exif_info_local[i]);
2441    if (rc) {
2442      CDBG_ERROR("%s:%d] Exif release failed (%d)", __func__, __LINE__, rc);
2443    }
2444  }
2445  p_session->exif_count_local = 0;
2446
2447  return rc;
2448}
2449
2450/** mm_jpeg_session_encode:
2451 *
2452 *  Arguments:
2453 *    @p_session: encode session
2454 *
2455 *  Return:
2456 *       OMX_ERRORTYPE
2457 *
2458 *  Description:
2459 *       Start the encoding
2460 *
2461 **/
2462static void mm_jpegenc_job_done(mm_jpeg_job_session_t *p_session)
2463{
2464  mm_jpeg_q_data_t qdata;
2465  mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj;
2466  mm_jpeg_job_q_node_t *node = NULL;
2467
2468  /*Destroy job related params*/
2469  mm_jpegenc_destroy_job(p_session);
2470
2471  /*remove the job*/
2472  node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q,
2473    p_session->jobId);
2474  if (node) {
2475    free(node);
2476  }
2477  p_session->encoding = OMX_FALSE;
2478
2479  // Queue to available sessions
2480  qdata.p = p_session;
2481  mm_jpeg_queue_enq(p_session->session_handle_q, qdata);
2482
2483  if (p_session->auto_out_buf) {
2484    //Queue out buf index
2485    qdata.u32 = (uint32_t)(p_session->encode_job.dst_index + 1);
2486    mm_jpeg_queue_enq(p_session->out_buf_q, qdata);
2487  }
2488
2489  /* wake up jobMgr thread to work on new job if there is any */
2490  cam_sem_post(&my_obj->job_mgr.job_sem);
2491}
2492
2493/** mm_jpeg_destroy_session:
2494 *
2495 *  Arguments:
2496 *    @my_obj: jpeg object
2497 *    @session_id: session index
2498 *
2499 *  Return:
2500 *       0 for success else failure
2501 *
2502 *  Description:
2503 *       Destroy the encoding session
2504 *
2505 **/
2506int32_t mm_jpeg_destroy_session(mm_jpeg_obj *my_obj,
2507  mm_jpeg_job_session_t *p_session)
2508{
2509  mm_jpeg_q_data_t qdata;
2510  int32_t rc = 0;
2511  mm_jpeg_job_q_node_t *node = NULL;
2512  uint32_t session_id = 0;
2513  mm_jpeg_job_session_t *p_cur_sess;
2514  char trace_tag[32];
2515
2516  if (NULL == p_session) {
2517    CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__);
2518    return rc;
2519  }
2520
2521  session_id = p_session->sessionId;
2522
2523  pthread_mutex_lock(&my_obj->job_lock);
2524
2525  /* abort job if in todo queue */
2526  CDBG_HIGH("%s:%d] abort todo jobs", __func__, __LINE__);
2527  node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
2528  while (NULL != node) {
2529    free(node);
2530    node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
2531  }
2532
2533  /* abort job if in ongoing queue */
2534  CDBG_HIGH("%s:%d] abort ongoing jobs", __func__, __LINE__);
2535  node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
2536  while (NULL != node) {
2537    free(node);
2538    node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
2539  }
2540
2541  /* abort the current session */
2542  mm_jpeg_session_abort(p_session);
2543  mm_jpeg_session_destroy(p_session);
2544
2545  p_cur_sess = p_session;
2546
2547  do {
2548    mm_jpeg_remove_session_idx(my_obj, p_cur_sess->sessionId);
2549  } while (NULL != (p_cur_sess = p_cur_sess->next_session));
2550
2551
2552  pthread_mutex_unlock(&my_obj->job_lock);
2553
2554  while (1) {
2555    qdata = mm_jpeg_queue_deq(p_session->session_handle_q);
2556    if (NULL == qdata.p)
2557      break;
2558  }
2559  mm_jpeg_queue_deinit(p_session->session_handle_q);
2560  free(p_session->session_handle_q);
2561  p_session->session_handle_q = NULL;
2562
2563  while (1) {
2564    qdata = mm_jpeg_queue_deq(p_session->out_buf_q);
2565    if (0U == qdata.u32)
2566      break;
2567  }
2568  mm_jpeg_queue_deinit(p_session->out_buf_q);
2569  free(p_session->out_buf_q);
2570  p_session->out_buf_q = NULL;
2571
2572
2573  /* wake up jobMgr thread to work on new job if there is any */
2574  cam_sem_post(&my_obj->job_mgr.job_sem);
2575
2576  snprintf(trace_tag, sizeof(trace_tag), "Camera:JPEGsession%d", GET_SESSION_IDX(session_id));
2577  ATRACE_INT(trace_tag, 0);
2578
2579  CDBG_HIGH("%s:%d] destroy session successful. X", __func__, __LINE__);
2580
2581  return rc;
2582}
2583
2584
2585
2586
2587/** mm_jpeg_destroy_session:
2588 *
2589 *  Arguments:
2590 *    @my_obj: jpeg object
2591 *    @session_id: session index
2592 *
2593 *  Return:
2594 *       0 for success else failure
2595 *
2596 *  Description:
2597 *       Destroy the encoding session
2598 *
2599 **/
2600int32_t mm_jpeg_destroy_session_unlocked(mm_jpeg_obj *my_obj,
2601  mm_jpeg_job_session_t *p_session)
2602{
2603  int32_t rc = -1;
2604  mm_jpeg_job_q_node_t *node = NULL;
2605  uint32_t session_id = 0;
2606  if (NULL == p_session) {
2607    CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__);
2608    return rc;
2609  }
2610
2611  session_id = p_session->sessionId;
2612
2613  /* abort job if in todo queue */
2614  CDBG("%s:%d] abort todo jobs", __func__, __LINE__);
2615  node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
2616  while (NULL != node) {
2617    free(node);
2618    node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
2619  }
2620
2621  /* abort job if in ongoing queue */
2622  CDBG("%s:%d] abort ongoing jobs", __func__, __LINE__);
2623  node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
2624  while (NULL != node) {
2625    free(node);
2626    node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
2627  }
2628
2629  /* abort the current session */
2630  mm_jpeg_session_abort(p_session);
2631  //mm_jpeg_remove_session_idx(my_obj, session_id);
2632
2633  return rc;
2634}
2635
2636/** mm_jpeg_destroy_session:
2637 *
2638 *  Arguments:
2639 *    @my_obj: jpeg object
2640 *    @session_id: session index
2641 *
2642 *  Return:
2643 *       0 for success else failure
2644 *
2645 *  Description:
2646 *       Destroy the encoding session
2647 *
2648 **/
2649int32_t mm_jpeg_destroy_session_by_id(mm_jpeg_obj *my_obj, uint32_t session_id)
2650{
2651  mm_jpeg_job_session_t *p_session = mm_jpeg_get_session(my_obj, session_id);
2652
2653  return mm_jpeg_destroy_session(my_obj, p_session);
2654}
2655
2656
2657
2658/** mm_jpeg_close:
2659 *
2660 *  Arguments:
2661 *    @my_obj: jpeg object
2662 *    @client_hdl: client handle
2663 *
2664 *  Return:
2665 *       0 for success else failure
2666 *
2667 *  Description:
2668 *       Close the jpeg client
2669 *
2670 **/
2671int32_t mm_jpeg_close(mm_jpeg_obj *my_obj, uint32_t client_hdl)
2672{
2673  int32_t rc = -1;
2674  uint8_t clnt_idx = 0;
2675  int i = 0;
2676
2677  /* check if valid client */
2678  clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl);
2679  if (clnt_idx >= MAX_JPEG_CLIENT_NUM) {
2680    CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl);
2681    return rc;
2682  }
2683
2684  CDBG("%s:%d] E", __func__, __LINE__);
2685
2686  /* abort all jobs from the client */
2687  pthread_mutex_lock(&my_obj->job_lock);
2688
2689  CDBG("%s:%d] ", __func__, __LINE__);
2690
2691  for (i = 0; i < MM_JPEG_MAX_SESSION; i++) {
2692    if (OMX_TRUE == my_obj->clnt_mgr[clnt_idx].session[i].active)
2693      mm_jpeg_destroy_session_unlocked(my_obj,
2694        &my_obj->clnt_mgr[clnt_idx].session[i]);
2695  }
2696
2697  CDBG("%s:%d] ", __func__, __LINE__);
2698
2699#ifdef LOAD_ADSP_RPC_LIB
2700  if (NULL != my_obj->adsprpc_lib_handle) {
2701    dlclose(my_obj->adsprpc_lib_handle);
2702    my_obj->adsprpc_lib_handle = NULL;
2703  }
2704#endif
2705
2706  pthread_mutex_unlock(&my_obj->job_lock);
2707  CDBG("%s:%d] ", __func__, __LINE__);
2708
2709  /* invalidate client session */
2710  pthread_mutex_destroy(&my_obj->clnt_mgr[clnt_idx].lock);
2711  memset(&my_obj->clnt_mgr[clnt_idx], 0, sizeof(mm_jpeg_client_t));
2712
2713  rc = 0;
2714  CDBG("%s:%d] X", __func__, __LINE__);
2715  return rc;
2716}
2717
2718OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent,
2719  OMX_PTR pAppData,
2720  OMX_BUFFERHEADERTYPE *pBuffer)
2721{
2722  mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
2723
2724  CDBG_HIGH("%s:%d] count %d ", __func__, __LINE__, p_session->ebd_count);
2725  pthread_mutex_lock(&p_session->lock);
2726  p_session->ebd_count++;
2727  pthread_mutex_unlock(&p_session->lock);
2728  return 0;
2729}
2730
2731OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent,
2732  OMX_PTR pAppData,
2733  OMX_BUFFERHEADERTYPE *pBuffer)
2734{
2735  OMX_ERRORTYPE ret = OMX_ErrorNone;
2736  mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
2737  mm_jpeg_output_t output_buf;
2738  CDBG_HIGH("%s:%d] count %d ", __func__, __LINE__, p_session->fbd_count);
2739  CDBG_HIGH("[KPI Perf] : PROFILE_JPEG_FBD");
2740
2741  pthread_mutex_lock(&p_session->lock);
2742  ATRACE_INT("Camera:JPEG",
2743      (int32_t)((uint32_t)GET_SESSION_IDX(
2744        p_session->sessionId)<<16 | --p_session->job_index));
2745  if (MM_JPEG_ABORT_NONE != p_session->abort_state) {
2746    pthread_mutex_unlock(&p_session->lock);
2747    return ret;
2748  }
2749
2750  p_session->fbd_count++;
2751  if (NULL != p_session->params.jpeg_cb) {
2752
2753    p_session->job_status = JPEG_JOB_STATUS_DONE;
2754    output_buf.buf_filled_len = (uint32_t)pBuffer->nFilledLen;
2755    output_buf.buf_vaddr = pBuffer->pBuffer;
2756    output_buf.fd = 0;
2757    CDBG_HIGH("%s:%d] send jpeg callback %d buf 0x%p len %u JobID %u",
2758      __func__, __LINE__,
2759      p_session->job_status, pBuffer->pBuffer,
2760      (unsigned int)pBuffer->nFilledLen, p_session->jobId);
2761    p_session->params.jpeg_cb(p_session->job_status,
2762      p_session->client_hdl,
2763      p_session->jobId,
2764      &output_buf,
2765      p_session->params.userdata);
2766
2767    mm_jpegenc_job_done(p_session);
2768
2769  }
2770  pthread_mutex_unlock(&p_session->lock);
2771  CDBG("%s:%d] ", __func__, __LINE__);
2772
2773  return ret;
2774}
2775
2776
2777
2778OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent,
2779  OMX_PTR pAppData,
2780  OMX_EVENTTYPE eEvent,
2781  OMX_U32 nData1,
2782  OMX_U32 nData2,
2783  OMX_PTR pEventData)
2784{
2785  mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
2786
2787  CDBG("%s:%d] %d %d %d state %d", __func__, __LINE__, eEvent, (int)nData1,
2788    (int)nData2, p_session->abort_state);
2789
2790  pthread_mutex_lock(&p_session->lock);
2791
2792  if (MM_JPEG_ABORT_INIT == p_session->abort_state) {
2793    p_session->abort_state = MM_JPEG_ABORT_DONE;
2794    pthread_cond_signal(&p_session->cond);
2795    pthread_mutex_unlock(&p_session->lock);
2796    return OMX_ErrorNone;
2797  }
2798
2799  if (eEvent == OMX_EventError) {
2800    p_session->error_flag = nData2;
2801    if (p_session->encoding == OMX_TRUE) {
2802      CDBG_ERROR("%s:%d] Error during encoding", __func__, __LINE__);
2803
2804      /* send jpeg callback */
2805      if (NULL != p_session->params.jpeg_cb) {
2806        p_session->job_status = JPEG_JOB_STATUS_ERROR;
2807        CDBG_ERROR("%s:%d] send jpeg error callback %d", __func__, __LINE__,
2808          p_session->job_status);
2809        p_session->params.jpeg_cb(p_session->job_status,
2810          p_session->client_hdl,
2811          p_session->jobId,
2812          NULL,
2813          p_session->params.userdata);
2814      }
2815
2816      /* remove from ready queue */
2817      mm_jpegenc_job_done(p_session);
2818    }
2819    pthread_cond_signal(&p_session->cond);
2820  } else if (eEvent == OMX_EventCmdComplete) {
2821    if (p_session->state_change_pending == OMX_TRUE) {
2822      p_session->state_change_pending = OMX_FALSE;
2823      pthread_cond_signal(&p_session->cond);
2824    }
2825  }
2826
2827  pthread_mutex_unlock(&p_session->lock);
2828  CDBG("%s:%d]", __func__, __LINE__);
2829  return OMX_ErrorNone;
2830}
2831
2832
2833
2834/* remove the first job from the queue with matching client handle */
2835mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id(
2836  mm_jpeg_queue_t* queue, uint32_t client_hdl)
2837{
2838  mm_jpeg_q_node_t* node = NULL;
2839  mm_jpeg_job_q_node_t* data = NULL;
2840  mm_jpeg_job_q_node_t* job_node = NULL;
2841  struct cam_list *head = NULL;
2842  struct cam_list *pos = NULL;
2843
2844  pthread_mutex_lock(&queue->lock);
2845  head = &queue->head.list;
2846  pos = head->next;
2847  while(pos != head) {
2848    node = member_of(pos, mm_jpeg_q_node_t, list);
2849    data = (mm_jpeg_job_q_node_t *)node->data.p;
2850
2851    if (data && (data->enc_info.client_handle == client_hdl)) {
2852      CDBG_HIGH("%s:%d] found matching client handle", __func__, __LINE__);
2853      job_node = data;
2854      cam_list_del_node(&node->list);
2855      queue->size--;
2856      free(node);
2857      CDBG_HIGH("%s: queue size = %d", __func__, queue->size);
2858      break;
2859    }
2860    pos = pos->next;
2861  }
2862
2863  pthread_mutex_unlock(&queue->lock);
2864
2865  return job_node;
2866}
2867
2868/* remove the first job from the queue with matching session id */
2869mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_session_id(
2870  mm_jpeg_queue_t* queue, uint32_t session_id)
2871{
2872  mm_jpeg_q_node_t* node = NULL;
2873  mm_jpeg_job_q_node_t* data = NULL;
2874  mm_jpeg_job_q_node_t* job_node = NULL;
2875  struct cam_list *head = NULL;
2876  struct cam_list *pos = NULL;
2877
2878  pthread_mutex_lock(&queue->lock);
2879  head = &queue->head.list;
2880  pos = head->next;
2881  while(pos != head) {
2882    node = member_of(pos, mm_jpeg_q_node_t, list);
2883    data = (mm_jpeg_job_q_node_t *)node->data.p;
2884
2885    if (data && (data->enc_info.encode_job.session_id == session_id)) {
2886      CDBG_HIGH("%s:%d] found matching session id", __func__, __LINE__);
2887      job_node = data;
2888      cam_list_del_node(&node->list);
2889      queue->size--;
2890      free(node);
2891      CDBG_HIGH("%s: queue size = %d", __func__, queue->size);
2892      break;
2893    }
2894    pos = pos->next;
2895  }
2896
2897  pthread_mutex_unlock(&queue->lock);
2898
2899  return job_node;
2900}
2901
2902/* remove job from the queue with matching job id */
2903mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id(
2904  mm_jpeg_queue_t* queue, uint32_t job_id)
2905{
2906  mm_jpeg_q_node_t* node = NULL;
2907  mm_jpeg_job_q_node_t* data = NULL;
2908  mm_jpeg_job_q_node_t* job_node = NULL;
2909  struct cam_list *head = NULL;
2910  struct cam_list *pos = NULL;
2911  uint32_t lq_job_id;
2912
2913  pthread_mutex_lock(&queue->lock);
2914  head = &queue->head.list;
2915  pos = head->next;
2916  while(pos != head) {
2917    node = member_of(pos, mm_jpeg_q_node_t, list);
2918    data = (mm_jpeg_job_q_node_t *)node->data.p;
2919
2920    if(NULL == data) {
2921      CDBG_ERROR("%s:%d] Data is NULL", __func__, __LINE__);
2922      pthread_mutex_unlock(&queue->lock);
2923      return NULL;
2924    }
2925
2926    if (data->type == MM_JPEG_CMD_TYPE_DECODE_JOB) {
2927      lq_job_id = data->dec_info.job_id;
2928    } else {
2929      lq_job_id = data->enc_info.job_id;
2930    }
2931
2932    if (data && (lq_job_id == job_id)) {
2933      CDBG_HIGH("%s:%d] found matching job id", __func__, __LINE__);
2934      job_node = data;
2935      cam_list_del_node(&node->list);
2936      queue->size--;
2937      free(node);
2938      break;
2939    }
2940    pos = pos->next;
2941  }
2942
2943  pthread_mutex_unlock(&queue->lock);
2944
2945  return job_node;
2946}
2947
2948/* remove job from the queue with matching job id */
2949mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_unlk(
2950  mm_jpeg_queue_t* queue, uint32_t job_id)
2951{
2952  mm_jpeg_q_node_t* node = NULL;
2953  mm_jpeg_job_q_node_t* data = NULL;
2954  mm_jpeg_job_q_node_t* job_node = NULL;
2955  struct cam_list *head = NULL;
2956  struct cam_list *pos = NULL;
2957
2958  head = &queue->head.list;
2959  pos = head->next;
2960  while(pos != head) {
2961    node = member_of(pos, mm_jpeg_q_node_t, list);
2962    data = (mm_jpeg_job_q_node_t *)node->data.p;
2963
2964    if (data && (data->enc_info.job_id == job_id)) {
2965      job_node = data;
2966      cam_list_del_node(&node->list);
2967      queue->size--;
2968      free(node);
2969      break;
2970    }
2971    pos = pos->next;
2972  }
2973
2974  return job_node;
2975}
2976