Home | History | Annotate | Download | only in HAL3
      1 /* Copyright (c) 2012-2015, The Linux Foundataion. 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 #define ATRACE_TAG ATRACE_TAG_CAMERA
     30 
     31 #define LOG_TAG "QCamera3PostProc"
     32 //#define LOG_NDEBUG 0
     33 
     34 #include <stdlib.h>
     35 #include <utils/Errors.h>
     36 #include <utils/Trace.h>
     37 #include <cutils/properties.h>
     38 
     39 #include "QCamera3PostProc.h"
     40 #include "QCamera3HWI.h"
     41 #include "QCamera3Channel.h"
     42 #include "QCamera3Stream.h"
     43 
     44 namespace qcamera {
     45 
     46 static const char ExifAsciiPrefix[] =
     47     { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };          // "ASCII\0\0\0"
     48 static const char ExifUndefinedPrefix[] =
     49     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };   // "\0\0\0\0\0\0\0\0"
     50 
     51 #define EXIF_ASCII_PREFIX_SIZE           8   //(sizeof(ExifAsciiPrefix))
     52 #define FOCAL_LENGTH_DECIMAL_PRECISION   1000
     53 
     54 /*===========================================================================
     55  * FUNCTION   : QCamera3PostProcessor
     56  *
     57  * DESCRIPTION: constructor of QCamera3PostProcessor.
     58  *
     59  * PARAMETERS :
     60  *   @cam_ctrl : ptr to HWI object
     61  *
     62  * RETURN     : None
     63  *==========================================================================*/
     64 QCamera3PostProcessor::QCamera3PostProcessor(QCamera3ProcessingChannel* ch_ctrl)
     65     : m_parent(ch_ctrl),
     66       mJpegCB(NULL),
     67       mJpegUserData(NULL),
     68       mJpegClientHandle(0),
     69       mJpegSessionId(0),
     70       m_bThumbnailNeeded(TRUE),
     71       m_pReprocChannel(NULL),
     72       m_inputPPQ(releasePPInputData, this),
     73       m_inputFWKPPQ(NULL, this),
     74       m_ongoingPPQ(releaseOngoingPPData, this),
     75       m_inputJpegQ(releaseJpegData, this),
     76       m_ongoingJpegQ(releaseJpegData, this),
     77       m_inputMetaQ(releaseMetadata, this),
     78       m_jpegSettingsQ(NULL, this)
     79 {
     80     memset(&mJpegHandle, 0, sizeof(mJpegHandle));
     81     pthread_mutex_init(&mReprocJobLock, NULL);
     82 }
     83 
     84 /*===========================================================================
     85  * FUNCTION   : ~QCamera3PostProcessor
     86  *
     87  * DESCRIPTION: deconstructor of QCamera3PostProcessor.
     88  *
     89  * PARAMETERS : None
     90  *
     91  * RETURN     : None
     92  *==========================================================================*/
     93 QCamera3PostProcessor::~QCamera3PostProcessor()
     94 {
     95     pthread_mutex_destroy(&mReprocJobLock);
     96 }
     97 
     98 /*===========================================================================
     99  * FUNCTION   : init
    100  *
    101  * DESCRIPTION: initialization of postprocessor
    102  *
    103  * PARAMETERS :
    104  *   @memory              : output buffer memory
    105  *   @postprocess_mask    : postprocess mask for the buffer
    106  *
    107  * RETURN     : int32_t type of status
    108  *              NO_ERROR  -- success
    109  *              none-zero failure code
    110  *==========================================================================*/
    111 int32_t QCamera3PostProcessor::init(QCamera3StreamMem *memory,
    112         uint32_t postprocess_mask)
    113 {
    114     ATRACE_CALL();
    115     mOutputMem = memory;
    116     mPostProcMask = postprocess_mask;
    117     m_dataProcTh.launch(dataProcessRoutine, this);
    118 
    119     return NO_ERROR;
    120 }
    121 
    122 /*===========================================================================
    123  * FUNCTION   : deinit
    124  *
    125  * DESCRIPTION: de-initialization of postprocessor
    126  *
    127  * PARAMETERS : None
    128  *
    129  * RETURN     : int32_t type of status
    130  *              NO_ERROR  -- success
    131  *              none-zero failure code
    132  *==========================================================================*/
    133 int32_t QCamera3PostProcessor::deinit()
    134 {
    135     int rc = NO_ERROR;
    136     m_dataProcTh.exit();
    137 
    138     if (m_pReprocChannel != NULL) {
    139         m_pReprocChannel->stop();
    140         delete m_pReprocChannel;
    141         m_pReprocChannel = NULL;
    142     }
    143 
    144     if(mJpegClientHandle > 0) {
    145         rc = mJpegHandle.close(mJpegClientHandle);
    146         CDBG_HIGH("%s: Jpeg closed, rc = %d, mJpegClientHandle = %x",
    147               __func__, rc, mJpegClientHandle);
    148         mJpegClientHandle = 0;
    149         memset(&mJpegHandle, 0, sizeof(mJpegHandle));
    150     }
    151 
    152     mOutputMem = NULL;
    153     return rc;
    154 }
    155 
    156 /*===========================================================================
    157  * FUNCTION   : initJpeg
    158  *
    159  * DESCRIPTION: initialization of jpeg through postprocessor
    160  *
    161  * PARAMETERS :
    162  *   @jpeg_cb      : callback to handle jpeg event from mm-camera-interface
    163  *   @max_pic_dim  : max picture dimensions
    164  *   @user_data    : user data ptr for jpeg callback
    165  *
    166  * RETURN     : int32_t type of status
    167  *              NO_ERROR  -- success
    168  *              none-zero failure code
    169  *==========================================================================*/
    170 int32_t QCamera3PostProcessor::initJpeg(jpeg_encode_callback_t jpeg_cb,
    171         cam_dimension_t* max_pic_dim,
    172         void *user_data)
    173 {
    174     ATRACE_CALL();
    175     mJpegCB = jpeg_cb;
    176     mJpegUserData = user_data;
    177     mm_dimension max_size;
    178 
    179     if ((0 > max_pic_dim->width) || (0 > max_pic_dim->height)) {
    180         ALOGE("%s : Negative dimension %dx%d", __func__,
    181                 max_pic_dim->width, max_pic_dim->height);
    182         return BAD_VALUE;
    183     }
    184 
    185     //set max pic size
    186     memset(&max_size, 0, sizeof(mm_dimension));
    187     max_size.w =  max_pic_dim->width;
    188     max_size.h =  max_pic_dim->height;
    189 
    190     mJpegClientHandle = jpeg_open(&mJpegHandle, max_size);
    191     if(!mJpegClientHandle) {
    192         ALOGE("%s : jpeg_open did not work", __func__);
    193         return UNKNOWN_ERROR;
    194     }
    195     return NO_ERROR;
    196 }
    197 
    198 /*===========================================================================
    199  * FUNCTION   : start
    200  *
    201  * DESCRIPTION: start postprocessor. Data process thread and data notify thread
    202  *              will be launched.
    203  *
    204  * PARAMETERS :
    205  *   @config        : reprocess configuration
    206  *
    207  * RETURN     : int32_t type of status
    208  *              NO_ERROR  -- success
    209  *              none-zero failure code
    210  *
    211  * NOTE       : if any reprocess is needed, a reprocess channel/stream
    212  *              will be started.
    213  *==========================================================================*/
    214 int32_t QCamera3PostProcessor::start(const reprocess_config_t &config)
    215 {
    216     int32_t rc = NO_ERROR;
    217     QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
    218 
    219     if (config.reprocess_type != REPROCESS_TYPE_NONE) {
    220         if (m_pReprocChannel != NULL) {
    221             m_pReprocChannel->stop();
    222             delete m_pReprocChannel;
    223             m_pReprocChannel = NULL;
    224         }
    225 
    226         // if reprocess is needed, start reprocess channel
    227         CDBG("%s: Setting input channel as pInputChannel", __func__);
    228         m_pReprocChannel = hal_obj->addOfflineReprocChannel(config, m_parent);
    229         if (m_pReprocChannel == NULL) {
    230             ALOGE("%s: cannot add reprocess channel", __func__);
    231             return UNKNOWN_ERROR;
    232         }
    233         /*start the reprocess channel only if buffers are already allocated, thus
    234           only start it in an intermediate reprocess type, defer it for others*/
    235         if (config.reprocess_type == REPROCESS_TYPE_JPEG) {
    236             rc = m_pReprocChannel->start();
    237             if (rc != 0) {
    238                 ALOGE("%s: cannot start reprocess channel", __func__);
    239                 delete m_pReprocChannel;
    240                 m_pReprocChannel = NULL;
    241                 return rc;
    242             }
    243         }
    244     }
    245     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, TRUE, FALSE);
    246 
    247     return rc;
    248 }
    249 
    250 /*===========================================================================
    251  * FUNCTION   : stop
    252  *
    253  * DESCRIPTION: stop postprocessor. Data process and notify thread will be stopped.
    254  *
    255  * PARAMETERS : None
    256  *
    257  * RETURN     : int32_t type of status
    258  *              NO_ERROR  -- success
    259  *              none-zero failure code
    260  *
    261  * NOTE       : reprocess channel will be stopped and deleted if there is any
    262  *==========================================================================*/
    263 int32_t QCamera3PostProcessor::stop()
    264 {
    265     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE);
    266 
    267     if (m_pReprocChannel != NULL) {
    268         m_pReprocChannel->stop();
    269         delete m_pReprocChannel;
    270         m_pReprocChannel = NULL;
    271     }
    272 
    273     return NO_ERROR;
    274 }
    275 
    276 /*===========================================================================
    277  * FUNCTION   : getFWKJpegEncodeConfig
    278  *
    279  * DESCRIPTION: function to prepare encoding job information
    280  *
    281  * PARAMETERS :
    282  *   @encode_parm   : param to be filled with encoding configuration
    283  *   @frame         : framework input buffer
    284  *   @jpeg_settings : jpeg settings to be applied for encoding
    285  *
    286  * RETURN     : int32_t type of status
    287  *              NO_ERROR  -- success
    288  *              none-zero failure code
    289  *==========================================================================*/
    290 int32_t QCamera3PostProcessor::getFWKJpegEncodeConfig(
    291         mm_jpeg_encode_params_t& encode_parm,
    292         qcamera_fwk_input_pp_data_t *frame,
    293         jpeg_settings_t *jpeg_settings)
    294 {
    295     CDBG("%s : E", __func__);
    296     int32_t ret = NO_ERROR;
    297 
    298     if ((NULL == frame) || (NULL == jpeg_settings)) {
    299         return BAD_VALUE;
    300     }
    301 
    302     ssize_t bufSize = mOutputMem->getSize(jpeg_settings->out_buf_index);
    303     if (BAD_INDEX == bufSize) {
    304         ALOGE("%s: cannot retrieve buffer size for buffer %u", __func__,
    305                 jpeg_settings->out_buf_index);
    306         return BAD_VALUE;
    307     }
    308 
    309     encode_parm.jpeg_cb = mJpegCB;
    310     encode_parm.userdata = mJpegUserData;
    311 
    312     if (jpeg_settings->thumbnail_size.width > 0 &&
    313             jpeg_settings->thumbnail_size.height > 0)
    314         m_bThumbnailNeeded = TRUE;
    315     else
    316         m_bThumbnailNeeded = FALSE;
    317     encode_parm.encode_thumbnail = m_bThumbnailNeeded;
    318 
    319     // get color format
    320     cam_format_t img_fmt = frame->reproc_config.stream_format;
    321     encode_parm.color_format = getColorfmtFromImgFmt(img_fmt);
    322 
    323     // get jpeg quality
    324     encode_parm.quality = jpeg_settings->jpeg_quality;
    325     if (encode_parm.quality <= 0) {
    326         encode_parm.quality = 85;
    327     }
    328 
    329     // get jpeg thumbnail quality
    330     encode_parm.thumb_quality = jpeg_settings->jpeg_thumb_quality;
    331 
    332     cam_frame_len_offset_t main_offset =
    333             frame->reproc_config.input_stream_plane_info.plane_info;
    334 
    335     encode_parm.num_src_bufs = 1;
    336     encode_parm.src_main_buf[0].index = 0;
    337     encode_parm.src_main_buf[0].buf_size = frame->input_buffer.frame_len;
    338     encode_parm.src_main_buf[0].buf_vaddr = (uint8_t *) frame->input_buffer.buffer;
    339     encode_parm.src_main_buf[0].fd = frame->input_buffer.fd;
    340     encode_parm.src_main_buf[0].format = MM_JPEG_FMT_YUV;
    341     encode_parm.src_main_buf[0].offset = main_offset;
    342 
    343     //Pass input thumbnail buffer info to encoder.
    344     //Note: Use main buffer to encode thumbnail
    345     if (m_bThumbnailNeeded == TRUE) {
    346         encode_parm.num_tmb_bufs = 1;
    347         encode_parm.src_thumb_buf[0] = encode_parm.src_main_buf[0];
    348     }
    349 
    350     //Pass output jpeg buffer info to encoder.
    351     //mOutputMem is allocated by framework.
    352     encode_parm.num_dst_bufs = 1;
    353     encode_parm.dest_buf[0].index = 0;
    354     encode_parm.dest_buf[0].buf_size = (size_t)bufSize;
    355     encode_parm.dest_buf[0].buf_vaddr = (uint8_t *)mOutputMem->getPtr(
    356             jpeg_settings->out_buf_index);
    357     encode_parm.dest_buf[0].fd = mOutputMem->getFd(
    358             jpeg_settings->out_buf_index);
    359     encode_parm.dest_buf[0].format = MM_JPEG_FMT_YUV;
    360     encode_parm.dest_buf[0].offset = main_offset;
    361 
    362     CDBG("%s : X", __func__);
    363     return NO_ERROR;
    364 
    365 on_error:
    366     CDBG("%s : X with error %d", __func__, ret);
    367     return ret;
    368 }
    369 
    370 /*===========================================================================
    371  * FUNCTION   : getJpegEncodeConfig
    372  *
    373  * DESCRIPTION: function to prepare encoding job information
    374  *
    375  * PARAMETERS :
    376  *   @encode_parm   : param to be filled with encoding configuration
    377  *   #main_stream   : stream object where the input buffer comes from
    378  *   @jpeg_settings : jpeg settings to be applied for encoding
    379  *
    380  * RETURN     : int32_t type of status
    381  *              NO_ERROR  -- success
    382  *              none-zero failure code
    383  *==========================================================================*/
    384 int32_t QCamera3PostProcessor::getJpegEncodeConfig(
    385                 mm_jpeg_encode_params_t& encode_parm,
    386                 QCamera3Stream *main_stream,
    387                 jpeg_settings_t *jpeg_settings)
    388 {
    389     CDBG("%s : E", __func__);
    390     int32_t ret = NO_ERROR;
    391     ssize_t bufSize = 0;
    392 
    393     encode_parm.jpeg_cb = mJpegCB;
    394     encode_parm.userdata = mJpegUserData;
    395 
    396     if (jpeg_settings->thumbnail_size.width > 0 &&
    397             jpeg_settings->thumbnail_size.height > 0)
    398         m_bThumbnailNeeded = TRUE;
    399     else
    400         m_bThumbnailNeeded = FALSE;
    401     encode_parm.encode_thumbnail = m_bThumbnailNeeded;
    402 
    403     // get color format
    404     cam_format_t img_fmt = CAM_FORMAT_YUV_420_NV12;  //default value
    405     main_stream->getFormat(img_fmt);
    406     encode_parm.color_format = getColorfmtFromImgFmt(img_fmt);
    407 
    408     // get jpeg quality
    409     encode_parm.quality = jpeg_settings->jpeg_quality;
    410     if (encode_parm.quality <= 0) {
    411         encode_parm.quality = 85;
    412     }
    413 
    414     // get jpeg thumbnail quality
    415     encode_parm.thumb_quality = jpeg_settings->jpeg_thumb_quality;
    416 
    417     cam_frame_len_offset_t main_offset;
    418     memset(&main_offset, 0, sizeof(cam_frame_len_offset_t));
    419     main_stream->getFrameOffset(main_offset);
    420 
    421     // src buf config
    422     //Pass input main image buffer info to encoder.
    423     QCamera3StreamMem *pStreamMem = main_stream->getStreamBufs();
    424     if (pStreamMem == NULL) {
    425         ALOGE("%s: cannot get stream bufs from main stream", __func__);
    426         ret = BAD_VALUE;
    427         goto on_error;
    428     }
    429     encode_parm.num_src_bufs = MIN(pStreamMem->getCnt(), MM_JPEG_MAX_BUF);
    430     for (uint32_t i = 0; i < encode_parm.num_src_bufs; i++) {
    431         if (pStreamMem != NULL) {
    432             encode_parm.src_main_buf[i].index = i;
    433             bufSize = pStreamMem->getSize(i);
    434             if (BAD_INDEX == bufSize) {
    435                 ALOGE("%s: cannot retrieve buffer size for buffer %u", __func__, i);
    436                 ret = BAD_VALUE;
    437                 goto on_error;
    438             }
    439             encode_parm.src_main_buf[i].buf_size = (size_t)bufSize;
    440             encode_parm.src_main_buf[i].buf_vaddr = (uint8_t *)pStreamMem->getPtr(i);
    441             encode_parm.src_main_buf[i].fd = pStreamMem->getFd(i);
    442             encode_parm.src_main_buf[i].format = MM_JPEG_FMT_YUV;
    443             encode_parm.src_main_buf[i].offset = main_offset;
    444         }
    445     }
    446 
    447     //Pass input thumbnail buffer info to encoder.
    448     //Note: Use main buffer to encode thumbnail
    449     if (m_bThumbnailNeeded == TRUE) {
    450         pStreamMem = main_stream->getStreamBufs();
    451         if (pStreamMem == NULL) {
    452             ALOGE("%s: cannot get stream bufs from thumb stream", __func__);
    453             ret = BAD_VALUE;
    454             goto on_error;
    455         }
    456         cam_frame_len_offset_t thumb_offset;
    457         memset(&thumb_offset, 0, sizeof(cam_frame_len_offset_t));
    458         main_stream->getFrameOffset(thumb_offset);
    459         encode_parm.num_tmb_bufs = MIN(pStreamMem->getCnt(), MM_JPEG_MAX_BUF);
    460         for (uint32_t i = 0; i < encode_parm.num_tmb_bufs; i++) {
    461             if (pStreamMem != NULL) {
    462                 encode_parm.src_thumb_buf[i].index = i;
    463                 bufSize = pStreamMem->getSize(i);
    464                 if (BAD_INDEX == bufSize) {
    465                     ALOGE("%s: cannot retrieve buffer size for buffer %u", __func__, i);
    466                     ret = BAD_VALUE;
    467                     goto on_error;
    468                 }
    469                 encode_parm.src_thumb_buf[i].buf_size = (uint32_t)bufSize;
    470                 encode_parm.src_thumb_buf[i].buf_vaddr = (uint8_t *)pStreamMem->getPtr(i);
    471                 encode_parm.src_thumb_buf[i].fd = pStreamMem->getFd(i);
    472                 encode_parm.src_thumb_buf[i].format = MM_JPEG_FMT_YUV;
    473                 encode_parm.src_thumb_buf[i].offset = thumb_offset;
    474             }
    475         }
    476     }
    477 
    478     //Pass output jpeg buffer info to encoder.
    479     //mJpegMem is allocated by framework.
    480     bufSize = mOutputMem->getSize(jpeg_settings->out_buf_index);
    481     if (BAD_INDEX == bufSize) {
    482         ALOGE("%s: cannot retrieve buffer size for buffer %u", __func__,
    483                 jpeg_settings->out_buf_index);
    484         ret = BAD_VALUE;
    485         goto on_error;
    486     }
    487     encode_parm.num_dst_bufs = 1;
    488     encode_parm.dest_buf[0].index = 0;
    489     encode_parm.dest_buf[0].buf_size = (size_t)bufSize;
    490     encode_parm.dest_buf[0].buf_vaddr = (uint8_t *)mOutputMem->getPtr(
    491             jpeg_settings->out_buf_index);
    492     encode_parm.dest_buf[0].fd = mOutputMem->getFd(
    493             jpeg_settings->out_buf_index);
    494     encode_parm.dest_buf[0].format = MM_JPEG_FMT_YUV;
    495     encode_parm.dest_buf[0].offset = main_offset;
    496 
    497     CDBG("%s : X", __func__);
    498     return NO_ERROR;
    499 
    500 on_error:
    501     CDBG("%s : X with error %d", __func__, ret);
    502     return ret;
    503 }
    504 
    505 int32_t QCamera3PostProcessor::processData(mm_camera_super_buf_t *input) {
    506     return processData(input, NULL, 0);
    507 }
    508 
    509 /*===========================================================================
    510  * FUNCTION   : processData
    511  *
    512  * DESCRIPTION: enqueue data into dataProc thread
    513  *
    514  * PARAMETERS :
    515  *   @frame   : process input frame
    516  *   @output  : process output frame
    517  *
    518  * RETURN     : int32_t type of status
    519  *              NO_ERROR  -- success
    520  *              none-zero failure code
    521  *
    522  * NOTE       : depends on if offline reprocess is needed, received frame will
    523  *              be sent to either input queue of postprocess or jpeg encoding
    524  *==========================================================================*/
    525 int32_t QCamera3PostProcessor::processData(mm_camera_super_buf_t *input,
    526         buffer_handle_t *output, uint32_t frameNumber)
    527 {
    528     CDBG("%s: E", __func__);
    529     QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
    530     pthread_mutex_lock(&mReprocJobLock);
    531 
    532     // enqueue to post proc input queue
    533     qcamera_hal3_pp_buffer_t *pp_buffer = (qcamera_hal3_pp_buffer_t *)malloc(
    534             sizeof(qcamera_hal3_pp_buffer_t));
    535     if (NULL == pp_buffer) {
    536         ALOGE("%s: out of memory", __func__);
    537         return NO_MEMORY;
    538     }
    539     memset(pp_buffer, 0, sizeof(*pp_buffer));
    540     pp_buffer->input = input;
    541     pp_buffer->output = output;
    542     pp_buffer->frameNumber = frameNumber;
    543     m_inputPPQ.enqueue((void *)pp_buffer);
    544     if (!(m_inputMetaQ.isEmpty())) {
    545         CDBG("%s: meta queue is not empty, do next job", __func__);
    546         m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
    547     } else
    548         CDBG("%s: metadata queue is empty", __func__);
    549     pthread_mutex_unlock(&mReprocJobLock);
    550 
    551     return NO_ERROR;
    552 }
    553 
    554 /*===========================================================================
    555  * FUNCTION   : processData
    556  *
    557  * DESCRIPTION: enqueue data into dataProc thread
    558  *
    559  * PARAMETERS :
    560  *   @frame   : process frame
    561  *
    562  * RETURN     : int32_t type of status
    563  *              NO_ERROR  -- success
    564  *              none-zero failure code
    565  *
    566  * NOTE       : depends on if offline reprocess is needed, received frame will
    567  *              be sent to either input queue of postprocess or jpeg encoding
    568  *==========================================================================*/
    569 int32_t QCamera3PostProcessor::processData(qcamera_fwk_input_pp_data_t *frame)
    570 {
    571     QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
    572     if (frame->reproc_config.reprocess_type != REPROCESS_TYPE_NONE) {
    573         pthread_mutex_lock(&mReprocJobLock);
    574         // enqueu to post proc input queue
    575         m_inputFWKPPQ.enqueue((void *)frame);
    576         m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
    577         pthread_mutex_unlock(&mReprocJobLock);
    578     } else {
    579         jpeg_settings_t *jpeg_settings = (jpeg_settings_t *)m_jpegSettingsQ.dequeue();
    580 
    581         if (jpeg_settings == NULL) {
    582             ALOGE("%s: Cannot find jpeg settings", __func__);
    583             return BAD_VALUE;
    584         }
    585 
    586         CDBG_HIGH("%s: no need offline reprocess, sending to jpeg encoding", __func__);
    587         qcamera_hal3_jpeg_data_t *jpeg_job =
    588             (qcamera_hal3_jpeg_data_t *)malloc(sizeof(qcamera_hal3_jpeg_data_t));
    589         if (jpeg_job == NULL) {
    590             ALOGE("%s: No memory for jpeg job", __func__);
    591             return NO_MEMORY;
    592         }
    593 
    594         memset(jpeg_job, 0, sizeof(qcamera_hal3_jpeg_data_t));
    595         jpeg_job->fwk_frame = frame;
    596         jpeg_job->jpeg_settings = jpeg_settings;
    597         jpeg_job->metadata =
    598                 (metadata_buffer_t *) frame->metadata_buffer.buffer;
    599 
    600         // enqueu to jpeg input queue
    601         m_inputJpegQ.enqueue((void *)jpeg_job);
    602         m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
    603     }
    604 
    605     return NO_ERROR;
    606 }
    607 
    608 /*===========================================================================
    609  * FUNCTION   : processPPMetadata
    610  *
    611  * DESCRIPTION: enqueue data into dataProc thread
    612  *
    613  * PARAMETERS :
    614  *   @frame   : process metadata frame received from pic channel
    615  *
    616  * RETURN     : int32_t type of status
    617  *              NO_ERROR  -- success
    618  *              none-zero failure code
    619  *
    620  *==========================================================================*/
    621 int32_t QCamera3PostProcessor::processPPMetadata(mm_camera_super_buf_t *reproc_meta)
    622 {
    623     CDBG("%s: E", __func__);
    624     pthread_mutex_lock(&mReprocJobLock);
    625     // enqueue to metadata input queue
    626     m_inputMetaQ.enqueue((void *)reproc_meta);
    627     if (!(m_inputPPQ.isEmpty())) {
    628        CDBG("%s: pp queue is not empty, do next job", __func__);
    629        m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
    630     } else {
    631        CDBG("%s: pp queue is empty, not calling do next job", __func__);
    632     }
    633     pthread_mutex_unlock(&mReprocJobLock);
    634     return NO_ERROR;
    635 }
    636 
    637 /*===========================================================================
    638  * FUNCTION   : processJpegSettingData
    639  *
    640  * DESCRIPTION: enqueue jpegSetting into dataProc thread
    641  *
    642  * PARAMETERS :
    643  *   @jpeg_settings : jpeg settings data received from pic channel
    644  *
    645  * RETURN     : int32_t type of status
    646  *              NO_ERROR  -- success
    647  *              none-zero failure code
    648  *
    649  *==========================================================================*/
    650 int32_t QCamera3PostProcessor::processJpegSettingData(
    651         jpeg_settings_t *jpeg_settings)
    652 {
    653     if (!jpeg_settings) {
    654         ALOGE("%s: invalid jpeg settings pointer", __func__);
    655         return -EINVAL;
    656     }
    657     return m_jpegSettingsQ.enqueue((void *)jpeg_settings);
    658 }
    659 
    660 /*===========================================================================
    661  * FUNCTION   : processPPData
    662  *
    663  * DESCRIPTION: process received frame after reprocess.
    664  *
    665  * PARAMETERS :
    666  *   @frame   : received frame from reprocess channel.
    667  *
    668  * RETURN     : int32_t type of status
    669  *              NO_ERROR  -- success
    670  *              none-zero failure code
    671  *
    672  * NOTE       : The frame after reprocess need to send to jpeg encoding.
    673  *==========================================================================*/
    674 int32_t QCamera3PostProcessor::processPPData(mm_camera_super_buf_t *frame)
    675 {
    676     qcamera_hal3_pp_data_t *job = (qcamera_hal3_pp_data_t *)m_ongoingPPQ.dequeue();
    677 
    678     if (job == NULL || ((NULL == job->src_frame) && (NULL == job->fwk_src_frame))) {
    679         ALOGE("%s: Cannot find reprocess job", __func__);
    680         return BAD_VALUE;
    681     }
    682     if (job->jpeg_settings == NULL) {
    683         ALOGE("%s: Cannot find jpeg settings", __func__);
    684         return BAD_VALUE;
    685     }
    686 
    687     qcamera_hal3_jpeg_data_t *jpeg_job =
    688         (qcamera_hal3_jpeg_data_t *)malloc(sizeof(qcamera_hal3_jpeg_data_t));
    689     if (jpeg_job == NULL) {
    690         ALOGE("%s: No memory for jpeg job", __func__);
    691         return NO_MEMORY;
    692     }
    693 
    694     memset(jpeg_job, 0, sizeof(qcamera_hal3_jpeg_data_t));
    695     jpeg_job->src_frame = frame;
    696     if(frame != job->src_frame)
    697         jpeg_job->src_reproc_frame = job->src_frame;
    698     if (NULL == job->fwk_src_frame) {
    699         jpeg_job->metadata = job->metadata;
    700     } else {
    701         jpeg_job->metadata =
    702                 (metadata_buffer_t *) job->fwk_src_frame->metadata_buffer.buffer;
    703         jpeg_job->fwk_src_buffer = job->fwk_src_frame;
    704     }
    705     jpeg_job->src_metadata = job->src_metadata;
    706     jpeg_job->jpeg_settings = job->jpeg_settings;
    707 
    708     // free pp job buf
    709     free(job);
    710 
    711     // enqueu reprocessed frame to jpeg input queue
    712     m_inputJpegQ.enqueue((void *)jpeg_job);
    713 
    714     // wait up data proc thread
    715     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
    716 
    717     return NO_ERROR;
    718 }
    719 
    720 /*===========================================================================
    721  * FUNCTION   : dequeuePPJob
    722  *
    723  * DESCRIPTION: find a postprocessing job from ongoing pp queue by frame number
    724  *
    725  * PARAMETERS :
    726  *   @frameNumber : frame number for the pp job
    727  *
    728  * RETURN     : ptr to a pp job struct. NULL if not found.
    729  *==========================================================================*/
    730 qcamera_hal3_pp_data_t *QCamera3PostProcessor::dequeuePPJob(uint32_t frameNumber) {
    731     qcamera_hal3_pp_data_t *pp_job = NULL;
    732     pp_job = (qcamera_hal3_pp_data_t *)m_ongoingPPQ.dequeue();
    733 
    734     if (pp_job == NULL) {
    735         ALOGE("%s: Fatal: ongoing PP queue is empty", __func__);
    736         return NULL;
    737     }
    738     if (pp_job->fwk_src_frame &&
    739             (pp_job->fwk_src_frame->frameNumber != frameNumber)) {
    740         ALOGE("%s: head of pp queue doesn't match requested frame number", __func__);
    741     }
    742     return pp_job;
    743 }
    744 
    745 /*===========================================================================
    746  * FUNCTION   : findJpegJobByJobId
    747  *
    748  * DESCRIPTION: find a jpeg job from ongoing Jpeg queue by its job ID
    749  *
    750  * PARAMETERS :
    751  *   @jobId   : job Id of the job
    752  *
    753  * RETURN     : ptr to a jpeg job struct. NULL if not found.
    754  *
    755  * NOTE       : Currently only one job is sending to mm-jpeg-interface for jpeg
    756  *              encoding. Therefore simply dequeue from the ongoing Jpeg Queue
    757  *              will serve the purpose to find the jpeg job.
    758  *==========================================================================*/
    759 qcamera_hal3_jpeg_data_t *QCamera3PostProcessor::findJpegJobByJobId(uint32_t jobId)
    760 {
    761     qcamera_hal3_jpeg_data_t * job = NULL;
    762     if (jobId == 0) {
    763         ALOGE("%s: not a valid jpeg jobId", __func__);
    764         return NULL;
    765     }
    766 
    767     // currely only one jpeg job ongoing, so simply dequeue the head
    768     job = (qcamera_hal3_jpeg_data_t *)m_ongoingJpegQ.dequeue();
    769     return job;
    770 }
    771 
    772 /*===========================================================================
    773  * FUNCTION   : releasePPInputData
    774  *
    775  * DESCRIPTION: callback function to release post process input data node
    776  *
    777  * PARAMETERS :
    778  *   @data      : ptr to post process input data
    779  *   @user_data : user data ptr (QCamera3Reprocessor)
    780  *
    781  * RETURN     : None
    782  *==========================================================================*/
    783 void QCamera3PostProcessor::releasePPInputData(void *data, void *user_data)
    784 {
    785     QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data;
    786     if (NULL != pme) {
    787         qcamera_hal3_pp_buffer_t *buf = (qcamera_hal3_pp_buffer_t *)data;
    788         if (NULL != buf) {
    789             if (buf->input) {
    790                 pme->releaseSuperBuf(buf->input);
    791                 free(buf->input);
    792                 buf->input = NULL;
    793             }
    794         }
    795     }
    796 }
    797 
    798 /*===========================================================================
    799  * FUNCTION   : releaseMetaData
    800  *
    801  * DESCRIPTION: callback function to release metadata camera buffer
    802  *
    803  * PARAMETERS :
    804  *   @data      : ptr to post process input data
    805  *   @user_data : user data ptr (QCamera3Reprocessor)
    806  *
    807  * RETURN     : None
    808  *==========================================================================*/
    809 void QCamera3PostProcessor::releaseMetadata(void *data, void *user_data)
    810 {
    811     QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data;
    812     if (NULL != pme) {
    813         pme->m_parent->metadataBufDone((mm_camera_super_buf_t *)data);
    814     }
    815 }
    816 
    817 /*===========================================================================
    818  * FUNCTION   : releaseJpegData
    819  *
    820  * DESCRIPTION: callback function to release jpeg job node
    821  *
    822  * PARAMETERS :
    823  *   @data      : ptr to ongoing jpeg job data
    824  *   @user_data : user data ptr (QCamera3Reprocessor)
    825  *
    826  * RETURN     : None
    827  *==========================================================================*/
    828 void QCamera3PostProcessor::releaseJpegData(void *data, void *user_data)
    829 {
    830     QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data;
    831     if (NULL != pme) {
    832         pme->releaseJpegJobData((qcamera_hal3_jpeg_data_t *)data);
    833     }
    834 }
    835 
    836 /*===========================================================================
    837  * FUNCTION   : releaseOngoingPPData
    838  *
    839  * DESCRIPTION: callback function to release ongoing postprocess job node
    840  *
    841  * PARAMETERS :
    842  *   @data      : ptr to onging postprocess job
    843  *   @user_data : user data ptr (QCamera3Reprocessor)
    844  *
    845  * RETURN     : None
    846  *==========================================================================*/
    847 void QCamera3PostProcessor::releaseOngoingPPData(void *data, void *user_data)
    848 {
    849     QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data;
    850     if (NULL != pme) {
    851         qcamera_hal3_pp_data_t *pp_data = (qcamera_hal3_pp_data_t *)data;
    852 
    853         if (pp_data && pp_data->src_frame)
    854           pme->releaseSuperBuf(pp_data->src_frame);
    855 
    856         pme->releasePPJobData(pp_data);
    857 
    858     }
    859 }
    860 
    861 /*===========================================================================
    862  * FUNCTION   : releaseSuperBuf
    863  *
    864  * DESCRIPTION: function to release a superbuf frame by returning back to kernel
    865  *
    866  * PARAMETERS :
    867  *   @super_buf : ptr to the superbuf frame
    868  *
    869  * RETURN     : None
    870  *==========================================================================*/
    871 void QCamera3PostProcessor::releaseSuperBuf(mm_camera_super_buf_t *super_buf)
    872 {
    873     if (NULL != super_buf) {
    874         if (m_parent != NULL) {
    875             m_parent->bufDone(super_buf);
    876         }
    877     }
    878 }
    879 
    880 /*===========================================================================
    881  * FUNCTION   : releaseOfflineBuffers
    882  *
    883  * DESCRIPTION: function to release/unmap offline buffers if any
    884  *
    885  * PARAMETERS : None
    886  *
    887  * RETURN     : int32_t type of status
    888  *              NO_ERROR  -- success
    889  *              none-zero failure code
    890  *==========================================================================*/
    891 int32_t QCamera3PostProcessor::releaseOfflineBuffers()
    892 {
    893     int32_t rc = NO_ERROR;
    894 
    895     if(NULL != m_pReprocChannel) {
    896         rc = m_pReprocChannel->unmapOfflineBuffers(false);
    897     }
    898 
    899     return rc;
    900 }
    901 
    902 /*===========================================================================
    903  * FUNCTION   : releaseJpegJobData
    904  *
    905  * DESCRIPTION: function to release internal resources in jpeg job struct
    906  *
    907  * PARAMETERS :
    908  *   @job     : ptr to jpeg job struct
    909  *
    910  * RETURN     : None
    911  *
    912  * NOTE       : original source frame need to be queued back to kernel for
    913  *              future use. Output buf of jpeg job need to be released since
    914  *              it's allocated for each job. Exif object need to be deleted.
    915  *==========================================================================*/
    916 void QCamera3PostProcessor::releaseJpegJobData(qcamera_hal3_jpeg_data_t *job)
    917 {
    918     ATRACE_CALL();
    919     int32_t rc = NO_ERROR;
    920     CDBG("%s: E", __func__);
    921     if (NULL != job) {
    922         if (NULL != job->src_reproc_frame) {
    923             free(job->src_reproc_frame);
    924             job->src_reproc_frame = NULL;
    925         }
    926 
    927         if (NULL != job->src_frame) {
    928             if (NULL != m_pReprocChannel) {
    929                 rc = m_pReprocChannel->bufDone(job->src_frame);
    930                 if (NO_ERROR != rc)
    931                     ALOGE("%s: bufDone error: %d", __func__, rc);
    932             }
    933             free(job->src_frame);
    934             job->src_frame = NULL;
    935         }
    936 
    937         if (NULL != job->fwk_src_buffer) {
    938             free(job->fwk_src_buffer);
    939             job->fwk_src_buffer = NULL;
    940         } else if (NULL != job->src_metadata) {
    941             m_parent->metadataBufDone(job->src_metadata);
    942             free(job->src_metadata);
    943             job->src_metadata = NULL;
    944         }
    945 
    946         if (NULL != job->fwk_frame) {
    947             free(job->fwk_frame);
    948             job->fwk_frame = NULL;
    949         }
    950 
    951         if (NULL != job->pJpegExifObj) {
    952             delete job->pJpegExifObj;
    953             job->pJpegExifObj = NULL;
    954         }
    955 
    956         if (NULL != job->jpeg_settings) {
    957             free(job->jpeg_settings);
    958             job->jpeg_settings = NULL;
    959         }
    960     }
    961     /* Additional trigger to process any pending jobs in the input queue */
    962     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
    963     CDBG("%s: X", __func__);
    964 }
    965 
    966 /*===========================================================================
    967  * FUNCTION   : releasePPJobData
    968  *
    969  * DESCRIPTION: function to release internal resources in p pjob struct
    970  *
    971  * PARAMETERS :
    972  *   @job     : ptr to pp job struct
    973  *
    974  * RETURN     : None
    975  *
    976  * NOTE       : Original source metadata buffer needs to be released and
    977  *              queued back to kernel for future use. src_frame, src_metadata,
    978  *              and fwk_src_frame structures need to be freed.
    979  *==========================================================================*/
    980 void QCamera3PostProcessor::releasePPJobData(qcamera_hal3_pp_data_t *pp_job)
    981 {
    982     ATRACE_CALL();
    983     CDBG("%s: E", __func__);
    984     if (NULL != pp_job) {
    985         if (NULL != pp_job->src_frame) {
    986             free(pp_job->src_frame);
    987             if (NULL != pp_job->src_metadata) {
    988                 m_parent->metadataBufDone(pp_job->src_metadata);
    989                 free(pp_job->src_metadata);
    990             }
    991             pp_job->src_frame = NULL;
    992             pp_job->metadata = NULL;
    993         }
    994 
    995         if (NULL != pp_job->fwk_src_frame) {
    996             free(pp_job->fwk_src_frame);
    997             pp_job->fwk_src_frame = NULL;
    998         }
    999     }
   1000 
   1001     /* Additional trigger to process any pending jobs in the input queue */
   1002     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
   1003     CDBG("%s: X", __func__);
   1004 }
   1005 
   1006 /*===========================================================================
   1007  * FUNCTION   : getColorfmtFromImgFmt
   1008  *
   1009  * DESCRIPTION: function to return jpeg color format based on its image format
   1010  *
   1011  * PARAMETERS :
   1012  *   @img_fmt : image format
   1013  *
   1014  * RETURN     : jpeg color format that can be understandable by omx lib
   1015  *==========================================================================*/
   1016 mm_jpeg_color_format QCamera3PostProcessor::getColorfmtFromImgFmt(cam_format_t img_fmt)
   1017 {
   1018     switch (img_fmt) {
   1019     case CAM_FORMAT_YUV_420_NV21:
   1020         return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
   1021     case CAM_FORMAT_YUV_420_NV21_ADRENO:
   1022         return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
   1023     case CAM_FORMAT_YUV_420_NV12:
   1024         return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2;
   1025     case CAM_FORMAT_YUV_420_YV12:
   1026         return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2;
   1027     case CAM_FORMAT_YUV_422_NV61:
   1028         return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1;
   1029     case CAM_FORMAT_YUV_422_NV16:
   1030         return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1;
   1031     default:
   1032         return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
   1033     }
   1034 }
   1035 
   1036 /*===========================================================================
   1037  * FUNCTION   : getJpegImgTypeFromImgFmt
   1038  *
   1039  * DESCRIPTION: function to return jpeg encode image type based on its image format
   1040  *
   1041  * PARAMETERS :
   1042  *   @img_fmt : image format
   1043  *
   1044  * RETURN     : return jpeg source image format (YUV or Bitstream)
   1045  *==========================================================================*/
   1046 mm_jpeg_format_t QCamera3PostProcessor::getJpegImgTypeFromImgFmt(cam_format_t img_fmt)
   1047 {
   1048     switch (img_fmt) {
   1049     case CAM_FORMAT_YUV_420_NV21:
   1050     case CAM_FORMAT_YUV_420_NV21_ADRENO:
   1051     case CAM_FORMAT_YUV_420_NV12:
   1052     case CAM_FORMAT_YUV_420_YV12:
   1053     case CAM_FORMAT_YUV_422_NV61:
   1054     case CAM_FORMAT_YUV_422_NV16:
   1055         return MM_JPEG_FMT_YUV;
   1056     default:
   1057         return MM_JPEG_FMT_YUV;
   1058     }
   1059 }
   1060 
   1061 /*===========================================================================
   1062  * FUNCTION   : encodeFWKData
   1063  *
   1064  * DESCRIPTION: function to prepare encoding job information and send to
   1065  *              mm-jpeg-interface to do the encoding job
   1066  *
   1067  * PARAMETERS :
   1068  *   @jpeg_job_data : ptr to a struct saving job related information
   1069  *   @needNewSess   : flag to indicate if a new jpeg encoding session need
   1070  *                    to be created. After creation, this flag will be toggled
   1071  *
   1072  * RETURN     : int32_t type of status
   1073  *              NO_ERROR  -- success
   1074  *              none-zero failure code
   1075  *==========================================================================*/
   1076 int32_t QCamera3PostProcessor::encodeFWKData(qcamera_hal3_jpeg_data_t *jpeg_job_data,
   1077         uint8_t &needNewSess)
   1078 {
   1079     CDBG("%s : E", __func__);
   1080     int32_t ret = NO_ERROR;
   1081     mm_jpeg_job_t jpg_job;
   1082     uint32_t jobId = 0;
   1083     qcamera_fwk_input_pp_data_t *recvd_frame = NULL;
   1084     metadata_buffer_t *metadata = NULL;
   1085     jpeg_settings_t *jpeg_settings = NULL;
   1086     QCamera3HardwareInterface* hal_obj = NULL;
   1087     bool needJpegRotation = false;
   1088 
   1089     if (NULL == jpeg_job_data) {
   1090         ALOGE("%s: Invalid jpeg job", __func__);
   1091         return BAD_VALUE;
   1092     }
   1093 
   1094     recvd_frame = jpeg_job_data->fwk_frame;
   1095     if (NULL == recvd_frame) {
   1096         ALOGE("%s: Invalid input buffer", __func__);
   1097         return BAD_VALUE;
   1098     }
   1099 
   1100     metadata = jpeg_job_data->metadata;
   1101     if (NULL == metadata) {
   1102         ALOGE("%s: Invalid metadata buffer", __func__);
   1103         return BAD_VALUE;
   1104     }
   1105 
   1106     jpeg_settings = jpeg_job_data->jpeg_settings;
   1107     if (NULL == jpeg_settings) {
   1108         ALOGE("%s: Invalid jpeg settings buffer", __func__);
   1109         return BAD_VALUE;
   1110     }
   1111 
   1112     if ((NULL != jpeg_job_data->src_frame) && (NULL != jpeg_job_data->src_frame)) {
   1113         ALOGE("%s: Unsupported case both framework and camera source buffers are invalid!",
   1114                 __func__);
   1115         return BAD_VALUE;
   1116     }
   1117 
   1118     hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
   1119 
   1120     if (mJpegClientHandle <= 0) {
   1121         ALOGE("%s: Error: bug here, mJpegClientHandle is 0", __func__);
   1122         return UNKNOWN_ERROR;
   1123     }
   1124 
   1125     cam_dimension_t src_dim;
   1126     memset(&src_dim, 0, sizeof(cam_dimension_t));
   1127     src_dim.width = recvd_frame->reproc_config.input_stream_dim.width;
   1128     src_dim.height = recvd_frame->reproc_config.input_stream_dim.height;
   1129 
   1130     cam_dimension_t dst_dim;
   1131     memset(&dst_dim, 0, sizeof(cam_dimension_t));
   1132     dst_dim.width = recvd_frame->reproc_config.output_stream_dim.width;
   1133     dst_dim.height = recvd_frame->reproc_config.output_stream_dim.height;
   1134 
   1135     CDBG_HIGH("%s: Need new session?:%d",__func__, needNewSess);
   1136     if (needNewSess) {
   1137         //creating a new session, so we must destroy the old one
   1138         if ( 0 < mJpegSessionId ) {
   1139             ret = mJpegHandle.destroy_session(mJpegSessionId);
   1140             if (ret != NO_ERROR) {
   1141                 ALOGE("%s: Error destroying an old jpeg encoding session, id = %d",
   1142                       __func__, mJpegSessionId);
   1143                 return ret;
   1144             }
   1145             mJpegSessionId = 0;
   1146         }
   1147         // create jpeg encoding session
   1148         mm_jpeg_encode_params_t encodeParam;
   1149         memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t));
   1150         encodeParam.main_dim.src_dim = src_dim;
   1151         encodeParam.main_dim.dst_dim = dst_dim;
   1152         encodeParam.thumb_dim.src_dim = src_dim;
   1153         encodeParam.thumb_dim.dst_dim = jpeg_settings->thumbnail_size;
   1154 
   1155         getFWKJpegEncodeConfig(encodeParam, recvd_frame, jpeg_settings);
   1156         CDBG_HIGH("%s: #src bufs:%d # tmb bufs:%d #dst_bufs:%d", __func__,
   1157                      encodeParam.num_src_bufs,encodeParam.num_tmb_bufs,encodeParam.num_dst_bufs);
   1158 
   1159         ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId);
   1160         if (ret != NO_ERROR) {
   1161             ALOGE("%s: Error creating a new jpeg encoding session, ret = %d", __func__, ret);
   1162             return ret;
   1163         }
   1164         needNewSess = FALSE;
   1165     }
   1166 
   1167     // Fill in new job
   1168     memset(&jpg_job, 0, sizeof(mm_jpeg_job_t));
   1169     jpg_job.job_type = JPEG_JOB_TYPE_ENCODE;
   1170     jpg_job.encode_job.session_id = mJpegSessionId;
   1171     jpg_job.encode_job.src_index = 0;
   1172     jpg_job.encode_job.dst_index = 0;
   1173 
   1174     cam_rect_t crop;
   1175     memset(&crop, 0, sizeof(cam_rect_t));
   1176     //TBD_later - Zoom event removed in stream
   1177     //main_stream->getCropInfo(crop);
   1178 
   1179     // Set main dim job parameters and handle rotation
   1180     needJpegRotation = hal_obj->needJpegRotation();
   1181     if (!needJpegRotation && (jpeg_settings->jpeg_orientation == 90 ||
   1182             jpeg_settings->jpeg_orientation == 270)) {
   1183 
   1184         jpg_job.encode_job.main_dim.src_dim.width = src_dim.height;
   1185         jpg_job.encode_job.main_dim.src_dim.height = src_dim.width;
   1186 
   1187         jpg_job.encode_job.main_dim.dst_dim.width = dst_dim.height;
   1188         jpg_job.encode_job.main_dim.dst_dim.height = dst_dim.width;
   1189 
   1190         jpg_job.encode_job.main_dim.crop.width = crop.height;
   1191         jpg_job.encode_job.main_dim.crop.height = crop.width;
   1192         jpg_job.encode_job.main_dim.crop.left = crop.top;
   1193         jpg_job.encode_job.main_dim.crop.top = crop.left;
   1194     } else {
   1195         jpg_job.encode_job.main_dim.src_dim = src_dim;
   1196         jpg_job.encode_job.main_dim.dst_dim = dst_dim;
   1197         jpg_job.encode_job.main_dim.crop = crop;
   1198     }
   1199 
   1200     QCamera3HardwareInterface* obj = (QCamera3HardwareInterface*)m_parent->mUserData;
   1201     // get 3a sw version info
   1202     cam_q3a_version_t sw_version;
   1203     memset(&sw_version, 0, sizeof(sw_version));
   1204     if (obj)
   1205         obj->get3AVersion(sw_version);
   1206 
   1207     // get exif data
   1208     QCamera3Exif *pJpegExifObj = getExifData(metadata, jpeg_settings);
   1209     jpeg_job_data->pJpegExifObj = pJpegExifObj;
   1210     if (pJpegExifObj != NULL) {
   1211         jpg_job.encode_job.exif_info.exif_data = pJpegExifObj->getEntries();
   1212         jpg_job.encode_job.exif_info.numOfEntries =
   1213             pJpegExifObj->getNumOfEntries();
   1214         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[0] =
   1215             sw_version.major_version;
   1216         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[1] =
   1217             sw_version.minor_version;
   1218         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[2] =
   1219             sw_version.patch_version;
   1220         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[3] =
   1221             sw_version.new_feature_des;
   1222     }
   1223 
   1224     // thumbnail dim
   1225     CDBG_HIGH("%s: Thumbnail needed:%d",__func__, m_bThumbnailNeeded);
   1226     if (m_bThumbnailNeeded == TRUE) {
   1227         memset(&crop, 0, sizeof(cam_rect_t));
   1228         jpg_job.encode_job.thumb_dim.dst_dim =
   1229                 jpeg_settings->thumbnail_size;
   1230 
   1231         if (needJpegRotation) {
   1232             jpg_job.encode_job.rotation = (uint32_t)jpeg_settings->jpeg_orientation;
   1233             CDBG_HIGH("%s: jpeg rotation is set to %u", __func__, jpg_job.encode_job.rotation);
   1234         } else if (jpeg_settings->jpeg_orientation  == 90 ||
   1235                 jpeg_settings->jpeg_orientation == 270) {
   1236             //swap the thumbnail destination width and height if it has
   1237             //already been rotated
   1238             int temp = jpg_job.encode_job.thumb_dim.dst_dim.width;
   1239             jpg_job.encode_job.thumb_dim.dst_dim.width =
   1240                     jpg_job.encode_job.thumb_dim.dst_dim.height;
   1241             jpg_job.encode_job.thumb_dim.dst_dim.height = temp;
   1242         }
   1243         jpg_job.encode_job.thumb_dim.src_dim = src_dim;
   1244         jpg_job.encode_job.thumb_dim.crop = crop;
   1245         jpg_job.encode_job.thumb_index = 0;
   1246     }
   1247 
   1248     if (metadata != NULL) {
   1249        //Fill in the metadata passed as parameter
   1250        jpg_job.encode_job.p_metadata = metadata;
   1251     } else {
   1252        ALOGE("%s: Metadata is null", __func__);
   1253     }
   1254 
   1255     jpg_job.encode_job.hal_version = CAM_HAL_V3;
   1256 
   1257     //Start jpeg encoding
   1258     ret = mJpegHandle.start_job(&jpg_job, &jobId);
   1259     if (ret == NO_ERROR) {
   1260         // remember job info
   1261         jpeg_job_data->jobId = jobId;
   1262     }
   1263 
   1264     CDBG("%s : X", __func__);
   1265     return ret;
   1266 }
   1267 
   1268 /*===========================================================================
   1269  * FUNCTION   : encodeData
   1270  *
   1271  * DESCRIPTION: function to prepare encoding job information and send to
   1272  *              mm-jpeg-interface to do the encoding job
   1273  *
   1274  * PARAMETERS :
   1275  *   @jpeg_job_data : ptr to a struct saving job related information
   1276  *   @needNewSess   : flag to indicate if a new jpeg encoding session need
   1277  *                    to be created. After creation, this flag will be toggled
   1278  *
   1279  * RETURN     : int32_t type of status
   1280  *              NO_ERROR  -- success
   1281  *              none-zero failure code
   1282  *==========================================================================*/
   1283 int32_t QCamera3PostProcessor::encodeData(qcamera_hal3_jpeg_data_t *jpeg_job_data,
   1284                           uint8_t &needNewSess)
   1285 {
   1286     ATRACE_CALL();
   1287     CDBG("%s : E", __func__);
   1288     int32_t ret = NO_ERROR;
   1289     mm_jpeg_job_t jpg_job;
   1290     uint32_t jobId = 0;
   1291     QCamera3Stream *main_stream = NULL;
   1292     mm_camera_buf_def_t *main_frame = NULL;
   1293     QCamera3Channel *srcChannel = NULL;
   1294     mm_camera_super_buf_t *recvd_frame = NULL;
   1295     metadata_buffer_t *metadata = NULL;
   1296     jpeg_settings_t *jpeg_settings = NULL;
   1297     QCamera3HardwareInterface* hal_obj = NULL;
   1298     if (m_parent != NULL) {
   1299        hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
   1300     } else {
   1301        ALOGE("%s: m_parent is NULL, Error",__func__);
   1302        return BAD_VALUE;
   1303     }
   1304     bool needJpegRotation = false;
   1305 
   1306     recvd_frame = jpeg_job_data->src_frame;
   1307     metadata = jpeg_job_data->metadata;
   1308     jpeg_settings = jpeg_job_data->jpeg_settings;
   1309 
   1310     CDBG("%s: encoding bufIndex: %u", __func__,
   1311         jpeg_job_data->src_frame->bufs[0]->buf_idx);
   1312 
   1313     QCamera3Channel *pChannel = NULL;
   1314     // first check picture channel
   1315     if (m_parent->getMyHandle() == recvd_frame->ch_id) {
   1316         pChannel = m_parent;
   1317     }
   1318     // check reprocess channel if not found
   1319     if (pChannel == NULL) {
   1320         if (m_pReprocChannel != NULL &&
   1321             m_pReprocChannel->getMyHandle() == recvd_frame->ch_id) {
   1322             pChannel = m_pReprocChannel;
   1323         }
   1324     }
   1325 
   1326     srcChannel = pChannel;
   1327 
   1328     if (srcChannel == NULL) {
   1329         ALOGE("%s: No corresponding channel (ch_id = %d) exist, return here",
   1330               __func__, recvd_frame->ch_id);
   1331         return BAD_VALUE;
   1332     }
   1333 
   1334     // find snapshot frame and thumnail frame
   1335     //Note: In this version we will receive only snapshot frame.
   1336     for (uint32_t i = 0; i < recvd_frame->num_bufs; i++) {
   1337         QCamera3Stream *srcStream =
   1338             srcChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id);
   1339         if (srcStream != NULL) {
   1340             switch (srcStream->getMyType()) {
   1341             case CAM_STREAM_TYPE_SNAPSHOT:
   1342             case CAM_STREAM_TYPE_OFFLINE_PROC:
   1343                 main_stream = srcStream;
   1344                 main_frame = recvd_frame->bufs[i];
   1345                 break;
   1346             default:
   1347                 break;
   1348             }
   1349         }
   1350     }
   1351 
   1352     if(NULL == main_frame){
   1353        ALOGE("%s : Main frame is NULL", __func__);
   1354        return BAD_VALUE;
   1355     }
   1356 
   1357     QCamera3StreamMem *memObj = (QCamera3StreamMem *)main_frame->mem_info;
   1358     if (NULL == memObj) {
   1359         ALOGE("%s : Memeory Obj of main frame is NULL", __func__);
   1360         return NO_MEMORY;
   1361     }
   1362 
   1363     // clean and invalidate cache ops through mem obj of the frame
   1364     memObj->cleanInvalidateCache(main_frame->buf_idx);
   1365 
   1366     if (mJpegClientHandle <= 0) {
   1367         ALOGE("%s: Error: bug here, mJpegClientHandle is 0", __func__);
   1368         return UNKNOWN_ERROR;
   1369     }
   1370     cam_dimension_t src_dim;
   1371     memset(&src_dim, 0, sizeof(cam_dimension_t));
   1372     main_stream->getFrameDimension(src_dim);
   1373 
   1374     cam_dimension_t dst_dim;
   1375     memset(&dst_dim, 0, sizeof(cam_dimension_t));
   1376     if (NO_ERROR != m_parent->getStreamSize(dst_dim)) {
   1377         ALOGE("%s: Failed to get size of the JPEG stream", __func__);
   1378         return UNKNOWN_ERROR;
   1379     }
   1380 
   1381     needJpegRotation = hal_obj->needJpegRotation();
   1382     CDBG_HIGH("%s: Need new session?:%d",__func__, needNewSess);
   1383     if (needNewSess) {
   1384         //creating a new session, so we must destroy the old one
   1385         if ( 0 < mJpegSessionId ) {
   1386             ret = mJpegHandle.destroy_session(mJpegSessionId);
   1387             if (ret != NO_ERROR) {
   1388                 ALOGE("%s: Error destroying an old jpeg encoding session, id = %d",
   1389                       __func__, mJpegSessionId);
   1390                 return ret;
   1391             }
   1392             mJpegSessionId = 0;
   1393         }
   1394         // create jpeg encoding session
   1395         mm_jpeg_encode_params_t encodeParam;
   1396         memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t));
   1397         getJpegEncodeConfig(encodeParam, main_stream, jpeg_settings);
   1398         CDBG_HIGH("%s: #src bufs:%d # tmb bufs:%d #dst_bufs:%d", __func__,
   1399                      encodeParam.num_src_bufs,encodeParam.num_tmb_bufs,encodeParam.num_dst_bufs);
   1400         if (!needJpegRotation &&
   1401             (jpeg_settings->jpeg_orientation == 90 ||
   1402             jpeg_settings->jpeg_orientation == 270)) {
   1403            //swap src width and height, stride and scanline due to rotation
   1404            encodeParam.main_dim.src_dim.width = src_dim.height;
   1405            encodeParam.main_dim.src_dim.height = src_dim.width;
   1406            encodeParam.thumb_dim.src_dim.width = src_dim.height;
   1407            encodeParam.thumb_dim.src_dim.height = src_dim.width;
   1408 
   1409            int32_t temp = encodeParam.src_main_buf[0].offset.mp[0].stride;
   1410            encodeParam.src_main_buf[0].offset.mp[0].stride =
   1411               encodeParam.src_main_buf[0].offset.mp[0].scanline;
   1412            encodeParam.src_main_buf[0].offset.mp[0].scanline = temp;
   1413 
   1414            temp = encodeParam.src_thumb_buf[0].offset.mp[0].stride;
   1415            encodeParam.src_thumb_buf[0].offset.mp[0].stride =
   1416               encodeParam.src_thumb_buf[0].offset.mp[0].scanline;
   1417            encodeParam.src_thumb_buf[0].offset.mp[0].scanline = temp;
   1418         } else {
   1419            encodeParam.main_dim.src_dim  = src_dim;
   1420            encodeParam.thumb_dim.src_dim = src_dim;
   1421         }
   1422         encodeParam.main_dim.dst_dim = dst_dim;
   1423         encodeParam.thumb_dim.dst_dim = jpeg_settings->thumbnail_size;
   1424         if (needJpegRotation) {
   1425            encodeParam.rotation = (uint32_t)jpeg_settings->jpeg_orientation;
   1426         }
   1427 
   1428         ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId);
   1429         if (ret != NO_ERROR) {
   1430             ALOGE("%s: Error creating a new jpeg encoding session, ret = %d", __func__, ret);
   1431             return ret;
   1432         }
   1433         needNewSess = FALSE;
   1434     }
   1435 
   1436     // Fill in new job
   1437     memset(&jpg_job, 0, sizeof(mm_jpeg_job_t));
   1438     jpg_job.job_type = JPEG_JOB_TYPE_ENCODE;
   1439     jpg_job.encode_job.session_id = mJpegSessionId;
   1440     jpg_job.encode_job.src_index = (int32_t)main_frame->buf_idx;
   1441     jpg_job.encode_job.dst_index = 0;
   1442 
   1443     if (needJpegRotation) {
   1444         jpg_job.encode_job.rotation = (uint32_t)jpeg_settings->jpeg_orientation;
   1445         CDBG("%s: %d: jpeg rotation is set to %d", __func__, __LINE__,
   1446                 jpg_job.encode_job.rotation);
   1447     }
   1448 
   1449     cam_rect_t crop;
   1450     memset(&crop, 0, sizeof(cam_rect_t));
   1451     //TBD_later - Zoom event removed in stream
   1452     //main_stream->getCropInfo(crop);
   1453 
   1454     // Set main dim job parameters and handle rotation
   1455     if (!needJpegRotation && (jpeg_settings->jpeg_orientation == 90 ||
   1456             jpeg_settings->jpeg_orientation == 270)) {
   1457 
   1458         jpg_job.encode_job.main_dim.src_dim.width = src_dim.height;
   1459         jpg_job.encode_job.main_dim.src_dim.height = src_dim.width;
   1460 
   1461         jpg_job.encode_job.main_dim.dst_dim.width = dst_dim.height;
   1462         jpg_job.encode_job.main_dim.dst_dim.height = dst_dim.width;
   1463 
   1464         jpg_job.encode_job.main_dim.crop.width = crop.height;
   1465         jpg_job.encode_job.main_dim.crop.height = crop.width;
   1466         jpg_job.encode_job.main_dim.crop.left = crop.top;
   1467         jpg_job.encode_job.main_dim.crop.top = crop.left;
   1468     } else {
   1469         jpg_job.encode_job.main_dim.src_dim = src_dim;
   1470         jpg_job.encode_job.main_dim.dst_dim = dst_dim;
   1471         jpg_job.encode_job.main_dim.crop = crop;
   1472     }
   1473 
   1474     QCamera3HardwareInterface* obj = (QCamera3HardwareInterface*)m_parent->mUserData;
   1475     // get 3a sw version info
   1476     cam_q3a_version_t sw_version;
   1477     memset(&sw_version, 0, sizeof(sw_version));
   1478 
   1479     if (obj)
   1480         obj->get3AVersion(sw_version);
   1481 
   1482     // get exif data
   1483     QCamera3Exif *pJpegExifObj = getExifData(metadata, jpeg_settings);
   1484     jpeg_job_data->pJpegExifObj = pJpegExifObj;
   1485     if (pJpegExifObj != NULL) {
   1486         jpg_job.encode_job.exif_info.exif_data = pJpegExifObj->getEntries();
   1487         jpg_job.encode_job.exif_info.numOfEntries =
   1488             pJpegExifObj->getNumOfEntries();
   1489         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[0] =
   1490             sw_version.major_version;
   1491         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[1] =
   1492             sw_version.minor_version;
   1493         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[2] =
   1494             sw_version.patch_version;
   1495         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[3] =
   1496             sw_version.new_feature_des;
   1497     }
   1498 
   1499     // thumbnail dim
   1500     CDBG_HIGH("%s: Thumbnail needed:%d",__func__, m_bThumbnailNeeded);
   1501     if (m_bThumbnailNeeded == TRUE) {
   1502         memset(&crop, 0, sizeof(cam_rect_t));
   1503         jpg_job.encode_job.thumb_dim.dst_dim =
   1504                 jpeg_settings->thumbnail_size;
   1505 
   1506       if (!needJpegRotation &&
   1507           (jpeg_settings->jpeg_orientation  == 90 ||
   1508            jpeg_settings->jpeg_orientation == 270)) {
   1509             //swap the thumbnail destination width and height if it has
   1510             //already been rotated
   1511             int temp = jpg_job.encode_job.thumb_dim.dst_dim.width;
   1512             jpg_job.encode_job.thumb_dim.dst_dim.width =
   1513                     jpg_job.encode_job.thumb_dim.dst_dim.height;
   1514             jpg_job.encode_job.thumb_dim.dst_dim.height = temp;
   1515 
   1516             jpg_job.encode_job.thumb_dim.src_dim.width = src_dim.height;
   1517             jpg_job.encode_job.thumb_dim.src_dim.height = src_dim.width;
   1518         } else {
   1519            jpg_job.encode_job.thumb_dim.src_dim = src_dim;
   1520         }
   1521         jpg_job.encode_job.thumb_dim.crop = crop;
   1522         jpg_job.encode_job.thumb_index = main_frame->buf_idx;
   1523     }
   1524 
   1525     jpg_job.encode_job.cam_exif_params = hal_obj->get3AExifParams();
   1526     jpg_job.encode_job.mobicat_mask = hal_obj->getMobicatMask();
   1527     if (metadata != NULL) {
   1528        //Fill in the metadata passed as parameter
   1529        jpg_job.encode_job.p_metadata = metadata;
   1530 
   1531        jpg_job.encode_job.p_metadata->is_mobicat_aec_params_valid =
   1532                 jpg_job.encode_job.cam_exif_params.cam_3a_params_valid;
   1533 
   1534        if (jpg_job.encode_job.cam_exif_params.cam_3a_params_valid) {
   1535             jpg_job.encode_job.p_metadata->mobicat_aec_params =
   1536                 jpg_job.encode_job.cam_exif_params.cam_3a_params;
   1537        }
   1538 
   1539        /* Save a copy of 3A debug params */
   1540         jpg_job.encode_job.p_metadata->is_statsdebug_ae_params_valid =
   1541                 jpg_job.encode_job.cam_exif_params.ae_debug_params_valid;
   1542         jpg_job.encode_job.p_metadata->is_statsdebug_awb_params_valid =
   1543                 jpg_job.encode_job.cam_exif_params.awb_debug_params_valid;
   1544         jpg_job.encode_job.p_metadata->is_statsdebug_af_params_valid =
   1545                 jpg_job.encode_job.cam_exif_params.af_debug_params_valid;
   1546         jpg_job.encode_job.p_metadata->is_statsdebug_asd_params_valid =
   1547                 jpg_job.encode_job.cam_exif_params.asd_debug_params_valid;
   1548         jpg_job.encode_job.p_metadata->is_statsdebug_stats_params_valid =
   1549                 jpg_job.encode_job.cam_exif_params.stats_debug_params_valid;
   1550 
   1551         if (jpg_job.encode_job.cam_exif_params.ae_debug_params_valid) {
   1552             jpg_job.encode_job.p_metadata->statsdebug_ae_data =
   1553                     jpg_job.encode_job.cam_exif_params.ae_debug_params;
   1554         }
   1555         if (jpg_job.encode_job.cam_exif_params.awb_debug_params_valid) {
   1556             jpg_job.encode_job.p_metadata->statsdebug_awb_data =
   1557                     jpg_job.encode_job.cam_exif_params.awb_debug_params;
   1558         }
   1559         if (jpg_job.encode_job.cam_exif_params.af_debug_params_valid) {
   1560             jpg_job.encode_job.p_metadata->statsdebug_af_data =
   1561                     jpg_job.encode_job.cam_exif_params.af_debug_params;
   1562         }
   1563         if (jpg_job.encode_job.cam_exif_params.asd_debug_params_valid) {
   1564             jpg_job.encode_job.p_metadata->statsdebug_asd_data =
   1565                     jpg_job.encode_job.cam_exif_params.asd_debug_params;
   1566         }
   1567         if (jpg_job.encode_job.cam_exif_params.stats_debug_params_valid) {
   1568             jpg_job.encode_job.p_metadata->statsdebug_stats_buffer_data =
   1569                     jpg_job.encode_job.cam_exif_params.stats_debug_params;
   1570         }
   1571     } else {
   1572        ALOGE("%s: Metadata is null", __func__);
   1573     }
   1574 
   1575     jpg_job.encode_job.hal_version = CAM_HAL_V3;
   1576 
   1577     //Start jpeg encoding
   1578     ret = mJpegHandle.start_job(&jpg_job, &jobId);
   1579     if (ret == NO_ERROR) {
   1580         // remember job info
   1581         jpeg_job_data->jobId = jobId;
   1582     }
   1583 
   1584     CDBG("%s : X", __func__);
   1585     return ret;
   1586 }
   1587 
   1588 /*===========================================================================
   1589  * FUNCTION   : dataProcessRoutine
   1590  *
   1591  * DESCRIPTION: data process routine that handles input data either from input
   1592  *              Jpeg Queue to do jpeg encoding, or from input PP Queue to do
   1593  *              reprocess.
   1594  *
   1595  * PARAMETERS :
   1596  *   @data    : user data ptr (QCamera3PostProcessor)
   1597  *
   1598  * RETURN     : None
   1599  *==========================================================================*/
   1600 void *QCamera3PostProcessor::dataProcessRoutine(void *data)
   1601 {
   1602     int running = 1;
   1603     int ret;
   1604     uint8_t is_active = FALSE;
   1605     uint8_t needNewSess = TRUE;
   1606     mm_camera_super_buf_t *meta_buffer = NULL;
   1607     CDBG("%s: E", __func__);
   1608     QCamera3PostProcessor *pme = (QCamera3PostProcessor *)data;
   1609     QCameraCmdThread *cmdThread = &pme->m_dataProcTh;
   1610     cmdThread->setName("cam_data_proc");
   1611 
   1612     do {
   1613         do {
   1614             ret = cam_sem_wait(&cmdThread->cmd_sem);
   1615             if (ret != 0 && errno != EINVAL) {
   1616                 ALOGE("%s: cam_sem_wait error (%s)",
   1617                            __func__, strerror(errno));
   1618                 return NULL;
   1619             }
   1620         } while (ret != 0);
   1621 
   1622         // we got notified about new cmd avail in cmd queue
   1623         camera_cmd_type_t cmd = cmdThread->getCmd();
   1624         switch (cmd) {
   1625         case CAMERA_CMD_TYPE_START_DATA_PROC:
   1626             CDBG_HIGH("%s: start data proc", __func__);
   1627             is_active = TRUE;
   1628             needNewSess = TRUE;
   1629 
   1630             pme->m_ongoingPPQ.init();
   1631             pme->m_inputJpegQ.init();
   1632             pme->m_inputPPQ.init();
   1633             pme->m_inputFWKPPQ.init();
   1634             pme->m_inputMetaQ.init();
   1635             cam_sem_post(&cmdThread->sync_sem);
   1636 
   1637             break;
   1638         case CAMERA_CMD_TYPE_STOP_DATA_PROC:
   1639             {
   1640                 CDBG_HIGH("%s: stop data proc", __func__);
   1641                 is_active = FALSE;
   1642 
   1643                 // cancel all ongoing jpeg jobs
   1644                 qcamera_hal3_jpeg_data_t *jpeg_job =
   1645                     (qcamera_hal3_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
   1646                 while (jpeg_job != NULL) {
   1647                     pme->mJpegHandle.abort_job(jpeg_job->jobId);
   1648 
   1649                     pme->releaseJpegJobData(jpeg_job);
   1650                     free(jpeg_job);
   1651 
   1652                     jpeg_job = (qcamera_hal3_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
   1653                 }
   1654 
   1655                 // destroy jpeg encoding session
   1656                 if ( 0 < pme->mJpegSessionId ) {
   1657                     pme->mJpegHandle.destroy_session(pme->mJpegSessionId);
   1658                     pme->mJpegSessionId = 0;
   1659                 }
   1660 
   1661                 needNewSess = TRUE;
   1662 
   1663                 // flush ongoing postproc Queue
   1664                 pme->m_ongoingPPQ.flush();
   1665 
   1666                 // flush input jpeg Queue
   1667                 pme->m_inputJpegQ.flush();
   1668 
   1669                 // flush input Postproc Queue
   1670                 pme->m_inputPPQ.flush();
   1671 
   1672                 // flush framework input Postproc Queue
   1673                 pme->m_inputFWKPPQ.flush();
   1674 
   1675                 pme->m_inputMetaQ.flush();
   1676 
   1677                 // signal cmd is completed
   1678                 cam_sem_post(&cmdThread->sync_sem);
   1679             }
   1680             break;
   1681         case CAMERA_CMD_TYPE_DO_NEXT_JOB:
   1682             {
   1683                 CDBG_HIGH("%s: Do next job, active is %d", __func__, is_active);
   1684                 /* needNewSess is set to TRUE as postproc is not re-STARTed
   1685                  * anymore for every captureRequest */
   1686                 needNewSess = TRUE;
   1687                 if (is_active == TRUE) {
   1688                     // check if there is any ongoing jpeg jobs
   1689                     if (pme->m_ongoingJpegQ.isEmpty()) {
   1690                         CDBG("%s: ongoing jpeg queue is empty so doing the jpeg job", __func__);
   1691                         // no ongoing jpeg job, we are fine to send jpeg encoding job
   1692                         qcamera_hal3_jpeg_data_t *jpeg_job =
   1693                             (qcamera_hal3_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
   1694 
   1695                         if (NULL != jpeg_job) {
   1696                             // add into ongoing jpeg job Q
   1697                             pme->m_ongoingJpegQ.enqueue((void *)jpeg_job);
   1698 
   1699                             if (jpeg_job->fwk_frame) {
   1700                                 ret = pme->encodeFWKData(jpeg_job, needNewSess);
   1701                             } else {
   1702                                 ret = pme->encodeData(jpeg_job, needNewSess);
   1703                             }
   1704                             if (NO_ERROR != ret) {
   1705                                 // dequeue the last one
   1706                                 pme->m_ongoingJpegQ.dequeue(false);
   1707 
   1708                                 pme->releaseJpegJobData(jpeg_job);
   1709                                 free(jpeg_job);
   1710                             }
   1711                         }
   1712                     }
   1713 
   1714                     // check if there are any framework pp jobs
   1715                     if (!pme->m_inputFWKPPQ.isEmpty()) {
   1716                         qcamera_fwk_input_pp_data_t *fwk_frame =
   1717                                 (qcamera_fwk_input_pp_data_t *) pme->m_inputFWKPPQ.dequeue();
   1718                         if (NULL != fwk_frame) {
   1719                             qcamera_hal3_pp_data_t *pp_job =
   1720                                     (qcamera_hal3_pp_data_t *)malloc(sizeof(qcamera_hal3_pp_data_t));
   1721                             jpeg_settings_t *jpeg_settings =
   1722                                     (jpeg_settings_t *)pme->m_jpegSettingsQ.dequeue();
   1723                             if (pp_job != NULL) {
   1724                                 memset(pp_job, 0, sizeof(qcamera_hal3_pp_data_t));
   1725                                 pp_job->jpeg_settings = jpeg_settings;
   1726                                 if (pme->m_pReprocChannel != NULL) {
   1727                                     if (NO_ERROR != pme->m_pReprocChannel->overrideFwkMetadata(fwk_frame)) {
   1728                                         ALOGE("%s: Failed to extract output crop", __func__);
   1729                                     }
   1730                                     // add into ongoing PP job Q
   1731                                     pp_job->fwk_src_frame = fwk_frame;
   1732                                     pme->m_ongoingPPQ.enqueue((void *)pp_job);
   1733                                     ret = pme->m_pReprocChannel->doReprocessOffline(fwk_frame);
   1734                                     if (NO_ERROR != ret) {
   1735                                         // remove from ongoing PP job Q
   1736                                         pme->m_ongoingPPQ.dequeue(false);
   1737                                     }
   1738                                 } else {
   1739                                     ALOGE("%s: Reprocess channel is NULL", __func__);
   1740                                     ret = -1;
   1741                                 }
   1742                             } else {
   1743                                 ALOGE("%s: no mem for qcamera_hal3_pp_data_t", __func__);
   1744                                 ret = -1;
   1745                             }
   1746 
   1747                             if (0 != ret) {
   1748                                 // free pp_job
   1749                                 if (pp_job != NULL) {
   1750                                     free(pp_job);
   1751                                 }
   1752                                 // free frame
   1753                                 if (fwk_frame != NULL) {
   1754                                     free(fwk_frame);
   1755                                 }
   1756                             }
   1757                         }
   1758                     }
   1759 
   1760                     CDBG_HIGH("%s: dequeuing pp frame", __func__);
   1761                     pthread_mutex_lock(&pme->mReprocJobLock);
   1762                     if(!pme->m_inputPPQ.isEmpty() && !pme->m_inputMetaQ.isEmpty()) {
   1763                         qcamera_hal3_pp_buffer_t *pp_buffer =
   1764                             (qcamera_hal3_pp_buffer_t *)pme->m_inputPPQ.dequeue();
   1765                         meta_buffer =
   1766                             (mm_camera_super_buf_t *)pme->m_inputMetaQ.dequeue();
   1767                         jpeg_settings_t *jpeg_settings =
   1768                            (jpeg_settings_t *)pme->m_jpegSettingsQ.dequeue();
   1769                         pthread_mutex_unlock(&pme->mReprocJobLock);
   1770                         qcamera_hal3_pp_data_t *pp_job =
   1771                             (qcamera_hal3_pp_data_t *)malloc(sizeof(qcamera_hal3_pp_data_t));
   1772                         if (pp_job == NULL) {
   1773                             ALOGE("%s: no mem for qcamera_hal3_pp_data_t",
   1774                                     __func__);
   1775                             ret = -1;
   1776                         } else if (meta_buffer == NULL) {
   1777                             ALOGE("%s: no mem for mm_camera_super_buf_t",
   1778                                     __func__);
   1779                             ret = -1;
   1780                         } else {
   1781                             memset(pp_job, 0, sizeof(qcamera_hal3_pp_data_t));
   1782                             pp_job->src_frame = pp_buffer->input;
   1783                             pp_job->src_metadata = meta_buffer;
   1784                             if (meta_buffer->bufs[0] != NULL) {
   1785                                 pp_job->metadata = (metadata_buffer_t *)
   1786                                         meta_buffer->bufs[0]->buffer;
   1787                             }
   1788                             pp_job->jpeg_settings = jpeg_settings;
   1789                             pme->m_ongoingPPQ.enqueue((void *)pp_job);
   1790                             if (pme->m_pReprocChannel != NULL) {
   1791                                 mm_camera_buf_def_t *meta_buffer_arg = NULL;
   1792                                 meta_buffer_arg = meta_buffer->bufs[0];
   1793                                 qcamera_fwk_input_pp_data_t fwk_frame;
   1794                                 memset(&fwk_frame, 0, sizeof(qcamera_fwk_input_pp_data_t));
   1795                                 fwk_frame.frameNumber = pp_buffer->frameNumber;
   1796                                 ret = pme->m_pReprocChannel->overrideMetadata(
   1797                                         pp_buffer, meta_buffer_arg,
   1798                                         pp_job->jpeg_settings,
   1799                                         fwk_frame);
   1800                                 if (NO_ERROR == ret) {
   1801                                     // add into ongoing PP job Q
   1802                                     ret = pme->m_pReprocChannel->doReprocessOffline(
   1803                                             &fwk_frame);
   1804                                     if (NO_ERROR != ret) {
   1805                                         // remove from ongoing PP job Q
   1806                                         pme->m_ongoingPPQ.dequeue(false);
   1807                                     }
   1808                                 }
   1809                             } else {
   1810                                 ALOGE("%s: No reprocess. Calling processPPData directly",
   1811                                     __func__);
   1812                                 ret = pme->processPPData(pp_buffer->input);
   1813                             }
   1814                         }
   1815 
   1816                         if (0 != ret) {
   1817                             // free pp_job
   1818                             if (pp_job != NULL) {
   1819                                 free(pp_job);
   1820                             }
   1821                             // free frame
   1822                             if (pp_buffer != NULL) {
   1823                                 if (pp_buffer->input) {
   1824                                     pme->releaseSuperBuf(pp_buffer->input);
   1825                                     free(pp_buffer->input);
   1826                                 }
   1827                                 free(pp_buffer);
   1828                             }
   1829                             //free metadata
   1830                             if (NULL != meta_buffer) {
   1831                                 pme->m_parent->metadataBufDone(meta_buffer);
   1832                                 free(meta_buffer);
   1833                             }
   1834                         } else {
   1835                             if (pp_buffer != NULL) {
   1836                                 free(pp_buffer);
   1837                             }
   1838                         }
   1839                     } else {
   1840                         pthread_mutex_unlock(&pme->mReprocJobLock);
   1841                     }
   1842                 } else {
   1843                     // not active, simply return buf and do no op
   1844                     qcamera_hal3_jpeg_data_t *jpeg_job =
   1845                         (qcamera_hal3_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
   1846                     if (NULL != jpeg_job) {
   1847                         free(jpeg_job);
   1848                     }
   1849 
   1850                     qcamera_hal3_pp_buffer_t* pp_buf =
   1851                             (qcamera_hal3_pp_buffer_t *)pme->m_inputPPQ.dequeue();
   1852                     if (NULL != pp_buf) {
   1853                         if (pp_buf->input) {
   1854                             pme->releaseSuperBuf(pp_buf->input);
   1855                             free(pp_buf->input);
   1856                             pp_buf->input = NULL;
   1857                         }
   1858                         free(pp_buf);
   1859                     }
   1860                     mm_camera_super_buf_t *metadata = (mm_camera_super_buf_t *)pme->m_inputMetaQ.dequeue();
   1861                     if (metadata != NULL) {
   1862                         pme->m_parent->metadataBufDone(metadata);
   1863                         free(metadata);
   1864                     }
   1865                     qcamera_fwk_input_pp_data_t *fwk_frame =
   1866                             (qcamera_fwk_input_pp_data_t *) pme->m_inputFWKPPQ.dequeue();
   1867                     if (NULL != fwk_frame) {
   1868                         free(fwk_frame);
   1869                     }
   1870                 }
   1871             }
   1872             break;
   1873         case CAMERA_CMD_TYPE_EXIT:
   1874             running = 0;
   1875             break;
   1876         default:
   1877             break;
   1878         }
   1879     } while (running);
   1880     CDBG("%s: X", __func__);
   1881     return NULL;
   1882 }
   1883 
   1884 /* EXIF related helper methods */
   1885 
   1886 /*===========================================================================
   1887  * FUNCTION   : getRational
   1888  *
   1889  * DESCRIPTION: compose rational struct
   1890  *
   1891  * PARAMETERS :
   1892  *   @rat     : ptr to struct to store rational info
   1893  *   @num     :num of the rational
   1894  *   @denom   : denom of the rational
   1895  *
   1896  * RETURN     : int32_t type of status
   1897  *              NO_ERROR  -- success
   1898  *              none-zero failure code
   1899  *==========================================================================*/
   1900 int32_t getRational(rat_t *rat, int num, int denom)
   1901 {
   1902     if ((0 > num) || (0 >= denom)) {
   1903         ALOGE("%s: Negative values", __func__);
   1904         return BAD_VALUE;
   1905     }
   1906     if (NULL == rat) {
   1907         ALOGE("%s: NULL rat input", __func__);
   1908         return BAD_VALUE;
   1909     }
   1910     rat->num = (uint32_t)num;
   1911     rat->denom = (uint32_t)denom;
   1912     return NO_ERROR;
   1913 }
   1914 
   1915 /*===========================================================================
   1916  * FUNCTION   : parseGPSCoordinate
   1917  *
   1918  * DESCRIPTION: parse GPS coordinate string
   1919  *
   1920  * PARAMETERS :
   1921  *   @coord_str : [input] coordinate string
   1922  *   @coord     : [output]  ptr to struct to store coordinate
   1923  *
   1924  * RETURN     : int32_t type of status
   1925  *              NO_ERROR  -- success
   1926  *              none-zero failure code
   1927  *==========================================================================*/
   1928 int parseGPSCoordinate(const char *coord_str, rat_t* coord)
   1929 {
   1930     if(coord == NULL) {
   1931         ALOGE("%s: error, invalid argument coord == NULL", __func__);
   1932         return BAD_VALUE;
   1933     }
   1934     double degF = atof(coord_str);
   1935     if (degF < 0) {
   1936         degF = -degF;
   1937     }
   1938     double minF = (degF - (int) degF) * 60;
   1939     double secF = (minF - (int) minF) * 60;
   1940 
   1941     getRational(&coord[0], (int)degF, 1);
   1942     getRational(&coord[1], (int)minF, 1);
   1943     getRational(&coord[2], (int)(secF * 10000), 10000);
   1944     return NO_ERROR;
   1945 }
   1946 
   1947 /*===========================================================================
   1948  * FUNCTION   : getExifDateTime
   1949  *
   1950  * DESCRIPTION: query exif date time
   1951  *
   1952  * PARAMETERS :
   1953  *   @dateTime   : string to store exif date time
   1954  *   @subsecTime : string to store exif subsec time
   1955  *
   1956  * RETURN     : int32_t type of status
   1957  *              NO_ERROR  -- success
   1958  *              none-zero failure code
   1959  *==========================================================================*/
   1960 int32_t getExifDateTime(String8 &dateTime, String8 &subsecTime)
   1961 {
   1962     int32_t ret = NO_ERROR;
   1963 
   1964     //get time and date from system
   1965     struct timeval tv;
   1966     struct tm timeinfo_data;
   1967 
   1968     int res = gettimeofday(&tv, NULL);
   1969     if (0 == res) {
   1970         struct tm *timeinfo = localtime_r(&tv.tv_sec, &timeinfo_data);
   1971         if (NULL != timeinfo) {
   1972             //Write datetime according to EXIF Spec
   1973             //"YYYY:MM:DD HH:MM:SS" (20 chars including \0)
   1974             dateTime = String8::format("%04d:%02d:%02d %02d:%02d:%02d",
   1975                     timeinfo->tm_year + 1900, timeinfo->tm_mon + 1,
   1976                     timeinfo->tm_mday, timeinfo->tm_hour,
   1977                     timeinfo->tm_min, timeinfo->tm_sec);
   1978             //Write subsec according to EXIF Sepc
   1979             subsecTime = String8::format("%06ld", tv.tv_usec);
   1980         } else {
   1981             ALOGE("%s: localtime_r() error", __func__);
   1982             ret = UNKNOWN_ERROR;
   1983         }
   1984     } else if (-1 == res) {
   1985         ALOGE("%s: gettimeofday() error: %s", __func__, strerror(errno));
   1986         ret = UNKNOWN_ERROR;
   1987     } else {
   1988         ALOGE("%s: gettimeofday() unexpected return code: %d", __func__, res);
   1989         ret = UNKNOWN_ERROR;
   1990     }
   1991 
   1992     return ret;
   1993 }
   1994 
   1995 /*===========================================================================
   1996  * FUNCTION   : getExifFocalLength
   1997  *
   1998  * DESCRIPTION: get exif focal length
   1999  *
   2000  * PARAMETERS :
   2001  *   @focalLength : ptr to rational struct to store focal length
   2002  *   @value       : focal length value
   2003  *
   2004  * RETURN     : int32_t type of status
   2005  *              NO_ERROR  -- success
   2006  *              none-zero failure code
   2007  *==========================================================================*/
   2008 int32_t getExifFocalLength(rat_t *focalLength, float value)
   2009 {
   2010     int focalLengthValue =
   2011         (int)(value * FOCAL_LENGTH_DECIMAL_PRECISION);
   2012     return getRational(focalLength, focalLengthValue, FOCAL_LENGTH_DECIMAL_PRECISION);
   2013 }
   2014 
   2015 /*===========================================================================
   2016   * FUNCTION   : getExifExpTimeInfo
   2017   *
   2018   * DESCRIPTION: get exif exposure time information
   2019   *
   2020   * PARAMETERS :
   2021   *   @expoTimeInfo     : rational exposure time value
   2022   *   @value            : exposure time value
   2023   * RETURN     : nt32_t type of status
   2024   *              NO_ERROR  -- success
   2025   *              none-zero failure code
   2026   *==========================================================================*/
   2027 int32_t getExifExpTimeInfo(rat_t *expoTimeInfo, int64_t value)
   2028 {
   2029 
   2030     int64_t cal_exposureTime;
   2031     if (value != 0)
   2032         cal_exposureTime = value;
   2033     else
   2034         cal_exposureTime = 60;
   2035 
   2036     return getRational(expoTimeInfo, 1, (int)cal_exposureTime);
   2037 }
   2038 
   2039 /*===========================================================================
   2040  * FUNCTION   : getExifGpsProcessingMethod
   2041  *
   2042  * DESCRIPTION: get GPS processing method
   2043  *
   2044  * PARAMETERS :
   2045  *   @gpsProcessingMethod : string to store GPS process method
   2046  *   @count               : length of the string
   2047  *   @value               : the value of the processing method
   2048  *
   2049  * RETURN     : int32_t type of status
   2050  *              NO_ERROR  -- success
   2051  *              none-zero failure code
   2052  *==========================================================================*/
   2053 int32_t getExifGpsProcessingMethod(char *gpsProcessingMethod,
   2054         uint32_t &count, char* value)
   2055 {
   2056     if(value != NULL) {
   2057         memcpy(gpsProcessingMethod, ExifAsciiPrefix, EXIF_ASCII_PREFIX_SIZE);
   2058         count = EXIF_ASCII_PREFIX_SIZE;
   2059         strlcpy(gpsProcessingMethod + EXIF_ASCII_PREFIX_SIZE,
   2060                 value,
   2061                 strlen(value)+1);
   2062         count += (uint32_t)strlen(value);
   2063         gpsProcessingMethod[count++] = '\0'; // increase 1 for the last NULL char
   2064         return NO_ERROR;
   2065     } else {
   2066         return BAD_VALUE;
   2067     }
   2068 }
   2069 
   2070 /*===========================================================================
   2071  * FUNCTION   : getExifLatitude
   2072  *
   2073  * DESCRIPTION: get exif latitude
   2074  *
   2075  * PARAMETERS :
   2076  *   @latitude : ptr to rational struct to store latitude info
   2077  *   @latRef   : character to indicate latitude reference
   2078  *   @value    : value of the latitude
   2079  *
   2080  * RETURN     : int32_t type of status
   2081  *              NO_ERROR  -- success
   2082  *              none-zero failure code
   2083  *==========================================================================*/
   2084 int32_t getExifLatitude(rat_t *latitude, char *latRef, double value)
   2085 {
   2086     char str[30];
   2087     snprintf(str, sizeof(str), "%f", value);
   2088     if(str != NULL) {
   2089         parseGPSCoordinate(str, latitude);
   2090 
   2091         //set Latitude Ref
   2092         float latitudeValue = strtof(str, 0);
   2093         if(latitudeValue < 0.0f) {
   2094             latRef[0] = 'S';
   2095         } else {
   2096             latRef[0] = 'N';
   2097         }
   2098         latRef[1] = '\0';
   2099         return NO_ERROR;
   2100     }else{
   2101         return BAD_VALUE;
   2102     }
   2103 }
   2104 
   2105 /*===========================================================================
   2106  * FUNCTION   : getExifLongitude
   2107  *
   2108  * DESCRIPTION: get exif longitude
   2109  *
   2110  * PARAMETERS :
   2111  *   @longitude : ptr to rational struct to store longitude info
   2112  *   @lonRef    : character to indicate longitude reference
   2113  *   @value     : value of the longitude
   2114  *
   2115  * RETURN     : int32_t type of status
   2116  *              NO_ERROR  -- success
   2117  *              none-zero failure code
   2118  *==========================================================================*/
   2119 int32_t getExifLongitude(rat_t *longitude, char *lonRef, double value)
   2120 {
   2121     char str[30];
   2122     snprintf(str, sizeof(str), "%f", value);
   2123     if(str != NULL) {
   2124         parseGPSCoordinate(str, longitude);
   2125 
   2126         //set Longitude Ref
   2127         float longitudeValue = strtof(str, 0);
   2128         if(longitudeValue < 0.0f) {
   2129             lonRef[0] = 'W';
   2130         } else {
   2131             lonRef[0] = 'E';
   2132         }
   2133         lonRef[1] = '\0';
   2134         return NO_ERROR;
   2135     }else{
   2136         return BAD_VALUE;
   2137     }
   2138 }
   2139 
   2140 /*===========================================================================
   2141  * FUNCTION   : getExifAltitude
   2142  *
   2143  * DESCRIPTION: get exif altitude
   2144  *
   2145  * PARAMETERS :
   2146  *   @altitude : ptr to rational struct to store altitude info
   2147  *   @altRef   : character to indicate altitude reference
   2148  *   @argValue : altitude value
   2149  *
   2150  * RETURN     : int32_t type of status
   2151  *              NO_ERROR  -- success
   2152  *              none-zero failure code
   2153  *==========================================================================*/
   2154 int32_t getExifAltitude(rat_t *altitude, char *altRef, double argValue)
   2155 {
   2156     char str[30];
   2157     snprintf(str, sizeof(str), "%f", argValue);
   2158     if (str != NULL) {
   2159         double value = atof(str);
   2160         *altRef = 0;
   2161         if(value < 0){
   2162             *altRef = 1;
   2163             value = -value;
   2164         }
   2165         return getRational(altitude, (int)(value * 1000), 1000);
   2166     } else {
   2167         return BAD_VALUE;
   2168     }
   2169 }
   2170 
   2171 /*===========================================================================
   2172  * FUNCTION   : getExifGpsDateTimeStamp
   2173  *
   2174  * DESCRIPTION: get exif GPS date time stamp
   2175  *
   2176  * PARAMETERS :
   2177  *   @gpsDateStamp : GPS date time stamp string
   2178  *   @bufLen       : length of the string
   2179  *   @gpsTimeStamp : ptr to rational struct to store time stamp info
   2180  *   @value        : timestamp value
   2181  *
   2182  * RETURN     : int32_t type of status
   2183  *              NO_ERROR  -- success
   2184  *              none-zero failure code
   2185  *==========================================================================*/
   2186 int32_t getExifGpsDateTimeStamp(char *gpsDateStamp, uint32_t bufLen,
   2187         rat_t *gpsTimeStamp, int64_t value)
   2188 {
   2189     char str[30];
   2190     snprintf(str, sizeof(str), "%lld", (long long int)value);
   2191     if(str != NULL) {
   2192         time_t unixTime = (time_t)atol(str);
   2193         struct tm *UTCTimestamp = gmtime(&unixTime);
   2194         if (UTCTimestamp != NULL && gpsDateStamp != NULL
   2195                 && gpsTimeStamp != NULL) {
   2196             strftime(gpsDateStamp, bufLen, "%Y:%m:%d", UTCTimestamp);
   2197 
   2198             getRational(&gpsTimeStamp[0], UTCTimestamp->tm_hour, 1);
   2199             getRational(&gpsTimeStamp[1], UTCTimestamp->tm_min, 1);
   2200             getRational(&gpsTimeStamp[2], UTCTimestamp->tm_sec, 1);
   2201             return NO_ERROR;
   2202         } else {
   2203             ALOGE("%s: Could not get the timestamp", __func__);
   2204             return BAD_VALUE;
   2205         }
   2206     } else {
   2207         return BAD_VALUE;
   2208     }
   2209 }
   2210 
   2211 /*===========================================================================
   2212  * FUNCTION   : getExifExposureValue
   2213  *
   2214  * DESCRIPTION: get exif GPS date time stamp
   2215  *
   2216  * PARAMETERS :
   2217  *   @exposure_val        : rational exposure value
   2218  *   @exposure_comp       : exposure compensation
   2219  *   @step                : exposure step
   2220  *
   2221  * RETURN     : int32_t type of status
   2222  *              NO_ERROR  -- success
   2223  *              none-zero failure code
   2224  *==========================================================================*/
   2225 int32_t getExifExposureValue(srat_t* exposure_val, int32_t exposure_comp,
   2226         cam_rational_type_t step)
   2227 {
   2228     exposure_val->num = exposure_comp * step.numerator;
   2229     exposure_val->denom = step.denominator;
   2230     return 0;
   2231 }
   2232 
   2233 /*===========================================================================
   2234  * FUNCTION   : getExifData
   2235  *
   2236  * DESCRIPTION: get exif data to be passed into jpeg encoding
   2237  *
   2238  * PARAMETERS :
   2239  * @metadata      : metadata of the encoding request
   2240  * @jpeg_settings : jpeg_settings for encoding
   2241  *
   2242  * RETURN     : exif data from user setting and GPS
   2243  *==========================================================================*/
   2244 QCamera3Exif *QCamera3PostProcessor::getExifData(metadata_buffer_t *metadata,
   2245         jpeg_settings_t *jpeg_settings)
   2246 {
   2247     QCamera3Exif *exif = new QCamera3Exif();
   2248     if (exif == NULL) {
   2249         ALOGE("%s: No memory for QCamera3Exif", __func__);
   2250         return NULL;
   2251     }
   2252 
   2253     int32_t rc = NO_ERROR;
   2254     uint32_t count = 0;
   2255 
   2256     // add exif entries
   2257     String8 dateTime;
   2258     String8 subsecTime;
   2259     rc = getExifDateTime(dateTime, subsecTime);
   2260     if (rc == NO_ERROR) {
   2261         exif->addEntry(EXIFTAGID_DATE_TIME, EXIF_ASCII,
   2262                 (uint32_t)(dateTime.length() + 1), (void *)dateTime.string());
   2263         exif->addEntry(EXIFTAGID_EXIF_DATE_TIME_ORIGINAL, EXIF_ASCII,
   2264                 (uint32_t)(dateTime.length() + 1), (void *)dateTime.string());
   2265         exif->addEntry(EXIFTAGID_EXIF_DATE_TIME_DIGITIZED, EXIF_ASCII,
   2266                 (uint32_t)(dateTime.length() + 1), (void *)dateTime.string());
   2267         exif->addEntry(EXIFTAGID_SUBSEC_TIME, EXIF_ASCII,
   2268                 (uint32_t)(subsecTime.length() + 1), (void *)subsecTime.string());
   2269         exif->addEntry(EXIFTAGID_SUBSEC_TIME_ORIGINAL, EXIF_ASCII,
   2270                 (uint32_t)(subsecTime.length() + 1), (void *)subsecTime.string());
   2271         exif->addEntry(EXIFTAGID_SUBSEC_TIME_DIGITIZED, EXIF_ASCII,
   2272                 (uint32_t)(subsecTime.length() + 1), (void *)subsecTime.string());
   2273     } else {
   2274         ALOGE("%s: getExifDateTime failed", __func__);
   2275     }
   2276 
   2277 
   2278     if (metadata != NULL) {
   2279         IF_META_AVAILABLE(float, focal_length, CAM_INTF_META_LENS_FOCAL_LENGTH, metadata) {
   2280             rat_t focalLength;
   2281             rc = getExifFocalLength(&focalLength, *focal_length);
   2282             if (rc == NO_ERROR) {
   2283                 exif->addEntry(EXIFTAGID_FOCAL_LENGTH,
   2284                         EXIF_RATIONAL,
   2285                         1,
   2286                         (void *)&(focalLength));
   2287             } else {
   2288                 ALOGE("%s: getExifFocalLength failed", __func__);
   2289             }
   2290         }
   2291 
   2292         IF_META_AVAILABLE(int32_t, isoSpeed, CAM_INTF_META_SENSOR_SENSITIVITY, metadata) {
   2293             int16_t fwk_isoSpeed = (int16_t) *isoSpeed;
   2294             exif->addEntry(EXIFTAGID_ISO_SPEED_RATING, EXIF_SHORT, 1, (void *) &(fwk_isoSpeed));
   2295         }
   2296 
   2297 
   2298         IF_META_AVAILABLE(int64_t, sensor_exposure_time,
   2299                 CAM_INTF_META_SENSOR_EXPOSURE_TIME, metadata) {
   2300             rat_t sensorExpTime;
   2301             rc = getExifExpTimeInfo(&sensorExpTime, *sensor_exposure_time);
   2302             if (rc == NO_ERROR){
   2303                 exif->addEntry(EXIFTAGID_EXPOSURE_TIME,
   2304                         EXIF_RATIONAL,
   2305                         1,
   2306                         (void *)&(sensorExpTime));
   2307             } else {
   2308                 ALOGE("%s: getExifExpTimeInfo failed", __func__);
   2309             }
   2310         }
   2311 
   2312         char* jpeg_gps_processing_method = jpeg_settings->gps_processing_method;
   2313         if (strlen(jpeg_gps_processing_method) > 0) {
   2314             char gpsProcessingMethod[EXIF_ASCII_PREFIX_SIZE +
   2315                     GPS_PROCESSING_METHOD_SIZE];
   2316             count = 0;
   2317             rc = getExifGpsProcessingMethod(gpsProcessingMethod,
   2318                     count,
   2319                     jpeg_gps_processing_method);
   2320             if(rc == NO_ERROR) {
   2321                 exif->addEntry(EXIFTAGID_GPS_PROCESSINGMETHOD,
   2322                         EXIF_ASCII,
   2323                         count,
   2324                         (void *)gpsProcessingMethod);
   2325             } else {
   2326                 ALOGE("%s: getExifGpsProcessingMethod failed", __func__);
   2327             }
   2328         }
   2329 
   2330         if (jpeg_settings->gps_coordinates_valid) {
   2331 
   2332             //latitude
   2333             rat_t latitude[3];
   2334             char latRef[2];
   2335             rc = getExifLatitude(latitude, latRef,
   2336                     jpeg_settings->gps_coordinates[0]);
   2337             if(rc == NO_ERROR) {
   2338                 exif->addEntry(EXIFTAGID_GPS_LATITUDE,
   2339                         EXIF_RATIONAL,
   2340                         3,
   2341                         (void *)latitude);
   2342                 exif->addEntry(EXIFTAGID_GPS_LATITUDE_REF,
   2343                         EXIF_ASCII,
   2344                         2,
   2345                         (void *)latRef);
   2346             } else {
   2347                 ALOGE("%s: getExifLatitude failed", __func__);
   2348             }
   2349 
   2350             //longitude
   2351             rat_t longitude[3];
   2352             char lonRef[2];
   2353             rc = getExifLongitude(longitude, lonRef,
   2354                     jpeg_settings->gps_coordinates[1]);
   2355             if(rc == NO_ERROR) {
   2356                 exif->addEntry(EXIFTAGID_GPS_LONGITUDE,
   2357                         EXIF_RATIONAL,
   2358                         3,
   2359                         (void *)longitude);
   2360 
   2361                 exif->addEntry(EXIFTAGID_GPS_LONGITUDE_REF,
   2362                         EXIF_ASCII,
   2363                         2,
   2364                         (void *)lonRef);
   2365             } else {
   2366                 ALOGE("%s: getExifLongitude failed", __func__);
   2367             }
   2368 
   2369             //altitude
   2370             rat_t altitude;
   2371             char altRef;
   2372             rc = getExifAltitude(&altitude, &altRef,
   2373                     jpeg_settings->gps_coordinates[2]);
   2374             if(rc == NO_ERROR) {
   2375                 exif->addEntry(EXIFTAGID_GPS_ALTITUDE,
   2376                         EXIF_RATIONAL,
   2377                         1,
   2378                         (void *)&(altitude));
   2379 
   2380                 exif->addEntry(EXIFTAGID_GPS_ALTITUDE_REF,
   2381                         EXIF_BYTE,
   2382                         1,
   2383                         (void *)&altRef);
   2384             } else {
   2385                 ALOGE("%s: getExifAltitude failed", __func__);
   2386             }
   2387         }
   2388 
   2389         if (jpeg_settings->gps_timestamp_valid) {
   2390 
   2391             char gpsDateStamp[20];
   2392             rat_t gpsTimeStamp[3];
   2393             rc = getExifGpsDateTimeStamp(gpsDateStamp, 20, gpsTimeStamp,
   2394                     jpeg_settings->gps_timestamp);
   2395             if(rc == NO_ERROR) {
   2396                 exif->addEntry(EXIFTAGID_GPS_DATESTAMP, EXIF_ASCII,
   2397                         (uint32_t)(strlen(gpsDateStamp) + 1),
   2398                         (void *)gpsDateStamp);
   2399 
   2400                 exif->addEntry(EXIFTAGID_GPS_TIMESTAMP,
   2401                         EXIF_RATIONAL,
   2402                         3,
   2403                         (void *)gpsTimeStamp);
   2404             } else {
   2405                 ALOGE("%s: getExifGpsDataTimeStamp failed", __func__);
   2406             }
   2407         }
   2408 
   2409         IF_META_AVAILABLE(int32_t, exposure_comp, CAM_INTF_PARM_EXPOSURE_COMPENSATION, metadata) {
   2410             IF_META_AVAILABLE(cam_rational_type_t, comp_step, CAM_INTF_PARM_EV_STEP, metadata) {
   2411                 srat_t exposure_val;
   2412                 rc = getExifExposureValue(&exposure_val, *exposure_comp, *comp_step);
   2413                 if(rc == NO_ERROR) {
   2414                     exif->addEntry(EXIFTAGID_EXPOSURE_BIAS_VALUE,
   2415                             EXIF_SRATIONAL,
   2416                             1,
   2417                             (void *)(&exposure_val));
   2418                 } else {
   2419                     ALOGE("%s: getExifExposureValue failed ", __func__);
   2420                 }
   2421             }
   2422         }
   2423     } else {
   2424         ALOGE("%s: no metadata provided ", __func__);
   2425     }
   2426 
   2427     bool output_image_desc = true;
   2428 
   2429 #ifdef ENABLE_MODEL_INFO_EXIF
   2430 
   2431     char value[PROPERTY_VALUE_MAX];
   2432     if (property_get("ro.product.manufacturer", value, "QCOM-AA") > 0) {
   2433         exif->addEntry(EXIFTAGID_MAKE, EXIF_ASCII,
   2434                 (uint32_t)(strlen(value) + 1), (void *)value);
   2435     } else {
   2436         ALOGE("%s: getExifMaker failed", __func__);
   2437     }
   2438 
   2439     if (property_get("ro.product.model", value, "QCAM-AA") > 0) {
   2440         exif->addEntry(EXIFTAGID_MODEL, EXIF_ASCII,
   2441                 (uint32_t)(strlen(value) + 1), (void *)value);
   2442     } else {
   2443         ALOGE("%s: getExifModel failed", __func__);
   2444     }
   2445 
   2446     if (property_get("ro.build.description", value, "QCAM-AA") > 0) {
   2447         exif->addEntry(EXIFTAGID_SOFTWARE, EXIF_ASCII,
   2448                 (uint32_t)(strlen(value) + 1), (void *)value);
   2449     } else {
   2450         ALOGE("%s: getExifSoftware failed", __func__);
   2451     }
   2452 
   2453     // Production sw should not enable image description field output
   2454     output_image_desc = false;
   2455 #endif
   2456 
   2457     if (jpeg_settings->image_desc_valid && output_image_desc) {
   2458         if (exif->addEntry(EXIFTAGID_IMAGE_DESCRIPTION, EXIF_ASCII,
   2459                 strlen(jpeg_settings->image_desc)+1,
   2460                 (void *)jpeg_settings->image_desc)) {
   2461             ALOGE("%s: Adding IMAGE_DESCRIPTION tag failed", __func__);
   2462         }
   2463     }
   2464     return exif;
   2465 }
   2466 
   2467 /*===========================================================================
   2468  * FUNCTION   : QCamera3Exif
   2469  *
   2470  * DESCRIPTION: constructor of QCamera3Exif
   2471  *
   2472  * PARAMETERS : None
   2473  *
   2474  * RETURN     : None
   2475  *==========================================================================*/
   2476 QCamera3Exif::QCamera3Exif()
   2477     : m_nNumEntries(0)
   2478 {
   2479     memset(m_Entries, 0, sizeof(m_Entries));
   2480 }
   2481 
   2482 /*===========================================================================
   2483  * FUNCTION   : ~QCamera3Exif
   2484  *
   2485  * DESCRIPTION: deconstructor of QCamera3Exif. Will release internal memory ptr.
   2486  *
   2487  * PARAMETERS : None
   2488  *
   2489  * RETURN     : None
   2490  *==========================================================================*/
   2491 QCamera3Exif::~QCamera3Exif()
   2492 {
   2493     for (uint32_t i = 0; i < m_nNumEntries; i++) {
   2494         switch (m_Entries[i].tag_entry.type) {
   2495             case EXIF_BYTE:
   2496                 {
   2497                     if (m_Entries[i].tag_entry.count > 1 &&
   2498                             m_Entries[i].tag_entry.data._bytes != NULL) {
   2499                         free(m_Entries[i].tag_entry.data._bytes);
   2500                         m_Entries[i].tag_entry.data._bytes = NULL;
   2501                     }
   2502                 }
   2503                 break;
   2504             case EXIF_ASCII:
   2505                 {
   2506                     if (m_Entries[i].tag_entry.data._ascii != NULL) {
   2507                         free(m_Entries[i].tag_entry.data._ascii);
   2508                         m_Entries[i].tag_entry.data._ascii = NULL;
   2509                     }
   2510                 }
   2511                 break;
   2512             case EXIF_SHORT:
   2513                 {
   2514                     if (m_Entries[i].tag_entry.count > 1 &&
   2515                             m_Entries[i].tag_entry.data._shorts != NULL) {
   2516                         free(m_Entries[i].tag_entry.data._shorts);
   2517                         m_Entries[i].tag_entry.data._shorts = NULL;
   2518                     }
   2519                 }
   2520                 break;
   2521             case EXIF_LONG:
   2522                 {
   2523                     if (m_Entries[i].tag_entry.count > 1 &&
   2524                             m_Entries[i].tag_entry.data._longs != NULL) {
   2525                         free(m_Entries[i].tag_entry.data._longs);
   2526                         m_Entries[i].tag_entry.data._longs = NULL;
   2527                     }
   2528                 }
   2529                 break;
   2530             case EXIF_RATIONAL:
   2531                 {
   2532                     if (m_Entries[i].tag_entry.count > 1 &&
   2533                             m_Entries[i].tag_entry.data._rats != NULL) {
   2534                         free(m_Entries[i].tag_entry.data._rats);
   2535                         m_Entries[i].tag_entry.data._rats = NULL;
   2536                     }
   2537                 }
   2538                 break;
   2539             case EXIF_UNDEFINED:
   2540                 {
   2541                     if (m_Entries[i].tag_entry.data._undefined != NULL) {
   2542                         free(m_Entries[i].tag_entry.data._undefined);
   2543                         m_Entries[i].tag_entry.data._undefined = NULL;
   2544                     }
   2545                 }
   2546                 break;
   2547             case EXIF_SLONG:
   2548                 {
   2549                     if (m_Entries[i].tag_entry.count > 1 &&
   2550                             m_Entries[i].tag_entry.data._slongs != NULL) {
   2551                         free(m_Entries[i].tag_entry.data._slongs);
   2552                         m_Entries[i].tag_entry.data._slongs = NULL;
   2553                     }
   2554                 }
   2555                 break;
   2556             case EXIF_SRATIONAL:
   2557                 {
   2558                     if (m_Entries[i].tag_entry.count > 1 &&
   2559                             m_Entries[i].tag_entry.data._srats != NULL) {
   2560                         free(m_Entries[i].tag_entry.data._srats);
   2561                         m_Entries[i].tag_entry.data._srats = NULL;
   2562                     }
   2563                 }
   2564                 break;
   2565             default:
   2566                 ALOGE("%s: Error, Unknown type",__func__);
   2567                 break;
   2568         }
   2569     }
   2570 }
   2571 
   2572 /*===========================================================================
   2573  * FUNCTION   : addEntry
   2574  *
   2575  * DESCRIPTION: function to add an entry to exif data
   2576  *
   2577  * PARAMETERS :
   2578  *   @tagid   : exif tag ID
   2579  *   @type    : data type
   2580  *   @count   : number of data in uint of its type
   2581  *   @data    : input data ptr
   2582  *
   2583  * RETURN     : int32_t type of status
   2584  *              NO_ERROR  -- success
   2585  *              none-zero failure code
   2586  *==========================================================================*/
   2587 int32_t QCamera3Exif::addEntry(exif_tag_id_t tagid,
   2588                               exif_tag_type_t type,
   2589                               uint32_t count,
   2590                               void *data)
   2591 {
   2592     int32_t rc = NO_ERROR;
   2593     if(m_nNumEntries >= MAX_HAL3_EXIF_TABLE_ENTRIES) {
   2594         ALOGE("%s: Number of entries exceeded limit", __func__);
   2595         return NO_MEMORY;
   2596     }
   2597 
   2598     m_Entries[m_nNumEntries].tag_id = tagid;
   2599     m_Entries[m_nNumEntries].tag_entry.type = type;
   2600     m_Entries[m_nNumEntries].tag_entry.count = count;
   2601     m_Entries[m_nNumEntries].tag_entry.copy = 1;
   2602     switch (type) {
   2603         case EXIF_BYTE:
   2604             {
   2605                 if (count > 1) {
   2606                     uint8_t *values = (uint8_t *)malloc(count);
   2607                     if (values == NULL) {
   2608                         ALOGE("%s: No memory for byte array", __func__);
   2609                         rc = NO_MEMORY;
   2610                     } else {
   2611                         memcpy(values, data, count);
   2612                         m_Entries[m_nNumEntries].tag_entry.data._bytes = values;
   2613                     }
   2614                 } else {
   2615                     m_Entries[m_nNumEntries].tag_entry.data._byte =
   2616                         *(uint8_t *)data;
   2617                 }
   2618             }
   2619             break;
   2620         case EXIF_ASCII:
   2621             {
   2622                 char *str = NULL;
   2623                 str = (char *)malloc(count + 1);
   2624                 if (str == NULL) {
   2625                     ALOGE("%s: No memory for ascii string", __func__);
   2626                     rc = NO_MEMORY;
   2627                 } else {
   2628                     memset(str, 0, count + 1);
   2629                     memcpy(str, data, count);
   2630                     m_Entries[m_nNumEntries].tag_entry.data._ascii = str;
   2631                 }
   2632             }
   2633             break;
   2634         case EXIF_SHORT:
   2635             {
   2636                 if (count > 1) {
   2637                     uint16_t *values =
   2638                         (uint16_t *)malloc(count * sizeof(uint16_t));
   2639                     if (values == NULL) {
   2640                         ALOGE("%s: No memory for short array", __func__);
   2641                         rc = NO_MEMORY;
   2642                     } else {
   2643                         memcpy(values, data, count * sizeof(uint16_t));
   2644                         m_Entries[m_nNumEntries].tag_entry.data._shorts =values;
   2645                     }
   2646                 } else {
   2647                     m_Entries[m_nNumEntries].tag_entry.data._short =
   2648                         *(uint16_t *)data;
   2649                 }
   2650             }
   2651             break;
   2652         case EXIF_LONG:
   2653             {
   2654                 if (count > 1) {
   2655                     uint32_t *values =
   2656                         (uint32_t *)malloc(count * sizeof(uint32_t));
   2657                     if (values == NULL) {
   2658                         ALOGE("%s: No memory for long array", __func__);
   2659                         rc = NO_MEMORY;
   2660                     } else {
   2661                         memcpy(values, data, count * sizeof(uint32_t));
   2662                         m_Entries[m_nNumEntries].tag_entry.data._longs = values;
   2663                     }
   2664                 } else {
   2665                     m_Entries[m_nNumEntries].tag_entry.data._long =
   2666                         *(uint32_t *)data;
   2667                 }
   2668             }
   2669             break;
   2670         case EXIF_RATIONAL:
   2671             {
   2672                 if (count > 1) {
   2673                     rat_t *values = (rat_t *)malloc(count * sizeof(rat_t));
   2674                     if (values == NULL) {
   2675                         ALOGE("%s: No memory for rational array", __func__);
   2676                         rc = NO_MEMORY;
   2677                     } else {
   2678                         memcpy(values, data, count * sizeof(rat_t));
   2679                         m_Entries[m_nNumEntries].tag_entry.data._rats = values;
   2680                     }
   2681                 } else {
   2682                     m_Entries[m_nNumEntries].tag_entry.data._rat =
   2683                         *(rat_t *)data;
   2684                 }
   2685             }
   2686             break;
   2687         case EXIF_UNDEFINED:
   2688             {
   2689                 uint8_t *values = (uint8_t *)malloc(count);
   2690                 if (values == NULL) {
   2691                     ALOGE("%s: No memory for undefined array", __func__);
   2692                     rc = NO_MEMORY;
   2693                 } else {
   2694                     memcpy(values, data, count);
   2695                     m_Entries[m_nNumEntries].tag_entry.data._undefined = values;
   2696                 }
   2697             }
   2698             break;
   2699         case EXIF_SLONG:
   2700             {
   2701                 if (count > 1) {
   2702                     int32_t *values =
   2703                         (int32_t *)malloc(count * sizeof(int32_t));
   2704                     if (values == NULL) {
   2705                         ALOGE("%s: No memory for signed long array", __func__);
   2706                         rc = NO_MEMORY;
   2707                     } else {
   2708                         memcpy(values, data, count * sizeof(int32_t));
   2709                         m_Entries[m_nNumEntries].tag_entry.data._slongs =values;
   2710                     }
   2711                 } else {
   2712                     m_Entries[m_nNumEntries].tag_entry.data._slong =
   2713                         *(int32_t *)data;
   2714                 }
   2715             }
   2716             break;
   2717         case EXIF_SRATIONAL:
   2718             {
   2719                 if (count > 1) {
   2720                     srat_t *values = (srat_t *)malloc(count * sizeof(srat_t));
   2721                     if (values == NULL) {
   2722                         ALOGE("%s: No memory for sign rational array",__func__);
   2723                         rc = NO_MEMORY;
   2724                     } else {
   2725                         memcpy(values, data, count * sizeof(srat_t));
   2726                         m_Entries[m_nNumEntries].tag_entry.data._srats = values;
   2727                     }
   2728                 } else {
   2729                     m_Entries[m_nNumEntries].tag_entry.data._srat =
   2730                         *(srat_t *)data;
   2731                 }
   2732             }
   2733             break;
   2734         default:
   2735             ALOGE("%s: Error, Unknown type",__func__);
   2736             break;
   2737     }
   2738 
   2739     // Increase number of entries
   2740     m_nNumEntries++;
   2741     return rc;
   2742 }
   2743 
   2744 }; // namespace qcamera
   2745