Home | History | Annotate | Download | only in HAL
      1 /* Copyright (c) 2012-2013, 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 
     30 #define LOG_TAG "QCameraPostProc"
     31 
     32 #include <stdlib.h>
     33 #include <utils/Errors.h>
     34 
     35 #include "QCamera2HWI.h"
     36 #include "QCameraPostProc.h"
     37 
     38 namespace qcamera {
     39 
     40 /*===========================================================================
     41  * FUNCTION   : QCameraPostProcessor
     42  *
     43  * DESCRIPTION: constructor of QCameraPostProcessor.
     44  *
     45  * PARAMETERS :
     46  *   @cam_ctrl : ptr to HWI object
     47  *
     48  * RETURN     : None
     49  *==========================================================================*/
     50 QCameraPostProcessor::QCameraPostProcessor(QCamera2HardwareInterface *cam_ctrl)
     51     : m_parent(cam_ctrl),
     52       mJpegCB(NULL),
     53       mJpegUserData(NULL),
     54       mJpegClientHandle(0),
     55       mJpegSessionId(0),
     56       m_pJpegOutputMem(NULL),
     57       m_pJpegExifObj(NULL),
     58       m_bThumbnailNeeded(TRUE),
     59       m_pReprocChannel(NULL),
     60       m_inputPPQ(releasePPInputData, this),
     61       m_ongoingPPQ(releaseOngoingPPData, this),
     62       m_inputJpegQ(releaseJpegData, this),
     63       m_ongoingJpegQ(releaseJpegData, this),
     64       m_inputRawQ(releasePPInputData, this)
     65 {
     66     memset(&mJpegHandle, 0, sizeof(mJpegHandle));
     67 }
     68 
     69 /*===========================================================================
     70  * FUNCTION   : ~QCameraPostProcessor
     71  *
     72  * DESCRIPTION: deconstructor of QCameraPostProcessor.
     73  *
     74  * PARAMETERS : None
     75  *
     76  * RETURN     : None
     77  *==========================================================================*/
     78 QCameraPostProcessor::~QCameraPostProcessor()
     79 {
     80     if (m_pJpegOutputMem != NULL) {
     81         m_pJpegOutputMem->deallocate();
     82         delete m_pJpegOutputMem;
     83         m_pJpegOutputMem = NULL;
     84     }
     85     if (m_pJpegExifObj != NULL) {
     86         delete m_pJpegExifObj;
     87         m_pJpegExifObj = NULL;
     88     }
     89     if (m_pReprocChannel != NULL) {
     90         m_pReprocChannel->stop();
     91         delete m_pReprocChannel;
     92         m_pReprocChannel = NULL;
     93     }
     94 }
     95 
     96 /*===========================================================================
     97  * FUNCTION   : init
     98  *
     99  * DESCRIPTION: initialization of postprocessor
    100  *
    101  * PARAMETERS :
    102  *   @jpeg_cb      : callback to handle jpeg event from mm-camera-interface
    103  *   @user_data    : user data ptr for jpeg callback
    104  *
    105  * RETURN     : int32_t type of status
    106  *              NO_ERROR  -- success
    107  *              none-zero failure code
    108  *==========================================================================*/
    109 int32_t QCameraPostProcessor::init(jpeg_encode_callback_t jpeg_cb, void *user_data)
    110 {
    111     mJpegCB = jpeg_cb;
    112     mJpegUserData = user_data;
    113 
    114     mJpegClientHandle = jpeg_open(&mJpegHandle);
    115     if(!mJpegClientHandle) {
    116         ALOGE("%s : jpeg_open did not work", __func__);
    117         return UNKNOWN_ERROR;
    118     }
    119 
    120     m_dataProcTh.launch(dataProcessRoutine, this);
    121 
    122     return NO_ERROR;
    123 }
    124 
    125 /*===========================================================================
    126  * FUNCTION   : deinit
    127  *
    128  * DESCRIPTION: de-initialization of postprocessor
    129  *
    130  * PARAMETERS : None
    131  *
    132  * RETURN     : int32_t type of status
    133  *              NO_ERROR  -- success
    134  *              none-zero failure code
    135  *==========================================================================*/
    136 int32_t QCameraPostProcessor::deinit()
    137 {
    138     m_dataProcTh.exit();
    139 
    140     if(mJpegClientHandle > 0) {
    141         int rc = mJpegHandle.close(mJpegClientHandle);
    142         ALOGE("%s: Jpeg closed, rc = %d, mJpegClientHandle = %x",
    143               __func__, rc, mJpegClientHandle);
    144         mJpegClientHandle = 0;
    145         memset(&mJpegHandle, 0, sizeof(mJpegHandle));
    146     }
    147 
    148     return NO_ERROR;
    149 }
    150 
    151 /*===========================================================================
    152  * FUNCTION   : start
    153  *
    154  * DESCRIPTION: start postprocessor. Data process thread and data notify thread
    155  *              will be launched.
    156  *
    157  * PARAMETERS :
    158  *   @pSrcChannel : source channel obj ptr that possibly needs reprocess
    159  *
    160  * RETURN     : int32_t type of status
    161  *              NO_ERROR  -- success
    162  *              none-zero failure code
    163  *
    164  * NOTE       : if any reprocess is needed, a reprocess channel/stream
    165  *              will be started.
    166  *==========================================================================*/
    167 int32_t QCameraPostProcessor::start(QCameraChannel *pSrcChannel)
    168 {
    169     int32_t rc = NO_ERROR;
    170     if (m_parent->needReprocess()) {
    171         if (m_pReprocChannel != NULL) {
    172             delete m_pReprocChannel;
    173             m_pReprocChannel = NULL;
    174         }
    175         // if reprocess is needed, start reprocess channel
    176         m_pReprocChannel = m_parent->addOnlineReprocChannel(pSrcChannel);
    177         if (m_pReprocChannel == NULL) {
    178             ALOGE("%s: cannot add reprocess channel", __func__);
    179             return UNKNOWN_ERROR;
    180         }
    181 
    182         rc = m_pReprocChannel->start();
    183         if (rc != 0) {
    184             ALOGE("%s: cannot start reprocess channel", __func__);
    185             delete m_pReprocChannel;
    186             m_pReprocChannel = NULL;
    187             return rc;
    188         }
    189     }
    190 
    191     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, FALSE, FALSE);
    192     m_parent->m_cbNotifier.startSnapshots();
    193 
    194     return rc;
    195 }
    196 
    197 /*===========================================================================
    198  * FUNCTION   : stop
    199  *
    200  * DESCRIPTION: stop postprocessor. Data process and notify thread will be stopped.
    201  *
    202  * PARAMETERS : None
    203  *
    204  * RETURN     : int32_t type of status
    205  *              NO_ERROR  -- success
    206  *              none-zero failure code
    207  *
    208  * NOTE       : reprocess channel will be stopped and deleted if there is any
    209  *==========================================================================*/
    210 int32_t QCameraPostProcessor::stop()
    211 {
    212     m_parent->m_cbNotifier.stopSnapshots();
    213     // dataProc Thread need to process "stop" as sync call because abort jpeg job should be a sync call
    214     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE);
    215 
    216     return NO_ERROR;
    217 }
    218 
    219 /*===========================================================================
    220  * FUNCTION   : getJpegEncodingConfig
    221  *
    222  * DESCRIPTION: function to prepare encoding job information
    223  *
    224  * PARAMETERS :
    225  *   @encode_parm   : param to be filled with encoding configuration
    226  *
    227  * RETURN     : int32_t type of status
    228  *              NO_ERROR  -- success
    229  *              none-zero failure code
    230  *==========================================================================*/
    231 int32_t QCameraPostProcessor::getJpegEncodingConfig(mm_jpeg_encode_params_t& encode_parm,
    232                                                     QCameraStream *main_stream,
    233                                                     QCameraStream *thumb_stream)
    234 {
    235     ALOGV("%s : E", __func__);
    236     int32_t ret = NO_ERROR;
    237     camera_memory_t *jpeg_mem = NULL;
    238 
    239     encode_parm.jpeg_cb = mJpegCB;
    240     encode_parm.userdata = mJpegUserData;
    241 
    242     m_bThumbnailNeeded = TRUE; // need encode thumbnail by default
    243     cam_dimension_t thumbnailSize;
    244     memset(&thumbnailSize, 0, sizeof(cam_dimension_t));
    245     m_parent->getThumbnailSize(thumbnailSize);
    246     if (thumbnailSize.width == 0 || thumbnailSize.height == 0) {
    247         // (0,0) means no thumbnail
    248         m_bThumbnailNeeded = FALSE;
    249     }
    250     encode_parm.encode_thumbnail = m_bThumbnailNeeded;
    251 
    252     // get color format
    253     cam_format_t img_fmt = CAM_FORMAT_YUV_420_NV12;
    254     main_stream->getFormat(img_fmt);
    255     encode_parm.color_format = getColorfmtFromImgFmt(img_fmt);
    256 
    257     // get jpeg quality
    258     encode_parm.quality = m_parent->getJpegQuality();
    259     if (encode_parm.quality <= 0) {
    260         encode_parm.quality = 85;
    261     }
    262 
    263     // get exif data
    264     if (m_pJpegExifObj != NULL) {
    265         delete m_pJpegExifObj;
    266         m_pJpegExifObj = NULL;
    267     }
    268     m_pJpegExifObj = m_parent->getExifData();
    269     if (m_pJpegExifObj != NULL) {
    270         encode_parm.exif_info.exif_data = m_pJpegExifObj->getEntries();
    271         encode_parm.exif_info.numOfEntries = m_pJpegExifObj->getNumOfEntries();
    272     }
    273 
    274     cam_frame_len_offset_t main_offset;
    275     memset(&main_offset, 0, sizeof(cam_frame_len_offset_t));
    276     main_stream->getFrameOffset(main_offset);
    277 
    278     // src buf config
    279     QCameraMemory *pStreamMem = main_stream->getStreamBufs();
    280     if (pStreamMem == NULL) {
    281         ALOGE("%s: cannot get stream bufs from main stream", __func__);
    282         ret = BAD_VALUE;
    283         goto on_error;
    284     }
    285     encode_parm.num_src_bufs = pStreamMem->getCnt();
    286     for (uint32_t i = 0; i < encode_parm.num_src_bufs; i++) {
    287         camera_memory_t *stream_mem = pStreamMem->getMemory(i, false);
    288         if (stream_mem != NULL) {
    289             encode_parm.src_main_buf[i].index = i;
    290             encode_parm.src_main_buf[i].buf_size = stream_mem->size;
    291             encode_parm.src_main_buf[i].buf_vaddr = (uint8_t *)stream_mem->data;
    292             encode_parm.src_main_buf[i].fd = pStreamMem->getFd(i);
    293             encode_parm.src_main_buf[i].format = MM_JPEG_FMT_YUV;
    294             encode_parm.src_main_buf[i].offset = main_offset;
    295         }
    296     }
    297 
    298     if (m_bThumbnailNeeded == TRUE) {
    299         if (thumb_stream == NULL) {
    300             thumb_stream = main_stream;
    301         }
    302         pStreamMem = thumb_stream->getStreamBufs();
    303         if (pStreamMem == NULL) {
    304             ALOGE("%s: cannot get stream bufs from thumb stream", __func__);
    305             ret = BAD_VALUE;
    306             goto on_error;
    307         }
    308         cam_frame_len_offset_t thumb_offset;
    309         memset(&thumb_offset, 0, sizeof(cam_frame_len_offset_t));
    310         thumb_stream->getFrameOffset(thumb_offset);
    311         encode_parm.num_tmb_bufs =  pStreamMem->getCnt();
    312         for (int i = 0; i < pStreamMem->getCnt(); i++) {
    313             camera_memory_t *stream_mem = pStreamMem->getMemory(i, false);
    314             if (stream_mem != NULL) {
    315                 encode_parm.src_thumb_buf[i].index = i;
    316                 encode_parm.src_thumb_buf[i].buf_size = stream_mem->size;
    317                 encode_parm.src_thumb_buf[i].buf_vaddr = (uint8_t *)stream_mem->data;
    318                 encode_parm.src_thumb_buf[i].fd = pStreamMem->getFd(i);
    319                 encode_parm.src_thumb_buf[i].format = MM_JPEG_FMT_YUV;
    320                 encode_parm.src_thumb_buf[i].offset = thumb_offset;
    321             }
    322         }
    323     }
    324 
    325     // allocate output buf for jpeg encoding
    326     if (m_pJpegOutputMem != NULL) {
    327         m_pJpegOutputMem->deallocate();
    328         delete m_pJpegOutputMem;
    329         m_pJpegOutputMem = NULL;
    330     }
    331     m_pJpegOutputMem = new QCameraStreamMemory(m_parent->mGetMemory,
    332                                                QCAMERA_ION_USE_CACHE);
    333     if (NULL == m_pJpegOutputMem) {
    334         ret = NO_MEMORY;
    335         ALOGE("%s : No memory for m_pJpegOutputMem", __func__);
    336         goto on_error;
    337     }
    338     ret = m_pJpegOutputMem->allocate(1, main_offset.frame_len);
    339     if(ret != OK) {
    340         ret = NO_MEMORY;
    341         ALOGE("%s : No memory for m_pJpegOutputMem", __func__);
    342         goto on_error;
    343     }
    344     jpeg_mem = m_pJpegOutputMem->getMemory(0, false);
    345     if (NULL == jpeg_mem) {
    346         ret = NO_MEMORY;
    347         ALOGE("%s : initHeapMem for jpeg, ret = NO_MEMORY", __func__);
    348         goto on_error;
    349     }
    350     encode_parm.num_dst_bufs = 1;
    351     encode_parm.dest_buf[0].index = 0;
    352     encode_parm.dest_buf[0].buf_size = jpeg_mem->size;
    353     encode_parm.dest_buf[0].buf_vaddr = (uint8_t *)jpeg_mem->data;
    354     encode_parm.dest_buf[0].fd = m_pJpegOutputMem->getFd(0);
    355     encode_parm.dest_buf[0].format = MM_JPEG_FMT_YUV;
    356     encode_parm.dest_buf[0].offset = main_offset;
    357 
    358     ALOGV("%s : X", __func__);
    359     return NO_ERROR;
    360 
    361 on_error:
    362     if (m_pJpegOutputMem != NULL) {
    363         m_pJpegOutputMem->deallocate();
    364         delete m_pJpegOutputMem;
    365         m_pJpegOutputMem = NULL;
    366     }
    367     if (m_pJpegExifObj != NULL) {
    368         delete m_pJpegExifObj;
    369         m_pJpegExifObj = NULL;
    370     }
    371     ALOGV("%s : X with error %d", __func__, ret);
    372     return ret;
    373 }
    374 
    375 /*===========================================================================
    376  * FUNCTION   : sendEvtNotify
    377  *
    378  * DESCRIPTION: send event notify through notify callback registered by upper layer
    379  *
    380  * PARAMETERS :
    381  *   @msg_type: msg type of notify
    382  *   @ext1    : extension
    383  *   @ext2    : extension
    384  *
    385  * RETURN     : int32_t type of status
    386  *              NO_ERROR  -- success
    387  *              none-zero failure code
    388  *==========================================================================*/
    389 int32_t QCameraPostProcessor::sendEvtNotify(int32_t msg_type,
    390                                             int32_t ext1,
    391                                             int32_t ext2)
    392 {
    393     return m_parent->sendEvtNotify(msg_type, ext1, ext2);
    394 }
    395 
    396 /*===========================================================================
    397  * FUNCTION   : sendDataNotify
    398  *
    399  * DESCRIPTION: enqueue data into dataNotify thread
    400  *
    401  * PARAMETERS :
    402  *   @msg_type: data callback msg type
    403  *   @data    : ptr to data memory struct
    404  *   @index   : index to data buffer
    405  *   @metadata: ptr to meta data buffer if there is any
    406  *   @release_data : ptr to struct indicating if data need to be released
    407  *                   after notify
    408  *
    409  * RETURN     : int32_t type of status
    410  *              NO_ERROR  -- success
    411  *              none-zero failure code
    412  *==========================================================================*/
    413 int32_t QCameraPostProcessor::sendDataNotify(int32_t msg_type,
    414                                              camera_memory_t *data,
    415                                              uint8_t index,
    416                                              camera_frame_metadata_t *metadata,
    417                                              qcamera_release_data_t *release_data)
    418 {
    419     qcamera_data_argm_t *data_cb = (qcamera_data_argm_t *)malloc(sizeof(qcamera_data_argm_t));
    420     if (NULL == data_cb) {
    421         ALOGE("%s: no mem for acamera_data_argm_t", __func__);
    422         return NO_MEMORY;
    423     }
    424     memset(data_cb, 0, sizeof(qcamera_data_argm_t));
    425     data_cb->msg_type = msg_type;
    426     data_cb->data = data;
    427     data_cb->index = index;
    428     data_cb->metadata = metadata;
    429     if (release_data != NULL) {
    430         data_cb->release_data = *release_data;
    431     }
    432 
    433     qcamera_callback_argm_t cbArg;
    434     memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
    435     cbArg.cb_type = QCAMERA_DATA_SNAPSHOT_CALLBACK;
    436     cbArg.msg_type = msg_type;
    437     cbArg.data = data;
    438     cbArg.metadata = metadata;
    439     cbArg.user_data = data_cb;
    440     cbArg.cookie = this;
    441     cbArg.release_cb = releaseNotifyData;
    442     int rc = m_parent->m_cbNotifier.notifyCallback(cbArg);
    443     if ( NO_ERROR != rc ) {
    444         ALOGE("%s: Error enqueuing jpeg data into notify queue", __func__);
    445         free(data_cb);
    446         return UNKNOWN_ERROR;
    447     }
    448 
    449     return rc;
    450 }
    451 
    452 /*===========================================================================
    453  * FUNCTION   : processData
    454  *
    455  * DESCRIPTION: enqueue data into dataProc thread
    456  *
    457  * PARAMETERS :
    458  *   @frame   : process frame received from mm-camera-interface
    459  *
    460  * RETURN     : int32_t type of status
    461  *              NO_ERROR  -- success
    462  *              none-zero failure code
    463  *
    464  * NOTE       : depends on if offline reprocess is needed, received frame will
    465  *              be sent to either input queue of postprocess or jpeg encoding
    466  *==========================================================================*/
    467 int32_t QCameraPostProcessor::processData(mm_camera_super_buf_t *frame)
    468 {
    469     if (m_parent->needReprocess()) {
    470         ALOGD("%s: need reprocess", __func__);
    471         // enqueu to post proc input queue
    472         m_inputPPQ.enqueue((void *)frame);
    473     } else if (m_parent->mParameters.isNV16PictureFormat()) {
    474         processRawData(frame);
    475     } else {
    476         ALOGD("%s: no need offline reprocess, sending to jpeg encoding", __func__);
    477         qcamera_jpeg_data_t *jpeg_job =
    478             (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t));
    479         if (jpeg_job == NULL) {
    480             ALOGE("%s: No memory for jpeg job", __func__);
    481             return NO_MEMORY;
    482         }
    483 
    484         memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t));
    485         jpeg_job->src_frame = frame;
    486 
    487         // enqueu to jpeg input queue
    488         m_inputJpegQ.enqueue((void *)jpeg_job);
    489     }
    490     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
    491 
    492     return NO_ERROR;
    493 }
    494 
    495 /*===========================================================================
    496  * FUNCTION   : processRawData
    497  *
    498  * DESCRIPTION: enqueue raw data into dataProc thread
    499  *
    500  * PARAMETERS :
    501  *   @frame   : process frame received from mm-camera-interface
    502  *
    503  * RETURN     : int32_t type of status
    504  *              NO_ERROR  -- success
    505  *              none-zero failure code
    506  *==========================================================================*/
    507 int32_t QCameraPostProcessor::processRawData(mm_camera_super_buf_t *frame)
    508 {
    509     // enqueu to raw input queue
    510     m_inputRawQ.enqueue((void *)frame);
    511     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
    512     return NO_ERROR;
    513 }
    514 
    515 /*===========================================================================
    516  * FUNCTION   : processJpegEvt
    517  *
    518  * DESCRIPTION: process jpeg event from mm-jpeg-interface.
    519  *
    520  * PARAMETERS :
    521  *   @evt     : payload of jpeg event, including information about jpeg encoding
    522  *              status, jpeg size and so on.
    523  *
    524  * RETURN     : int32_t type of status
    525  *              NO_ERROR  -- success
    526  *              none-zero failure code
    527  *
    528  * NOTE       : This event will also trigger DataProc thread to move to next job
    529  *              processing (i.e., send a new jpeg encoding job to mm-jpeg-interface
    530  *              if there is any pending job in jpeg input queue)
    531  *==========================================================================*/
    532 int32_t QCameraPostProcessor::processJpegEvt(qcamera_jpeg_evt_payload_t *evt)
    533 {
    534     int32_t rc = NO_ERROR;
    535     camera_memory_t *jpeg_mem = NULL;
    536 
    537     // find job by jobId
    538     qcamera_jpeg_data_t *job = findJpegJobByJobId(evt->jobId);
    539 
    540     if (job == NULL) {
    541         ALOGE("%s: Cannot find jpeg job by jobId(%d)", __func__, evt->jobId);
    542         rc = BAD_VALUE;
    543         goto end;
    544     }
    545 
    546     ALOGD("[KPI Perf] %s : jpeg job %d", __func__, evt->jobId);
    547 
    548     if (m_parent->mDataCb == NULL ||
    549         m_parent->msgTypeEnabledWithLock(CAMERA_MSG_COMPRESSED_IMAGE) == 0 ) {
    550         ALOGD("%s: No dataCB or CAMERA_MSG_COMPRESSED_IMAGE not enabled",
    551               __func__);
    552         rc = NO_ERROR;
    553         goto end;
    554     }
    555 
    556     if(evt->status == JPEG_JOB_STATUS_ERROR) {
    557         ALOGE("%s: Error event handled from jpeg, status = %d",
    558               __func__, evt->status);
    559         rc = FAILED_TRANSACTION;
    560         goto end;
    561     }
    562 
    563     m_parent->dumpFrameToFile(evt->out_data.buf_vaddr,
    564                               evt->out_data.buf_filled_len,
    565                               evt->jobId,
    566                               QCAMERA_DUMP_FRM_JPEG);
    567     ALOGD("%s: Dump jpeg_size=%d", __func__, evt->out_data.buf_filled_len);
    568 
    569     // alloc jpeg memory to pass to upper layer
    570     jpeg_mem = m_parent->mGetMemory(-1, evt->out_data.buf_filled_len, 1, m_parent->mCallbackCookie);
    571     if (NULL == jpeg_mem) {
    572         rc = NO_MEMORY;
    573         ALOGE("%s : getMemory for jpeg, ret = NO_MEMORY", __func__);
    574         goto end;
    575     }
    576     memcpy(jpeg_mem->data, evt->out_data.buf_vaddr, evt->out_data.buf_filled_len);
    577 
    578     ALOGE("%s : Calling upperlayer callback to store JPEG image", __func__);
    579     qcamera_release_data_t release_data;
    580     memset(&release_data, 0, sizeof(qcamera_release_data_t));
    581     release_data.data = jpeg_mem;
    582     rc = sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE,
    583                         jpeg_mem,
    584                         0,
    585                         NULL,
    586                         &release_data);
    587 
    588 end:
    589     if (rc != NO_ERROR) {
    590         // send error msg to upper layer
    591         sendEvtNotify(CAMERA_MSG_ERROR,
    592                       UNKNOWN_ERROR,
    593                       0);
    594 
    595         if (NULL != jpeg_mem) {
    596             jpeg_mem->release(jpeg_mem);
    597             jpeg_mem = NULL;
    598         }
    599     }
    600 
    601     // release internal data for jpeg job
    602     if (job != NULL) {
    603         releaseJpegJobData(job);
    604         free(job);
    605     }
    606 
    607     // wait up data proc thread to do next job,
    608     // if previous request is blocked due to ongoing jpeg job
    609     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
    610 
    611     return rc;
    612 }
    613 
    614 /*===========================================================================
    615  * FUNCTION   : processPPData
    616  *
    617  * DESCRIPTION: process received frame after reprocess.
    618  *
    619  * PARAMETERS :
    620  *   @frame   : received frame from reprocess channel.
    621  *
    622  * RETURN     : int32_t type of status
    623  *              NO_ERROR  -- success
    624  *              none-zero failure code
    625  *
    626  * NOTE       : The frame after reprocess need to send to jpeg encoding.
    627  *==========================================================================*/
    628 int32_t QCameraPostProcessor::processPPData(mm_camera_super_buf_t *frame)
    629 {
    630     qcamera_pp_data_t *job = (qcamera_pp_data_t *)m_ongoingPPQ.dequeue();
    631 
    632     if (job == NULL || job->src_frame == NULL) {
    633         ALOGE("%s: Cannot find reprocess job", __func__);
    634         return BAD_VALUE;
    635     }
    636 
    637     if (m_parent->mParameters.isNV16PictureFormat()) {
    638         releaseSuperBuf(job->src_frame);
    639         free(job->src_frame);
    640         free(job);
    641         return processRawData(frame);
    642     }
    643 
    644     qcamera_jpeg_data_t *jpeg_job =
    645         (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t));
    646     if (jpeg_job == NULL) {
    647         ALOGE("%s: No memory for jpeg job", __func__);
    648         return NO_MEMORY;
    649     }
    650 
    651     memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t));
    652     jpeg_job->src_frame = frame;
    653     jpeg_job->src_reproc_frame = job->src_frame;
    654 
    655     // free pp job buf
    656     free(job);
    657 
    658     // enqueu reprocessed frame to jpeg input queue
    659     m_inputJpegQ.enqueue((void *)jpeg_job);
    660 
    661     // wait up data proc thread
    662     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
    663 
    664     return NO_ERROR;
    665 }
    666 
    667 /*===========================================================================
    668  * FUNCTION   : findJpegJobByJobId
    669  *
    670  * DESCRIPTION: find a jpeg job from ongoing Jpeg queue by its job ID
    671  *
    672  * PARAMETERS :
    673  *   @jobId   : job Id of the job
    674  *
    675  * RETURN     : ptr to a jpeg job struct. NULL if not found.
    676  *
    677  * NOTE       : Currently only one job is sending to mm-jpeg-interface for jpeg
    678  *              encoding. Therefore simply dequeue from the ongoing Jpeg Queue
    679  *              will serve the purpose to find the jpeg job.
    680  *==========================================================================*/
    681 qcamera_jpeg_data_t *QCameraPostProcessor::findJpegJobByJobId(uint32_t jobId)
    682 {
    683     qcamera_jpeg_data_t * job = NULL;
    684     if (jobId == 0) {
    685         ALOGE("%s: not a valid jpeg jobId", __func__);
    686         return NULL;
    687     }
    688 
    689     // currely only one jpeg job ongoing, so simply dequeue the head
    690     job = (qcamera_jpeg_data_t *)m_ongoingJpegQ.dequeue();
    691     return job;
    692 }
    693 
    694 /*===========================================================================
    695  * FUNCTION   : releasePPInputData
    696  *
    697  * DESCRIPTION: callback function to release post process input data node
    698  *
    699  * PARAMETERS :
    700  *   @data      : ptr to post process input data
    701  *   @user_data : user data ptr (QCameraReprocessor)
    702  *
    703  * RETURN     : None
    704  *==========================================================================*/
    705 void QCameraPostProcessor::releasePPInputData(void *data, void *user_data)
    706 {
    707     QCameraPostProcessor *pme = (QCameraPostProcessor *)user_data;
    708     if (NULL != pme) {
    709         pme->releaseSuperBuf((mm_camera_super_buf_t *)data);
    710     }
    711 }
    712 
    713 /*===========================================================================
    714  * FUNCTION   : releaseJpegData
    715  *
    716  * DESCRIPTION: callback function to release jpeg job node
    717  *
    718  * PARAMETERS :
    719  *   @data      : ptr to ongoing jpeg job data
    720  *   @user_data : user data ptr (QCameraReprocessor)
    721  *
    722  * RETURN     : None
    723  *==========================================================================*/
    724 void QCameraPostProcessor::releaseJpegData(void *data, void *user_data)
    725 {
    726     QCameraPostProcessor *pme = (QCameraPostProcessor *)user_data;
    727     if (NULL != pme) {
    728         pme->releaseJpegJobData((qcamera_jpeg_data_t *)data);
    729     }
    730 }
    731 
    732 /*===========================================================================
    733  * FUNCTION   : releaseOngoingPPData
    734  *
    735  * DESCRIPTION: callback function to release ongoing postprocess job node
    736  *
    737  * PARAMETERS :
    738  *   @data      : ptr to onging postprocess job
    739  *   @user_data : user data ptr (QCameraReprocessor)
    740  *
    741  * RETURN     : None
    742  *==========================================================================*/
    743 void QCameraPostProcessor::releaseOngoingPPData(void *data, void *user_data)
    744 {
    745     QCameraPostProcessor *pme = (QCameraPostProcessor *)user_data;
    746     if (NULL != pme) {
    747         qcamera_pp_data_t *pp_job = (qcamera_pp_data_t *)data;
    748         if (NULL != pp_job->src_frame) {
    749             pme->releaseSuperBuf(pp_job->src_frame);
    750             free(pp_job->src_frame);
    751             pp_job->src_frame = NULL;
    752         }
    753     }
    754 }
    755 
    756 /*===========================================================================
    757  * FUNCTION   : releaseNotifyData
    758  *
    759  * DESCRIPTION: function to release internal resources in notify data struct
    760  *
    761  * PARAMETERS :
    762  *   @user_data  : ptr user data
    763  *   @cookie     : callback cookie
    764  *
    765  * RETURN     : None
    766  *
    767  * NOTE       : deallocate jpeg heap memory if it's not NULL
    768  *==========================================================================*/
    769 void QCameraPostProcessor::releaseNotifyData(void *user_data, void *cookie)
    770 {
    771     qcamera_data_argm_t *app_cb = ( qcamera_data_argm_t * ) user_data;
    772     QCameraPostProcessor *postProc = ( QCameraPostProcessor * ) cookie;
    773     if ( ( NULL != app_cb ) && ( NULL != postProc ) ) {
    774         if (app_cb && NULL != app_cb->release_data.data) {
    775             app_cb->release_data.data->release(app_cb->release_data.data);
    776             app_cb->release_data.data = NULL;
    777         }
    778         if (app_cb && NULL != app_cb->release_data.frame) {
    779             postProc->releaseSuperBuf(app_cb->release_data.frame);
    780             free(app_cb->release_data.frame);
    781             app_cb->release_data.frame = NULL;
    782         }
    783         free(app_cb);
    784     }
    785 }
    786 
    787 /*===========================================================================
    788  * FUNCTION   : releaseSuperBuf
    789  *
    790  * DESCRIPTION: function to release a superbuf frame by returning back to kernel
    791  *
    792  * PARAMETERS :
    793  *   @super_buf : ptr to the superbuf frame
    794  *
    795  * RETURN     : None
    796  *==========================================================================*/
    797 void QCameraPostProcessor::releaseSuperBuf(mm_camera_super_buf_t *super_buf)
    798 {
    799     QCameraChannel *pChannel = NULL;
    800 
    801     if (NULL != super_buf) {
    802         pChannel = m_parent->getChannelByHandle(super_buf->ch_id);
    803 
    804         if ( NULL == pChannel ) {
    805             if (m_pReprocChannel != NULL &&
    806                 m_pReprocChannel->getMyHandle() == super_buf->ch_id) {
    807                 pChannel = m_pReprocChannel;
    808             }
    809         }
    810 
    811         if (pChannel != NULL) {
    812             pChannel->bufDone(super_buf);
    813         } else {
    814             ALOGE(" %s : Channel id %d not found!!",
    815                   __func__,
    816                   super_buf->ch_id);
    817         }
    818     }
    819 }
    820 
    821 /*===========================================================================
    822  * FUNCTION   : releaseJpegJobData
    823  *
    824  * DESCRIPTION: function to release internal resources in jpeg job struct
    825  *
    826  * PARAMETERS :
    827  *   @job     : ptr to jpeg job struct
    828  *
    829  * RETURN     : None
    830  *
    831  * NOTE       : original source frame need to be queued back to kernel for
    832  *              future use. Output buf of jpeg job need to be released since
    833  *              it's allocated for each job. Exif object need to be deleted.
    834  *==========================================================================*/
    835 void QCameraPostProcessor::releaseJpegJobData(qcamera_jpeg_data_t *job)
    836 {
    837     ALOGV("%s: E", __func__);
    838     if (NULL != job) {
    839         if (NULL != job->src_reproc_frame) {
    840             releaseSuperBuf(job->src_reproc_frame);
    841             free(job->src_reproc_frame);
    842             job->src_reproc_frame = NULL;
    843         }
    844 
    845         if (NULL != job->src_frame) {
    846             releaseSuperBuf(job->src_frame);
    847             free(job->src_frame);
    848             job->src_frame = NULL;
    849         }
    850     }
    851     ALOGV("%s: X", __func__);
    852 }
    853 
    854 /*===========================================================================
    855  * FUNCTION   : getColorfmtFromImgFmt
    856  *
    857  * DESCRIPTION: function to return jpeg color format based on its image format
    858  *
    859  * PARAMETERS :
    860  *   @img_fmt : image format
    861  *
    862  * RETURN     : jpeg color format that can be understandable by omx lib
    863  *==========================================================================*/
    864 mm_jpeg_color_format QCameraPostProcessor::getColorfmtFromImgFmt(cam_format_t img_fmt)
    865 {
    866     switch (img_fmt) {
    867     case CAM_FORMAT_YUV_420_NV21:
    868         return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
    869     case CAM_FORMAT_YUV_420_NV21_ADRENO:
    870         return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
    871     case CAM_FORMAT_YUV_420_NV12:
    872         return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2;
    873     case CAM_FORMAT_YUV_420_YV12:
    874         return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2;
    875     case CAM_FORMAT_YUV_422_NV61:
    876         return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1;
    877     case CAM_FORMAT_YUV_422_NV16:
    878         return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1;
    879     default:
    880         return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
    881     }
    882 }
    883 
    884 /*===========================================================================
    885  * FUNCTION   : getJpegImgTypeFromImgFmt
    886  *
    887  * DESCRIPTION: function to return jpeg encode image type based on its image format
    888  *
    889  * PARAMETERS :
    890  *   @img_fmt : image format
    891  *
    892  * RETURN     : return jpeg source image format (YUV or Bitstream)
    893  *==========================================================================*/
    894 mm_jpeg_format_t QCameraPostProcessor::getJpegImgTypeFromImgFmt(cam_format_t img_fmt)
    895 {
    896     switch (img_fmt) {
    897     case CAM_FORMAT_YUV_420_NV21:
    898     case CAM_FORMAT_YUV_420_NV21_ADRENO:
    899     case CAM_FORMAT_YUV_420_NV12:
    900     case CAM_FORMAT_YUV_420_YV12:
    901     case CAM_FORMAT_YUV_422_NV61:
    902     case CAM_FORMAT_YUV_422_NV16:
    903         return MM_JPEG_FMT_YUV;
    904     default:
    905         return MM_JPEG_FMT_YUV;
    906     }
    907 }
    908 
    909 /*===========================================================================
    910  * FUNCTION   : encodeData
    911  *
    912  * DESCRIPTION: function to prepare encoding job information and send to
    913  *              mm-jpeg-interface to do the encoding job
    914  *
    915  * PARAMETERS :
    916  *   @jpeg_job_data : ptr to a struct saving job related information
    917  *   @needNewSess   : flag to indicate if a new jpeg encoding session need
    918  *                    to be created. After creation, this flag will be toggled
    919  *
    920  * RETURN     : int32_t type of status
    921  *              NO_ERROR  -- success
    922  *              none-zero failure code
    923  *==========================================================================*/
    924 int32_t QCameraPostProcessor::encodeData(qcamera_jpeg_data_t *jpeg_job_data,
    925                                          uint8_t &needNewSess)
    926 {
    927     ALOGV("%s : E", __func__);
    928     int32_t ret = NO_ERROR;
    929     mm_jpeg_job_t jpg_job;
    930     uint32_t jobId = 0;
    931     QCameraStream *main_stream = NULL;
    932     mm_camera_buf_def_t *main_frame = NULL;
    933     QCameraStream *thumb_stream = NULL;
    934     mm_camera_buf_def_t *thumb_frame = NULL;
    935     mm_camera_super_buf_t *recvd_frame = jpeg_job_data->src_frame;
    936 
    937     // find channel
    938     QCameraChannel *pChannel = m_parent->getChannelByHandle(recvd_frame->ch_id);
    939     // check reprocess channel if not found
    940     if (pChannel == NULL) {
    941         if (m_pReprocChannel != NULL &&
    942             m_pReprocChannel->getMyHandle() == recvd_frame->ch_id) {
    943             pChannel = m_pReprocChannel;
    944         }
    945     }
    946     if (pChannel == NULL) {
    947         ALOGE("%s: No corresponding channel (ch_id = %d) exist, return here",
    948               __func__, recvd_frame->ch_id);
    949         return BAD_VALUE;
    950     }
    951 
    952     // find snapshot frame and thumnail frame
    953     for (int i = 0; i < recvd_frame->num_bufs; i++) {
    954         QCameraStream *pStream =
    955             pChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id);
    956         if (pStream != NULL) {
    957             if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
    958                 pStream->isTypeOf(CAM_STREAM_TYPE_NON_ZSL_SNAPSHOT) ||
    959                 pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
    960                 pStream->isOrignalTypeOf(CAM_STREAM_TYPE_NON_ZSL_SNAPSHOT)) {
    961                 main_stream = pStream;
    962                 main_frame = recvd_frame->bufs[i];
    963             } else if (pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
    964                        pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) ||
    965                        pStream->isOrignalTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
    966                        pStream->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW)) {
    967                 thumb_stream = pStream;
    968                 thumb_frame = recvd_frame->bufs[i];
    969             }
    970         }
    971     }
    972 
    973     if(NULL == main_frame){
    974        ALOGE("%s : Main frame is NULL", __func__);
    975        return BAD_VALUE;
    976     }
    977 
    978     QCameraMemory *memObj = (QCameraMemory *)main_frame->mem_info;
    979     if (NULL == memObj) {
    980         ALOGE("%s : Memeory Obj of main frame is NULL", __func__);
    981         return NO_MEMORY;
    982     }
    983 
    984     // dump snapshot frame if enabled
    985     m_parent->dumpFrameToFile(main_frame->buffer, main_frame->frame_len,
    986                               main_frame->frame_idx, QCAMERA_DUMP_FRM_SNAPSHOT);
    987 
    988     // send upperlayer callback for raw image
    989     camera_memory_t *mem = memObj->getMemory(main_frame->buf_idx, false);
    990     if (NULL != m_parent->mDataCb &&
    991         m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE) > 0) {
    992         qcamera_callback_argm_t cbArg;
    993         memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
    994         cbArg.cb_type = QCAMERA_DATA_CALLBACK;
    995         cbArg.msg_type = CAMERA_MSG_RAW_IMAGE;
    996         cbArg.data = mem;
    997         cbArg.index = 1;
    998         m_parent->m_cbNotifier.notifyCallback(cbArg);
    999     }
   1000     if (NULL != m_parent->mNotifyCb &&
   1001         m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE_NOTIFY) > 0) {
   1002         qcamera_callback_argm_t cbArg;
   1003         memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
   1004         cbArg.cb_type = QCAMERA_NOTIFY_CALLBACK;
   1005         cbArg.msg_type = CAMERA_MSG_RAW_IMAGE_NOTIFY;
   1006         cbArg.ext1 = 0;
   1007         cbArg.ext2 = 0;
   1008         m_parent->m_cbNotifier.notifyCallback(cbArg);
   1009     }
   1010 
   1011     if (thumb_frame != NULL) {
   1012         // dump thumbnail frame if enabled
   1013         m_parent->dumpFrameToFile(thumb_frame->buffer, thumb_frame->frame_len,
   1014                                   thumb_frame->frame_idx, QCAMERA_DUMP_FRM_THUMBNAIL);
   1015     }
   1016 
   1017     if (mJpegClientHandle <= 0) {
   1018         ALOGE("%s: Error: bug here, mJpegClientHandle is 0", __func__);
   1019         return UNKNOWN_ERROR;
   1020     }
   1021 
   1022     if (needNewSess) {
   1023         // create jpeg encoding session
   1024         mm_jpeg_encode_params_t encodeParam;
   1025         memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t));
   1026         getJpegEncodingConfig(encodeParam, main_stream, thumb_stream);
   1027         ALOGD("[KPI Perf] %s : call jpeg create_session", __func__);
   1028         ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId);
   1029         if (ret != NO_ERROR) {
   1030             ALOGE("%s: error creating a new jpeg encoding session", __func__);
   1031             return ret;
   1032         }
   1033         needNewSess = FALSE;
   1034     }
   1035 
   1036     // Fill in new job
   1037     memset(&jpg_job, 0, sizeof(mm_jpeg_job_t));
   1038     jpg_job.job_type = JPEG_JOB_TYPE_ENCODE;
   1039     jpg_job.encode_job.session_id = mJpegSessionId;
   1040     jpg_job.encode_job.src_index = main_frame->buf_idx;
   1041     jpg_job.encode_job.dst_index = 0;
   1042 
   1043     cam_rect_t crop;
   1044     memset(&crop, 0, sizeof(cam_rect_t));
   1045     main_stream->getCropInfo(crop);
   1046 
   1047     cam_dimension_t src_dim;
   1048     memset(&src_dim, 0, sizeof(cam_dimension_t));
   1049     main_stream->getFrameDimension(src_dim);
   1050 
   1051     // main dim
   1052     jpg_job.encode_job.main_dim.src_dim = src_dim;
   1053     jpg_job.encode_job.main_dim.dst_dim = src_dim;
   1054     jpg_job.encode_job.main_dim.crop = crop;
   1055 
   1056     // thumbnail dim
   1057     if (m_bThumbnailNeeded == TRUE) {
   1058         if (thumb_stream == NULL) {
   1059             // need jpeg thumbnail, but no postview/preview stream exists
   1060             // we use the main stream/frame to encode thumbnail
   1061             thumb_stream = main_stream;
   1062             thumb_frame = main_frame;
   1063         }
   1064         memset(&crop, 0, sizeof(cam_rect_t));
   1065         thumb_stream->getCropInfo(crop);
   1066         memset(&src_dim, 0, sizeof(cam_dimension_t));
   1067         thumb_stream->getFrameDimension(src_dim);
   1068         jpg_job.encode_job.thumb_dim.src_dim = src_dim;
   1069         m_parent->getThumbnailSize(jpg_job.encode_job.thumb_dim.dst_dim);
   1070         int rotation = m_parent->getJpegRotation();
   1071         if (rotation == 90 || rotation ==270) {
   1072             // swap dimension if rotation is 90 or 270
   1073             int32_t temp = jpg_job.encode_job.thumb_dim.dst_dim.height;
   1074             jpg_job.encode_job.thumb_dim.dst_dim.height =
   1075                 jpg_job.encode_job.thumb_dim.dst_dim.width;
   1076             jpg_job.encode_job.thumb_dim.dst_dim.width = temp;
   1077         }
   1078         jpg_job.encode_job.thumb_dim.crop = crop;
   1079         jpg_job.encode_job.thumb_index = thumb_frame->buf_idx;
   1080     }
   1081 
   1082     // set rotation only when no online rotation or offline pp rotation is done before
   1083     if (!m_parent->needRotationReprocess()) {
   1084         jpg_job.encode_job.rotation = m_parent->getJpegRotation();
   1085     }
   1086     ALOGV("%s: jpeg rotation is set to %d", __func__, jpg_job.encode_job.rotation);
   1087 
   1088     // find meta data frame
   1089     mm_camera_buf_def_t *meta_frame = NULL;
   1090     for (int i = 0; i < jpeg_job_data->src_frame->num_bufs; i++) {
   1091         // look through input superbuf
   1092         if (jpeg_job_data->src_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) {
   1093             meta_frame = jpeg_job_data->src_frame->bufs[i];
   1094             break;
   1095         }
   1096     }
   1097     if (meta_frame == NULL && jpeg_job_data->src_reproc_frame != NULL) {
   1098         // look through reprocess source superbuf
   1099         for (int i = 0; i < jpeg_job_data->src_reproc_frame->num_bufs; i++) {
   1100             if (jpeg_job_data->src_reproc_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) {
   1101                 meta_frame = jpeg_job_data->src_reproc_frame->bufs[i];
   1102                 break;
   1103             }
   1104         }
   1105     }
   1106     if (meta_frame != NULL) {
   1107         // fill in meta data frame ptr
   1108         jpg_job.encode_job.p_metadata = (cam_metadata_info_t *)meta_frame->buffer;
   1109     }
   1110 
   1111     ALOGD("[KPI Perf] %s : call jpeg start_job", __func__);
   1112     ret = mJpegHandle.start_job(&jpg_job, &jobId);
   1113     if (ret == NO_ERROR) {
   1114         // remember job info
   1115         jpeg_job_data->jobId = jobId;
   1116     }
   1117 
   1118     return ret;
   1119 }
   1120 
   1121 /*===========================================================================
   1122  * FUNCTION   : processRawImageImpl
   1123  *
   1124  * DESCRIPTION: function to send raw image to upper layer
   1125  *
   1126  * PARAMETERS :
   1127  *   @recvd_frame   : frame to be encoded
   1128  *
   1129  * RETURN     : int32_t type of status
   1130  *              NO_ERROR  -- success
   1131  *              none-zero failure code
   1132  *==========================================================================*/
   1133 int32_t QCameraPostProcessor::processRawImageImpl(mm_camera_super_buf_t *recvd_frame)
   1134 {
   1135     int32_t rc = NO_ERROR;
   1136 
   1137     mm_camera_buf_def_t *frame = NULL;
   1138     for ( int i= 0 ; i < recvd_frame->num_bufs ; i++ ) {
   1139         if ( recvd_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_SNAPSHOT ||
   1140             recvd_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_NON_ZSL_SNAPSHOT ||
   1141              recvd_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_RAW ) {
   1142             frame = recvd_frame->bufs[i];
   1143             break;
   1144         }
   1145     }
   1146     if ( NULL == frame ) {
   1147         ALOGE("%s: No valid raw buffer", __func__);
   1148         return BAD_VALUE;
   1149     }
   1150 
   1151     QCameraMemory *rawMemObj = (QCameraMemory *)frame->mem_info;
   1152     camera_memory_t *raw_mem = NULL;
   1153 
   1154     if (rawMemObj != NULL) {
   1155         raw_mem = rawMemObj->getMemory(frame->buf_idx, false);
   1156     }
   1157 
   1158     if (NULL != rawMemObj && NULL != raw_mem) {
   1159         // dump frame into file
   1160         m_parent->dumpFrameToFile(frame->buffer, frame->frame_len,
   1161                                   frame->frame_idx, QCAMERA_DUMP_FRM_RAW);
   1162 
   1163         // send data callback / notify for RAW_IMAGE
   1164         if (NULL != m_parent->mDataCb &&
   1165             m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE) > 0) {
   1166             qcamera_callback_argm_t cbArg;
   1167             memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
   1168             cbArg.cb_type = QCAMERA_DATA_CALLBACK;
   1169             cbArg.msg_type = CAMERA_MSG_RAW_IMAGE;
   1170             cbArg.data = raw_mem;
   1171             cbArg.index = 0;
   1172             m_parent->m_cbNotifier.notifyCallback(cbArg);
   1173         }
   1174         if (NULL != m_parent->mNotifyCb &&
   1175             m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE_NOTIFY) > 0) {
   1176             qcamera_callback_argm_t cbArg;
   1177             memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
   1178             cbArg.cb_type = QCAMERA_NOTIFY_CALLBACK;
   1179             cbArg.msg_type = CAMERA_MSG_RAW_IMAGE_NOTIFY;
   1180             cbArg.ext1 = 0;
   1181             cbArg.ext2 = 0;
   1182             m_parent->m_cbNotifier.notifyCallback(cbArg);
   1183         }
   1184 
   1185         if ((m_parent->mDataCb != NULL) &&
   1186             m_parent->msgTypeEnabledWithLock(CAMERA_MSG_COMPRESSED_IMAGE) > 0) {
   1187             qcamera_release_data_t release_data;
   1188             memset(&release_data, 0, sizeof(qcamera_release_data_t));
   1189             release_data.frame = recvd_frame;
   1190             sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE,
   1191                            raw_mem,
   1192                            0,
   1193                            NULL,
   1194                            &release_data);
   1195         }
   1196     } else {
   1197         ALOGE("%s: Cannot get raw mem", __func__);
   1198         rc = UNKNOWN_ERROR;
   1199     }
   1200 
   1201     return rc;
   1202 }
   1203 
   1204 /*===========================================================================
   1205  * FUNCTION   : dataProcessRoutine
   1206  *
   1207  * DESCRIPTION: data process routine that handles input data either from input
   1208  *              Jpeg Queue to do jpeg encoding, or from input PP Queue to do
   1209  *              reprocess.
   1210  *
   1211  * PARAMETERS :
   1212  *   @data    : user data ptr (QCameraPostProcessor)
   1213  *
   1214  * RETURN     : None
   1215  *==========================================================================*/
   1216 void *QCameraPostProcessor::dataProcessRoutine(void *data)
   1217 {
   1218     int running = 1;
   1219     int ret;
   1220     uint8_t is_active = FALSE;
   1221     uint8_t needNewSess = TRUE;
   1222     QCameraPostProcessor *pme = (QCameraPostProcessor *)data;
   1223     QCameraCmdThread *cmdThread = &pme->m_dataProcTh;
   1224 
   1225     ALOGD("%s: E", __func__);
   1226     do {
   1227         do {
   1228             ret = cam_sem_wait(&cmdThread->cmd_sem);
   1229             if (ret != 0 && errno != EINVAL) {
   1230                 ALOGE("%s: cam_sem_wait error (%s)",
   1231                            __func__, strerror(errno));
   1232                 return NULL;
   1233             }
   1234         } while (ret != 0);
   1235 
   1236         // we got notified about new cmd avail in cmd queue
   1237         camera_cmd_type_t cmd = cmdThread->getCmd();
   1238         switch (cmd) {
   1239         case CAMERA_CMD_TYPE_START_DATA_PROC:
   1240             ALOGD("%s: start data proc", __func__);
   1241             is_active = TRUE;
   1242             needNewSess = TRUE;
   1243             break;
   1244         case CAMERA_CMD_TYPE_STOP_DATA_PROC:
   1245             {
   1246                 ALOGD("%s: stop data proc", __func__);
   1247                 is_active = FALSE;
   1248 
   1249                 // cancel all ongoing jpeg jobs
   1250                 qcamera_jpeg_data_t *jpeg_job =
   1251                     (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
   1252                 while (jpeg_job != NULL) {
   1253                     pme->mJpegHandle.abort_job(jpeg_job->jobId);
   1254 
   1255                     pme->releaseJpegJobData(jpeg_job);
   1256                     free(jpeg_job);
   1257 
   1258                     jpeg_job = (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
   1259                 }
   1260 
   1261                 // destroy jpeg encoding session
   1262                 if ( 0 < pme->mJpegSessionId ) {
   1263                     pme->mJpegHandle.destroy_session(pme->mJpegSessionId);
   1264                     pme->mJpegSessionId = 0;
   1265                 }
   1266 
   1267                 // free jpeg out buf and exif obj
   1268                 if (pme->m_pJpegOutputMem != NULL) {
   1269                     pme->m_pJpegOutputMem->deallocate();
   1270                     delete pme->m_pJpegOutputMem;
   1271                     pme->m_pJpegOutputMem = NULL;
   1272                 }
   1273                 if (pme->m_pJpegExifObj != NULL) {
   1274                     delete pme->m_pJpegExifObj;
   1275                     pme->m_pJpegExifObj = NULL;
   1276                 }
   1277                 needNewSess = TRUE;
   1278 
   1279                 // stop reproc channel if exists
   1280                 if (pme->m_pReprocChannel != NULL) {
   1281                     pme->m_pReprocChannel->stop();
   1282                     delete pme->m_pReprocChannel;
   1283                     pme->m_pReprocChannel = NULL;
   1284                 }
   1285 
   1286                 // flush ongoing postproc Queue
   1287                 pme->m_ongoingPPQ.flush();
   1288 
   1289                 // flush input jpeg Queue
   1290                 pme->m_inputJpegQ.flush();
   1291 
   1292                 // flush input Postproc Queue
   1293                 pme->m_inputPPQ.flush();
   1294 
   1295                 // flush input raw Queue
   1296                 pme->m_inputRawQ.flush();
   1297 
   1298                 // signal cmd is completed
   1299                 cam_sem_post(&cmdThread->sync_sem);
   1300             }
   1301             break;
   1302         case CAMERA_CMD_TYPE_DO_NEXT_JOB:
   1303             {
   1304                 ALOGD("%s: Do next job, active is %d", __func__, is_active);
   1305                 if (is_active == TRUE) {
   1306                     // check if there is any ongoing jpeg jobs
   1307                     if (pme->m_ongoingJpegQ.isEmpty()) {
   1308                         // no ongoing jpeg job, we are fine to send jpeg encoding job
   1309                         qcamera_jpeg_data_t *jpeg_job =
   1310                             (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
   1311 
   1312                         if (NULL != jpeg_job) {
   1313                             //play shutter sound
   1314                             pme->m_parent->playShutter();
   1315 
   1316                             // add into ongoing jpeg job Q
   1317                             pme->m_ongoingJpegQ.enqueue((void *)jpeg_job);
   1318                             ret = pme->encodeData(jpeg_job, needNewSess);
   1319                             if (NO_ERROR != ret) {
   1320                                 // dequeue the last one
   1321                                 pme->m_ongoingJpegQ.dequeue(false);
   1322 
   1323                                 pme->releaseJpegJobData(jpeg_job);
   1324                                 free(jpeg_job);
   1325                                 pme->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
   1326                             }
   1327                         }
   1328                     }
   1329 
   1330                     // process raw data if any
   1331                     mm_camera_super_buf_t *super_buf =
   1332                         (mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue();
   1333 
   1334                     if (NULL != super_buf) {
   1335                         //play shutter sound
   1336                         pme->m_parent->playShutter();
   1337                         ret = pme->processRawImageImpl(super_buf);
   1338                         if (NO_ERROR != ret) {
   1339                             pme->releaseSuperBuf(super_buf);
   1340                             free(super_buf);
   1341                             pme->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
   1342                         }
   1343                     }
   1344 
   1345                     mm_camera_super_buf_t *pp_frame =
   1346                         (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue();
   1347                     if (NULL != pp_frame) {
   1348                         qcamera_pp_data_t *pp_job =
   1349                             (qcamera_pp_data_t *)malloc(sizeof(qcamera_pp_data_t));
   1350                         if (pp_job != NULL) {
   1351                             memset(pp_job, 0, sizeof(qcamera_pp_data_t));
   1352                             if (pme->m_pReprocChannel != NULL) {
   1353                                 // add into ongoing PP job Q
   1354                                 pp_job->src_frame = pp_frame;
   1355                                 pme->m_ongoingPPQ.enqueue((void *)pp_job);
   1356                                 ret = pme->m_pReprocChannel->doReprocess(pp_frame);
   1357                                 if (NO_ERROR != ret) {
   1358                                     // remove from ongoing PP job Q
   1359                                     pme->m_ongoingPPQ.dequeue(false);
   1360                                 }
   1361                             } else {
   1362                                 ALOGE("%s: Reprocess channel is NULL", __func__);
   1363                                 ret = -1;
   1364                             }
   1365                         } else {
   1366                             ALOGE("%s: no mem for qcamera_pp_data_t", __func__);
   1367                             ret = -1;
   1368                         }
   1369 
   1370                         if (0 != ret) {
   1371                             // free pp_job
   1372                             if (pp_job != NULL) {
   1373                                 free(pp_job);
   1374                             }
   1375                             // free frame
   1376                             if (pp_frame != NULL) {
   1377                                 pme->releaseSuperBuf(pp_frame);
   1378                                 free(pp_frame);
   1379                             }
   1380                             // send error notify
   1381                             pme->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
   1382                         }
   1383                     }
   1384                 } else {
   1385                     // not active, simply return buf and do no op
   1386                     qcamera_jpeg_data_t *jpeg_data =
   1387                         (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
   1388                     if (NULL != jpeg_data) {
   1389                         pme->releaseJpegJobData(jpeg_data);
   1390                         free(jpeg_data);
   1391                     }
   1392                     mm_camera_super_buf_t *super_buf =
   1393                         (mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue();
   1394                     if (NULL != super_buf) {
   1395                         pme->releaseSuperBuf(super_buf);
   1396                         free(super_buf);
   1397                     }
   1398                     super_buf = (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue();
   1399                     if (NULL != super_buf) {
   1400                         pme->releaseSuperBuf(super_buf);
   1401                         free(super_buf);
   1402                     }
   1403                 }
   1404             }
   1405             break;
   1406         case CAMERA_CMD_TYPE_EXIT:
   1407             running = 0;
   1408             break;
   1409         default:
   1410             break;
   1411         }
   1412     } while (running);
   1413     ALOGD("%s: X", __func__);
   1414     return NULL;
   1415 }
   1416 
   1417 /*===========================================================================
   1418  * FUNCTION   : getJpegPaddingReq
   1419  *
   1420  * DESCRIPTION: function to add an entry to exif data
   1421  *
   1422  * PARAMETERS :
   1423  *   @padding_info : jpeg specific padding requirement
   1424  *
   1425  * RETURN     : int32_t type of status
   1426  *              NO_ERROR  -- success
   1427  *              none-zero failure code
   1428  *==========================================================================*/
   1429 int32_t QCameraPostProcessor::getJpegPaddingReq(cam_padding_info_t &padding_info)
   1430 {
   1431     // TODO: hardcode for now, needs to query from mm-jpeg-interface
   1432     padding_info.width_padding  = CAM_PAD_NONE;
   1433     padding_info.height_padding  = CAM_PAD_TO_16;
   1434     padding_info.plane_padding  = CAM_PAD_TO_WORD;
   1435     return NO_ERROR;
   1436 }
   1437 
   1438 /*===========================================================================
   1439  * FUNCTION   : QCameraExif
   1440  *
   1441  * DESCRIPTION: constructor of QCameraExif
   1442  *
   1443  * PARAMETERS : None
   1444  *
   1445  * RETURN     : None
   1446  *==========================================================================*/
   1447 QCameraExif::QCameraExif()
   1448     : m_nNumEntries(0)
   1449 {
   1450     memset(m_Entries, 0, sizeof(m_Entries));
   1451 }
   1452 
   1453 /*===========================================================================
   1454  * FUNCTION   : ~QCameraExif
   1455  *
   1456  * DESCRIPTION: deconstructor of QCameraExif. Will release internal memory ptr.
   1457  *
   1458  * PARAMETERS : None
   1459  *
   1460  * RETURN     : None
   1461  *==========================================================================*/
   1462 QCameraExif::~QCameraExif()
   1463 {
   1464     for (uint32_t i = 0; i < m_nNumEntries; i++) {
   1465         switch (m_Entries[i].tag_entry.type) {
   1466         case EXIF_BYTE:
   1467             {
   1468                 if (m_Entries[i].tag_entry.count > 1 &&
   1469                     m_Entries[i].tag_entry.data._bytes != NULL) {
   1470                     free(m_Entries[i].tag_entry.data._bytes);
   1471                     m_Entries[i].tag_entry.data._bytes = NULL;
   1472                 }
   1473             }
   1474             break;
   1475         case EXIF_ASCII:
   1476             {
   1477                 if (m_Entries[i].tag_entry.data._ascii != NULL) {
   1478                     free(m_Entries[i].tag_entry.data._ascii);
   1479                     m_Entries[i].tag_entry.data._ascii = NULL;
   1480                 }
   1481             }
   1482             break;
   1483         case EXIF_SHORT:
   1484             {
   1485                 if (m_Entries[i].tag_entry.count > 1 &&
   1486                     m_Entries[i].tag_entry.data._shorts != NULL) {
   1487                     free(m_Entries[i].tag_entry.data._shorts);
   1488                     m_Entries[i].tag_entry.data._shorts = NULL;
   1489                 }
   1490             }
   1491             break;
   1492         case EXIF_LONG:
   1493             {
   1494                 if (m_Entries[i].tag_entry.count > 1 &&
   1495                     m_Entries[i].tag_entry.data._longs != NULL) {
   1496                     free(m_Entries[i].tag_entry.data._longs);
   1497                     m_Entries[i].tag_entry.data._longs = NULL;
   1498                 }
   1499             }
   1500             break;
   1501         case EXIF_RATIONAL:
   1502             {
   1503                 if (m_Entries[i].tag_entry.count > 1 &&
   1504                     m_Entries[i].tag_entry.data._rats != NULL) {
   1505                     free(m_Entries[i].tag_entry.data._rats);
   1506                     m_Entries[i].tag_entry.data._rats = NULL;
   1507                 }
   1508             }
   1509             break;
   1510         case EXIF_UNDEFINED:
   1511             {
   1512                 if (m_Entries[i].tag_entry.data._undefined != NULL) {
   1513                     free(m_Entries[i].tag_entry.data._undefined);
   1514                     m_Entries[i].tag_entry.data._undefined = NULL;
   1515                 }
   1516             }
   1517             break;
   1518         case EXIF_SLONG:
   1519             {
   1520                 if (m_Entries[i].tag_entry.count > 1 &&
   1521                     m_Entries[i].tag_entry.data._slongs != NULL) {
   1522                     free(m_Entries[i].tag_entry.data._slongs);
   1523                     m_Entries[i].tag_entry.data._slongs = NULL;
   1524                 }
   1525             }
   1526             break;
   1527         case EXIF_SRATIONAL:
   1528             {
   1529                 if (m_Entries[i].tag_entry.count > 1 &&
   1530                     m_Entries[i].tag_entry.data._srats != NULL) {
   1531                     free(m_Entries[i].tag_entry.data._srats);
   1532                     m_Entries[i].tag_entry.data._srats = NULL;
   1533                 }
   1534             }
   1535             break;
   1536         }
   1537     }
   1538 }
   1539 
   1540 /*===========================================================================
   1541  * FUNCTION   : addEntry
   1542  *
   1543  * DESCRIPTION: function to add an entry to exif data
   1544  *
   1545  * PARAMETERS :
   1546  *   @tagid   : exif tag ID
   1547  *   @type    : data type
   1548  *   @count   : number of data in uint of its type
   1549  *   @data    : input data ptr
   1550  *
   1551  * RETURN     : int32_t type of status
   1552  *              NO_ERROR  -- success
   1553  *              none-zero failure code
   1554  *==========================================================================*/
   1555 int32_t QCameraExif::addEntry(exif_tag_id_t tagid,
   1556                               exif_tag_type_t type,
   1557                               uint32_t count,
   1558                               void *data)
   1559 {
   1560     int32_t rc = NO_ERROR;
   1561     if(m_nNumEntries >= MAX_EXIF_TABLE_ENTRIES) {
   1562         ALOGE("%s: Number of entries exceeded limit", __func__);
   1563         return NO_MEMORY;
   1564     }
   1565 
   1566     m_Entries[m_nNumEntries].tag_id = tagid;
   1567     m_Entries[m_nNumEntries].tag_entry.type = type;
   1568     m_Entries[m_nNumEntries].tag_entry.count = count;
   1569     m_Entries[m_nNumEntries].tag_entry.copy = 1;
   1570     switch (type) {
   1571     case EXIF_BYTE:
   1572         {
   1573             if (count > 1) {
   1574                 uint8_t *values = (uint8_t *)malloc(count);
   1575                 if (values == NULL) {
   1576                     ALOGE("%s: No memory for byte array", __func__);
   1577                     rc = NO_MEMORY;
   1578                 } else {
   1579                     memcpy(values, data, count);
   1580                     m_Entries[m_nNumEntries].tag_entry.data._bytes = values;
   1581                 }
   1582             } else {
   1583                 m_Entries[m_nNumEntries].tag_entry.data._byte = *(uint8_t *)data;
   1584             }
   1585         }
   1586         break;
   1587     case EXIF_ASCII:
   1588         {
   1589             char *str = NULL;
   1590             str = (char *)malloc(count + 1);
   1591             if (str == NULL) {
   1592                 ALOGE("%s: No memory for ascii string", __func__);
   1593                 rc = NO_MEMORY;
   1594             } else {
   1595                 memset(str, 0, count + 1);
   1596                 memcpy(str, data, count);
   1597                 m_Entries[m_nNumEntries].tag_entry.data._ascii = str;
   1598             }
   1599         }
   1600         break;
   1601     case EXIF_SHORT:
   1602         {
   1603             if (count > 1) {
   1604                 uint16_t *values = (uint16_t *)malloc(count * sizeof(uint16_t));
   1605                 if (values == NULL) {
   1606                     ALOGE("%s: No memory for short array", __func__);
   1607                     rc = NO_MEMORY;
   1608                 } else {
   1609                     memcpy(values, data, count * sizeof(uint16_t));
   1610                     m_Entries[m_nNumEntries].tag_entry.data._shorts = values;
   1611                 }
   1612             } else {
   1613                 m_Entries[m_nNumEntries].tag_entry.data._short = *(uint16_t *)data;
   1614             }
   1615         }
   1616         break;
   1617     case EXIF_LONG:
   1618         {
   1619             if (count > 1) {
   1620                 uint32_t *values = (uint32_t *)malloc(count * sizeof(uint32_t));
   1621                 if (values == NULL) {
   1622                     ALOGE("%s: No memory for long array", __func__);
   1623                     rc = NO_MEMORY;
   1624                 } else {
   1625                     memcpy(values, data, count * sizeof(uint32_t));
   1626                     m_Entries[m_nNumEntries].tag_entry.data._longs = values;
   1627                 }
   1628             } else {
   1629                 m_Entries[m_nNumEntries].tag_entry.data._long = *(uint32_t *)data;
   1630             }
   1631         }
   1632         break;
   1633     case EXIF_RATIONAL:
   1634         {
   1635             if (count > 1) {
   1636                 rat_t *values = (rat_t *)malloc(count * sizeof(rat_t));
   1637                 if (values == NULL) {
   1638                     ALOGE("%s: No memory for rational array", __func__);
   1639                     rc = NO_MEMORY;
   1640                 } else {
   1641                     memcpy(values, data, count * sizeof(rat_t));
   1642                     m_Entries[m_nNumEntries].tag_entry.data._rats = values;
   1643                 }
   1644             } else {
   1645                 m_Entries[m_nNumEntries].tag_entry.data._rat = *(rat_t *)data;
   1646             }
   1647         }
   1648         break;
   1649     case EXIF_UNDEFINED:
   1650         {
   1651             uint8_t *values = (uint8_t *)malloc(count);
   1652             if (values == NULL) {
   1653                 ALOGE("%s: No memory for undefined array", __func__);
   1654                 rc = NO_MEMORY;
   1655             } else {
   1656                 memcpy(values, data, count);
   1657                 m_Entries[m_nNumEntries].tag_entry.data._undefined = values;
   1658             }
   1659         }
   1660         break;
   1661     case EXIF_SLONG:
   1662         {
   1663             if (count > 1) {
   1664                 int32_t *values = (int32_t *)malloc(count * sizeof(int32_t));
   1665                 if (values == NULL) {
   1666                     ALOGE("%s: No memory for signed long array", __func__);
   1667                     rc = NO_MEMORY;
   1668                 } else {
   1669                     memcpy(values, data, count * sizeof(int32_t));
   1670                     m_Entries[m_nNumEntries].tag_entry.data._slongs = values;
   1671                 }
   1672             } else {
   1673                 m_Entries[m_nNumEntries].tag_entry.data._slong = *(int32_t *)data;
   1674             }
   1675         }
   1676         break;
   1677     case EXIF_SRATIONAL:
   1678         {
   1679             if (count > 1) {
   1680                 srat_t *values = (srat_t *)malloc(count * sizeof(srat_t));
   1681                 if (values == NULL) {
   1682                     ALOGE("%s: No memory for signed rational array", __func__);
   1683                     rc = NO_MEMORY;
   1684                 } else {
   1685                     memcpy(values, data, count * sizeof(srat_t));
   1686                     m_Entries[m_nNumEntries].tag_entry.data._srats = values;
   1687                 }
   1688             } else {
   1689                 m_Entries[m_nNumEntries].tag_entry.data._srat = *(srat_t *)data;
   1690             }
   1691         }
   1692         break;
   1693     }
   1694 
   1695     // Increase number of entries
   1696     m_nNumEntries++;
   1697     return rc;
   1698 }
   1699 
   1700 }; // namespace qcamera
   1701