QCamera3PostProc.cpp revision 9a351c81529b36fd8b6978ca21a27bdc56a01355
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 "QCamera3PostProc"
31
32#include <stdlib.h>
33#include <utils/Errors.h>
34
35#include "QCamera3PostProc.h"
36#include "QCamera3HWI.h"
37#include "QCamera3Channel.h"
38#include "QCamera3Stream.h"
39
40namespace qcamera {
41
42/*===========================================================================
43 * FUNCTION   : QCamera3PostProcessor
44 *
45 * DESCRIPTION: constructor of QCamera3PostProcessor.
46 *
47 * PARAMETERS :
48 *   @cam_ctrl : ptr to HWI object
49 *
50 * RETURN     : None
51 *==========================================================================*/
52QCamera3PostProcessor::QCamera3PostProcessor(QCamera3PicChannel* ch_ctrl)
53    : m_parent(ch_ctrl),
54      mJpegCB(NULL),
55      mJpegUserData(NULL),
56      mJpegClientHandle(0),
57      mJpegSessionId(0),
58      m_pJpegExifObj(NULL),
59      m_bThumbnailNeeded(TRUE),
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   : ~QCamera3PostProcessor
71 *
72 * DESCRIPTION: deconstructor of QCamera3PostProcessor.
73 *
74 * PARAMETERS : None
75 *
76 * RETURN     : None
77 *==========================================================================*/
78QCamera3PostProcessor::~QCamera3PostProcessor()
79{
80    if (m_pJpegExifObj != NULL) {
81        delete m_pJpegExifObj;
82        m_pJpegExifObj = NULL;
83    }
84}
85
86/*===========================================================================
87 * FUNCTION   : init
88 *
89 * DESCRIPTION: initialization of postprocessor
90 *
91 * PARAMETERS :
92 *   @jpeg_cb      : callback to handle jpeg event from mm-camera-interface
93 *   @user_data    : user data ptr for jpeg callback
94 *
95 * RETURN     : int32_t type of status
96 *              NO_ERROR  -- success
97 *              none-zero failure code
98 *==========================================================================*/
99int32_t QCamera3PostProcessor::init(jpeg_encode_callback_t jpeg_cb, void *user_data)
100{
101    mJpegCB = jpeg_cb;
102    mJpegUserData = user_data;
103
104    mJpegClientHandle = jpeg_open(&mJpegHandle);
105    if(!mJpegClientHandle) {
106        ALOGE("%s : jpeg_open did not work", __func__);
107        return UNKNOWN_ERROR;
108    }
109
110    m_dataProcTh.launch(dataProcessRoutine, this);
111
112    return NO_ERROR;
113}
114
115/*===========================================================================
116 * FUNCTION   : deinit
117 *
118 * DESCRIPTION: de-initialization of postprocessor
119 *
120 * PARAMETERS : None
121 *
122 * RETURN     : int32_t type of status
123 *              NO_ERROR  -- success
124 *              none-zero failure code
125 *==========================================================================*/
126int32_t QCamera3PostProcessor::deinit()
127{
128    m_dataProcTh.exit();
129
130    if(mJpegClientHandle > 0) {
131        int rc = mJpegHandle.close(mJpegClientHandle);
132        ALOGD("%s: Jpeg closed, rc = %d, mJpegClientHandle = %x",
133              __func__, rc, mJpegClientHandle);
134        mJpegClientHandle = 0;
135        memset(&mJpegHandle, 0, sizeof(mJpegHandle));
136    }
137
138    return NO_ERROR;
139}
140
141/*===========================================================================
142 * FUNCTION   : start
143 *
144 * DESCRIPTION: start postprocessor. Data process thread and data notify thread
145 *              will be launched.
146 *
147 * PARAMETERS :
148 *   @pSrcChannel : source channel obj ptr that possibly needs reprocess
149 *
150 * RETURN     : int32_t type of status
151 *              NO_ERROR  -- success
152 *              none-zero failure code
153 *
154 * NOTE       : if any reprocess is needed, a reprocess channel/stream
155 *              will be started.
156 *==========================================================================*/
157int32_t QCamera3PostProcessor::start(QCamera3Memory* mMemory, int index)
158{
159    int32_t rc = NO_ERROR;
160    mJpegMem = mMemory;
161    mJpegMemIndex = index;
162    m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, FALSE, FALSE);
163
164    return rc;
165}
166
167/*===========================================================================
168 * FUNCTION   : stop
169 *
170 * DESCRIPTION: stop postprocessor. Data process and notify thread will be stopped.
171 *
172 * PARAMETERS : None
173 *
174 * RETURN     : int32_t type of status
175 *              NO_ERROR  -- success
176 *              none-zero failure code
177 *
178 * NOTE       : reprocess channel will be stopped and deleted if there is any
179 *==========================================================================*/
180int32_t QCamera3PostProcessor::stop()
181{
182    m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE);
183
184    return NO_ERROR;
185}
186
187/*===========================================================================
188 * FUNCTION   : getJpegEncodingConfig
189 *
190 * DESCRIPTION: function to prepare encoding job information
191 *
192 * PARAMETERS :
193 *   @encode_parm   : param to be filled with encoding configuration
194 *
195 * RETURN     : int32_t type of status
196 *              NO_ERROR  -- success
197 *              none-zero failure code
198 *==========================================================================*/
199int32_t QCamera3PostProcessor::getJpegEncodingConfig(mm_jpeg_encode_params_t& encode_parm,
200                                                    QCamera3Stream *main_stream,
201                                                    QCamera3Stream *thumb_stream)
202{
203    ALOGV("%s : E", __func__);
204    int32_t ret = NO_ERROR;
205
206    encode_parm.jpeg_cb = mJpegCB;
207    encode_parm.userdata = mJpegUserData;
208
209    m_bThumbnailNeeded = TRUE; // need encode thumbnail by default
210    cam_dimension_t thumbnailSize;
211    memset(&thumbnailSize, 0, sizeof(cam_dimension_t));
212    m_parent->getThumbnailSize(thumbnailSize);
213    if (thumbnailSize.width == 0 && thumbnailSize.height == 0) {
214        // (0,0) means no thumbnail
215        m_bThumbnailNeeded = FALSE;
216    }
217    encode_parm.encode_thumbnail = m_bThumbnailNeeded;
218
219    // get color format
220    cam_format_t img_fmt = CAM_FORMAT_YUV_420_NV12;  //default value
221    main_stream->getFormat(img_fmt);
222    encode_parm.color_format = getColorfmtFromImgFmt(img_fmt);
223
224    // get jpeg quality
225    encode_parm.quality = m_parent->getJpegQuality();
226    if (encode_parm.quality <= 0) {
227        encode_parm.quality = 85;
228    }
229
230    // get exif data
231    if (m_pJpegExifObj != NULL) {
232        delete m_pJpegExifObj;
233        m_pJpegExifObj = NULL;
234    }
235    m_pJpegExifObj = m_parent->getExifData();
236    if (m_pJpegExifObj != NULL) {
237        encode_parm.exif_info.exif_data = m_pJpegExifObj->getEntries();
238        encode_parm.exif_info.numOfEntries = m_pJpegExifObj->getNumOfEntries();
239    }
240
241    cam_frame_len_offset_t main_offset;
242    memset(&main_offset, 0, sizeof(cam_frame_len_offset_t));
243    main_stream->getFrameOffset(main_offset);
244
245    // src buf config
246    //Pass input main image buffer info to encoder.
247    QCamera3Memory *pStreamMem = main_stream->getStreamBufs();
248    if (pStreamMem == NULL) {
249        ALOGE("%s: cannot get stream bufs from main stream", __func__);
250        ret = BAD_VALUE;
251        goto on_error;
252    }
253    encode_parm.num_src_bufs = pStreamMem->getCnt();
254    for (uint32_t i = 0; i < encode_parm.num_src_bufs; i++) {
255        if (pStreamMem != NULL) {
256            encode_parm.src_main_buf[i].index = i;
257            encode_parm.src_main_buf[i].buf_size = pStreamMem->getSize(i);
258            encode_parm.src_main_buf[i].buf_vaddr = (uint8_t *)pStreamMem->getPtr(i);
259            encode_parm.src_main_buf[i].fd = pStreamMem->getFd(i);
260            encode_parm.src_main_buf[i].format = MM_JPEG_FMT_YUV;
261            encode_parm.src_main_buf[i].offset = main_offset;
262        }
263    }
264
265    //Pass input thumbnail buffer info to encoder.
266    //Note: In this version thumb_stream = main_stream
267    if (m_bThumbnailNeeded == TRUE) {
268        if (thumb_stream == NULL) {
269            thumb_stream = main_stream;
270        }
271        pStreamMem = thumb_stream->getStreamBufs();
272        if (pStreamMem == NULL) {
273            ALOGE("%s: cannot get stream bufs from thumb stream", __func__);
274            ret = BAD_VALUE;
275            goto on_error;
276        }
277        cam_frame_len_offset_t thumb_offset;
278        memset(&thumb_offset, 0, sizeof(cam_frame_len_offset_t));
279        thumb_stream->getFrameOffset(thumb_offset);
280        encode_parm.num_tmb_bufs = pStreamMem->getCnt();
281        for (int i = 0; i < pStreamMem->getCnt(); i++) {
282            if (pStreamMem != NULL) {
283                encode_parm.src_thumb_buf[i].index = i;
284                encode_parm.src_thumb_buf[i].buf_size = pStreamMem->getSize(i);
285                encode_parm.src_thumb_buf[i].buf_vaddr = (uint8_t *)pStreamMem->getPtr(i);
286                encode_parm.src_thumb_buf[i].fd = pStreamMem->getFd(i);
287                encode_parm.src_thumb_buf[i].format = MM_JPEG_FMT_YUV;
288                encode_parm.src_thumb_buf[i].offset = thumb_offset;
289            }
290        }
291    }
292
293    //Pass output jpeg buffer info to encoder.
294    //mJpegMem is allocated by framework.
295    encode_parm.num_dst_bufs = 1;
296    encode_parm.dest_buf[0].index = 0;
297    encode_parm.dest_buf[0].buf_size = mJpegMem->getSize(mJpegMemIndex);
298    encode_parm.dest_buf[0].buf_vaddr = (uint8_t *)mJpegMem->getPtr(mJpegMemIndex);
299    encode_parm.dest_buf[0].fd = mJpegMem->getFd(mJpegMemIndex);
300    encode_parm.dest_buf[0].format = MM_JPEG_FMT_YUV;
301    encode_parm.dest_buf[0].offset = main_offset;
302
303    ALOGV("%s : X", __func__);
304    return NO_ERROR;
305
306on_error:
307    if (m_pJpegExifObj != NULL) {
308        delete m_pJpegExifObj;
309        m_pJpegExifObj = NULL;
310    }
311    ALOGV("%s : X with error %d", __func__, ret);
312    return ret;
313}
314
315/*===========================================================================
316 * FUNCTION   : processData
317 *
318 * DESCRIPTION: enqueue data into dataProc thread
319 *
320 * PARAMETERS :
321 *   @frame   : process frame received from mm-camera-interface
322 *
323 * RETURN     : int32_t type of status
324 *              NO_ERROR  -- success
325 *              none-zero failure code
326 *
327 * NOTE       : depends on if offline reprocess is needed, received frame will
328 *              be sent to either input queue of postprocess or jpeg encoding
329 *==========================================================================*/
330int32_t QCamera3PostProcessor::processData(mm_camera_super_buf_t *frame)
331{
332    ALOGD("%s: no need offline reprocess, sending to jpeg encoding", __func__);
333    qcamera_jpeg_data_t *jpeg_job =
334        (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t));
335    if (jpeg_job == NULL) {
336        ALOGE("%s: No memory for jpeg job", __func__);
337        return NO_MEMORY;
338    }
339
340    memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t));
341    jpeg_job->src_frame = frame;
342
343    // enqueu to jpeg input queue
344    m_inputJpegQ.enqueue((void *)jpeg_job);
345    m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
346
347    return NO_ERROR;
348}
349
350/*===========================================================================
351 * FUNCTION   : processRawData
352 *
353 * DESCRIPTION: enqueue raw data into dataProc thread
354 *
355 * PARAMETERS :
356 *   @frame   : process frame received from mm-camera-interface
357 *
358 * RETURN     : int32_t type of status
359 *              NO_ERROR  -- success
360 *              none-zero failure code
361 *==========================================================================*/
362int32_t QCamera3PostProcessor::processRawData(mm_camera_super_buf_t *frame)
363{
364    // enqueu to raw input queue
365    m_inputRawQ.enqueue((void *)frame);
366    m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
367    return NO_ERROR;
368}
369
370/*===========================================================================
371 * FUNCTION   : processPPData
372 *
373 * DESCRIPTION: process received frame after reprocess.
374 *
375 * PARAMETERS :
376 *   @frame   : received frame from reprocess channel.
377 *
378 * RETURN     : int32_t type of status
379 *              NO_ERROR  -- success
380 *              none-zero failure code
381 *
382 * NOTE       : The frame after reprocess need to send to jpeg encoding.
383 *==========================================================================*/
384int32_t QCamera3PostProcessor::processPPData(mm_camera_super_buf_t *frame)
385{
386    qcamera_pp_data_t *job = (qcamera_pp_data_t *)m_ongoingPPQ.dequeue();
387
388    if (job == NULL || job->src_frame == NULL) {
389        ALOGE("%s: Cannot find reprocess job", __func__);
390        return BAD_VALUE;
391    }
392
393    qcamera_jpeg_data_t *jpeg_job =
394        (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t));
395    if (jpeg_job == NULL) {
396        ALOGE("%s: No memory for jpeg job", __func__);
397        return NO_MEMORY;
398    }
399
400    memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t));
401    jpeg_job->src_frame = frame;
402    jpeg_job->src_reproc_frame = job->src_frame;
403
404    // free pp job buf
405    free(job);
406
407    // enqueu reprocessed frame to jpeg input queue
408    m_inputJpegQ.enqueue((void *)jpeg_job);
409
410    // wait up data proc thread
411    m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
412
413    return NO_ERROR;
414}
415
416/*===========================================================================
417 * FUNCTION   : findJpegJobByJobId
418 *
419 * DESCRIPTION: find a jpeg job from ongoing Jpeg queue by its job ID
420 *
421 * PARAMETERS :
422 *   @jobId   : job Id of the job
423 *
424 * RETURN     : ptr to a jpeg job struct. NULL if not found.
425 *
426 * NOTE       : Currently only one job is sending to mm-jpeg-interface for jpeg
427 *              encoding. Therefore simply dequeue from the ongoing Jpeg Queue
428 *              will serve the purpose to find the jpeg job.
429 *==========================================================================*/
430qcamera_jpeg_data_t *QCamera3PostProcessor::findJpegJobByJobId(uint32_t jobId)
431{
432    qcamera_jpeg_data_t * job = NULL;
433    if (jobId == 0) {
434        ALOGE("%s: not a valid jpeg jobId", __func__);
435        return NULL;
436    }
437
438    // currely only one jpeg job ongoing, so simply dequeue the head
439    job = (qcamera_jpeg_data_t *)m_ongoingJpegQ.dequeue();
440    return job;
441}
442
443/*===========================================================================
444 * FUNCTION   : releasePPInputData
445 *
446 * DESCRIPTION: callback function to release post process input data node
447 *
448 * PARAMETERS :
449 *   @data      : ptr to post process input data
450 *   @user_data : user data ptr (QCamera3Reprocessor)
451 *
452 * RETURN     : None
453 *==========================================================================*/
454void QCamera3PostProcessor::releasePPInputData(void *data, void *user_data)
455{
456    QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data;
457    if (NULL != pme) {
458        pme->releaseSuperBuf((mm_camera_super_buf_t *)data);
459    }
460}
461
462/*===========================================================================
463 * FUNCTION   : releaseJpegData
464 *
465 * DESCRIPTION: callback function to release jpeg job node
466 *
467 * PARAMETERS :
468 *   @data      : ptr to ongoing jpeg job data
469 *   @user_data : user data ptr (QCamera3Reprocessor)
470 *
471 * RETURN     : None
472 *==========================================================================*/
473void QCamera3PostProcessor::releaseJpegData(void *data, void *user_data)
474{
475    QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data;
476    if (NULL != pme) {
477        pme->releaseJpegJobData((qcamera_jpeg_data_t *)data);
478    }
479}
480
481/*===========================================================================
482 * FUNCTION   : releaseOngoingPPData
483 *
484 * DESCRIPTION: callback function to release ongoing postprocess job node
485 *
486 * PARAMETERS :
487 *   @data      : ptr to onging postprocess job
488 *   @user_data : user data ptr (QCamera3Reprocessor)
489 *
490 * RETURN     : None
491 *==========================================================================*/
492void QCamera3PostProcessor::releaseOngoingPPData(void *data, void *user_data)
493{
494    QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data;
495    if (NULL != pme) {
496        qcamera_pp_data_t *pp_job = (qcamera_pp_data_t *)data;
497        if (NULL != pp_job->src_frame) {
498            pme->releaseSuperBuf(pp_job->src_frame);
499            free(pp_job->src_frame);
500            pp_job->src_frame = NULL;
501        }
502    }
503}
504
505/*===========================================================================
506 * FUNCTION   : releaseSuperBuf
507 *
508 * DESCRIPTION: function to release a superbuf frame by returning back to kernel
509 *
510 * PARAMETERS :
511 *   @super_buf : ptr to the superbuf frame
512 *
513 * RETURN     : None
514 *==========================================================================*/
515void QCamera3PostProcessor::releaseSuperBuf(mm_camera_super_buf_t *super_buf)
516{
517    if (NULL != super_buf) {
518        if (m_parent != NULL) {
519            m_parent->bufDone(super_buf);
520        }
521    }
522}
523
524/*===========================================================================
525 * FUNCTION   : releaseJpegJobData
526 *
527 * DESCRIPTION: function to release internal resources in jpeg job struct
528 *
529 * PARAMETERS :
530 *   @job     : ptr to jpeg job struct
531 *
532 * RETURN     : None
533 *
534 * NOTE       : original source frame need to be queued back to kernel for
535 *              future use. Output buf of jpeg job need to be released since
536 *              it's allocated for each job. Exif object need to be deleted.
537 *==========================================================================*/
538void QCamera3PostProcessor::releaseJpegJobData(qcamera_jpeg_data_t *job)
539{
540    ALOGV("%s: E", __func__);
541    if (NULL != job) {
542        if (NULL != job->src_reproc_frame) {
543            releaseSuperBuf(job->src_reproc_frame);
544            free(job->src_reproc_frame);
545            job->src_reproc_frame = NULL;
546        }
547
548        if (NULL != job->src_frame) {
549            releaseSuperBuf(job->src_frame);
550            free(job->src_frame);
551            job->src_frame = NULL;
552        }
553        mJpegMem = NULL;
554    }
555    ALOGV("%s: X", __func__);
556}
557
558/*===========================================================================
559 * FUNCTION   : getColorfmtFromImgFmt
560 *
561 * DESCRIPTION: function to return jpeg color format based on its image format
562 *
563 * PARAMETERS :
564 *   @img_fmt : image format
565 *
566 * RETURN     : jpeg color format that can be understandable by omx lib
567 *==========================================================================*/
568mm_jpeg_color_format QCamera3PostProcessor::getColorfmtFromImgFmt(cam_format_t img_fmt)
569{
570    switch (img_fmt) {
571    case CAM_FORMAT_YUV_420_NV21:
572        return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
573    case CAM_FORMAT_YUV_420_NV21_ADRENO:
574        return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
575    case CAM_FORMAT_YUV_420_NV12:
576        return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2;
577    case CAM_FORMAT_YUV_420_YV12:
578        return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2;
579    case CAM_FORMAT_YUV_422_NV61:
580        return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1;
581    case CAM_FORMAT_YUV_422_NV16:
582        return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1;
583    default:
584        return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
585    }
586}
587
588/*===========================================================================
589 * FUNCTION   : getJpegImgTypeFromImgFmt
590 *
591 * DESCRIPTION: function to return jpeg encode image type based on its image format
592 *
593 * PARAMETERS :
594 *   @img_fmt : image format
595 *
596 * RETURN     : return jpeg source image format (YUV or Bitstream)
597 *==========================================================================*/
598mm_jpeg_format_t QCamera3PostProcessor::getJpegImgTypeFromImgFmt(cam_format_t img_fmt)
599{
600    switch (img_fmt) {
601    case CAM_FORMAT_YUV_420_NV21:
602    case CAM_FORMAT_YUV_420_NV21_ADRENO:
603    case CAM_FORMAT_YUV_420_NV12:
604    case CAM_FORMAT_YUV_420_YV12:
605    case CAM_FORMAT_YUV_422_NV61:
606    case CAM_FORMAT_YUV_422_NV16:
607        return MM_JPEG_FMT_YUV;
608    default:
609        return MM_JPEG_FMT_YUV;
610    }
611}
612
613/*===========================================================================
614 * FUNCTION   : encodeData
615 *
616 * DESCRIPTION: function to prepare encoding job information and send to
617 *              mm-jpeg-interface to do the encoding job
618 *
619 * PARAMETERS :
620 *   @jpeg_job_data : ptr to a struct saving job related information
621 *   @needNewSess   : flag to indicate if a new jpeg encoding session need
622 *                    to be created. After creation, this flag will be toggled
623 *
624 * RETURN     : int32_t type of status
625 *              NO_ERROR  -- success
626 *              none-zero failure code
627 *==========================================================================*/
628int32_t QCamera3PostProcessor::encodeData(qcamera_jpeg_data_t *jpeg_job_data,
629                                         uint8_t &needNewSess)
630{
631    ALOGV("%s : E", __func__);
632    int32_t ret = NO_ERROR;
633    mm_jpeg_job_t jpg_job;
634    uint32_t jobId = 0;
635    QCamera3Stream *main_stream = NULL;
636    mm_camera_buf_def_t *main_frame = NULL;
637    QCamera3Stream *thumb_stream = NULL;
638    mm_camera_buf_def_t *thumb_frame = NULL;
639    mm_camera_super_buf_t *recvd_frame = jpeg_job_data->src_frame;
640
641    // find channel
642    QCamera3Channel *pChannel = m_parent;
643    // check reprocess channel if not found
644    if (pChannel == NULL) {
645        ALOGE("%s: No corresponding channel (ch_id = %d) exist, return here",
646              __func__, recvd_frame->ch_id);
647        return BAD_VALUE;
648    }
649
650    // find snapshot frame and thumnail frame
651    //Note: In this version we will receive only snapshot frame.
652    for (int i = 0; i < recvd_frame->num_bufs; i++) {
653        QCamera3Stream *pStream =
654            pChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id);
655        if (pStream != NULL) {
656            if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
657                pStream->isTypeOf(CAM_STREAM_TYPE_OFFLINE_PROC)) {
658                main_stream = pStream;
659                main_frame = recvd_frame->bufs[i];
660            } else if (pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
661                       pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW)) {
662                thumb_stream = pStream;
663                thumb_frame = recvd_frame->bufs[i];
664            }
665        }
666    }
667
668    if(NULL == main_frame){
669       ALOGE("%s : Main frame is NULL", __func__);
670       return BAD_VALUE;
671    }
672
673    QCamera3Memory *memObj = (QCamera3Memory *)main_frame->mem_info;
674    if (NULL == memObj) {
675        ALOGE("%s : Memeory Obj of main frame is NULL", __func__);
676        return NO_MEMORY;
677    }
678
679    // clean and invalidate cache ops through mem obj of the frame
680    memObj->cleanInvalidateCache(main_frame->buf_idx);
681
682    if (thumb_frame != NULL) {
683        QCamera3Memory *thumb_memObj = (QCamera3Memory *)thumb_frame->mem_info;
684        if (NULL != thumb_memObj) {
685            // clean and invalidate cache ops through mem obj of the frame
686            thumb_memObj->cleanInvalidateCache(thumb_frame->buf_idx);
687        }
688    }
689
690    if (mJpegClientHandle <= 0) {
691        ALOGE("%s: Error: bug here, mJpegClientHandle is 0", __func__);
692        return UNKNOWN_ERROR;
693    }
694
695    ALOGD("%s: Need new session?:%d",__func__, needNewSess);
696    if (needNewSess) {
697        //creating a new session, so we must destroy the old one
698        if ( 0 < mJpegSessionId ) {
699            ret = mJpegHandle.destroy_session(mJpegSessionId);
700            if (ret != NO_ERROR) {
701                ALOGE("%s: Error destroying an old jpeg encoding session, id = %d",
702                      __func__, mJpegSessionId);
703                return ret;
704            }
705            mJpegSessionId = 0;
706        }
707        // create jpeg encoding session
708        mm_jpeg_encode_params_t encodeParam;
709        memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t));
710
711        getJpegEncodingConfig(encodeParam, main_stream, thumb_stream);
712        ALOGD("%s: #src bufs:%d # tmb bufs:%d #dst_bufs:%d", __func__,
713                     encodeParam.num_src_bufs,encodeParam.num_tmb_bufs,encodeParam.num_dst_bufs);
714        ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId);
715        if (ret != NO_ERROR) {
716            ALOGE("%s: Error creating a new jpeg encoding session, ret = %d", __func__, ret);
717            return ret;
718        }
719        needNewSess = FALSE;
720    }
721
722    // Fill in new job
723    memset(&jpg_job, 0, sizeof(mm_jpeg_job_t));
724    jpg_job.job_type = JPEG_JOB_TYPE_ENCODE;
725    jpg_job.encode_job.session_id = mJpegSessionId;
726    jpg_job.encode_job.src_index = main_frame->buf_idx;
727    jpg_job.encode_job.dst_index = 0;
728
729    cam_rect_t crop;
730    memset(&crop, 0, sizeof(cam_rect_t));
731    //TBD_later - Zoom event removed in stream
732    //main_stream->getCropInfo(crop);
733
734    cam_dimension_t src_dim;
735    memset(&src_dim, 0, sizeof(cam_dimension_t));
736    main_stream->getFrameDimension(src_dim);
737
738    // main dim
739    jpg_job.encode_job.main_dim.src_dim = src_dim;
740    jpg_job.encode_job.main_dim.dst_dim = src_dim;
741    jpg_job.encode_job.main_dim.crop = crop;
742
743    // thumbnail dim
744    ALOGD("%s: Thumbnail needed:%d",__func__, m_bThumbnailNeeded);
745    if (m_bThumbnailNeeded == TRUE) {
746        if (thumb_stream == NULL) {
747            // need jpeg thumbnail, but no postview/preview stream exists
748            // we use the main stream/frame to encode thumbnail
749            thumb_stream = main_stream;
750            thumb_frame = main_frame;
751        }
752        memset(&crop, 0, sizeof(cam_rect_t));
753        //TBD_later - Zoom event removed in stream
754        //thumb_stream->getCropInfo(crop);
755        memset(&src_dim, 0, sizeof(cam_dimension_t));
756        thumb_stream->getFrameDimension(src_dim);
757        jpg_job.encode_job.thumb_dim.src_dim = src_dim;
758        m_parent->getThumbnailSize(jpg_job.encode_job.thumb_dim.dst_dim);
759        jpg_job.encode_job.thumb_dim.crop = crop;
760        jpg_job.encode_job.thumb_index = thumb_frame->buf_idx;
761    }
762
763    // set rotation only when no online rotation or offline pp rotation is done before
764
765    if (!m_parent->needOnlineRotation()) {
766        jpg_job.encode_job.rotation = m_parent->getJpegRotation();
767    }
768    ALOGV("%s: jpeg rotation is set to %d", __func__, jpg_job.encode_job.rotation);
769
770    // Find meta data frame. Meta data frame contains additional exif info
771    // which will be extracted and filled in by encoder.
772    //Note: In this version meta data will be null
773    //as we don't support bundling of snapshot and metadata streams.
774
775    mm_camera_buf_def_t *meta_frame = NULL;
776    for (int i = 0; i < jpeg_job_data->src_frame->num_bufs; i++) {
777        // look through input superbuf
778        if (jpeg_job_data->src_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) {
779            meta_frame = jpeg_job_data->src_frame->bufs[i];
780            break;
781        }
782    }
783    if (meta_frame == NULL && jpeg_job_data->src_reproc_frame != NULL) {
784        // look through reprocess source superbuf
785        for (int i = 0; i < jpeg_job_data->src_reproc_frame->num_bufs; i++) {
786            if (jpeg_job_data->src_reproc_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) {
787                meta_frame = jpeg_job_data->src_reproc_frame->bufs[i];
788                break;
789            }
790        }
791    }
792    if (meta_frame != NULL) {
793        // fill in meta data frame ptr
794        jpg_job.encode_job.p_metadata = (cam_metadata_info_t *)meta_frame->buffer;
795    }
796
797    //Start jpeg encoding
798    ret = mJpegHandle.start_job(&jpg_job, &jobId);
799    if (ret == NO_ERROR) {
800        // remember job info
801        jpeg_job_data->jobId = jobId;
802    }
803
804    ALOGV("%s : X", __func__);
805    return ret;
806}
807
808/*===========================================================================
809 * FUNCTION   : dataProcessRoutine
810 *
811 * DESCRIPTION: data process routine that handles input data either from input
812 *              Jpeg Queue to do jpeg encoding, or from input PP Queue to do
813 *              reprocess.
814 *
815 * PARAMETERS :
816 *   @data    : user data ptr (QCamera3PostProcessor)
817 *
818 * RETURN     : None
819 *==========================================================================*/
820void *QCamera3PostProcessor::dataProcessRoutine(void *data)
821{
822    int running = 1;
823    int ret;
824    uint8_t is_active = FALSE;
825    uint8_t needNewSess = TRUE;
826    ALOGV("%s: E", __func__);
827    QCamera3PostProcessor *pme = (QCamera3PostProcessor *)data;
828    QCameraCmdThread *cmdThread = &pme->m_dataProcTh;
829
830    do {
831        do {
832            ret = cam_sem_wait(&cmdThread->cmd_sem);
833            if (ret != 0 && errno != EINVAL) {
834                ALOGE("%s: cam_sem_wait error (%s)",
835                           __func__, strerror(errno));
836                return NULL;
837            }
838        } while (ret != 0);
839
840        // we got notified about new cmd avail in cmd queue
841        camera_cmd_type_t cmd = cmdThread->getCmd();
842        switch (cmd) {
843        case CAMERA_CMD_TYPE_START_DATA_PROC:
844            ALOGD("%s: start data proc", __func__);
845            is_active = TRUE;
846            needNewSess = TRUE;
847            break;
848        case CAMERA_CMD_TYPE_STOP_DATA_PROC:
849            {
850                ALOGD("%s: stop data proc", __func__);
851                is_active = FALSE;
852
853                // cancel all ongoing jpeg jobs
854                qcamera_jpeg_data_t *jpeg_job =
855                    (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
856                while (jpeg_job != NULL) {
857                    pme->mJpegHandle.abort_job(jpeg_job->jobId);
858
859                    pme->releaseJpegJobData(jpeg_job);
860                    free(jpeg_job);
861
862                    jpeg_job = (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
863                }
864
865                // destroy jpeg encoding session
866                if ( 0 < pme->mJpegSessionId ) {
867                    pme->mJpegHandle.destroy_session(pme->mJpegSessionId);
868                    pme->mJpegSessionId = 0;
869                }
870
871                // free jpeg exif obj
872                if (pme->m_pJpegExifObj != NULL) {
873                    delete pme->m_pJpegExifObj;
874                    pme->m_pJpegExifObj = NULL;
875                }
876                needNewSess = TRUE;
877
878                // flush ongoing postproc Queue
879                pme->m_ongoingPPQ.flush();
880
881                // flush input jpeg Queue
882                pme->m_inputJpegQ.flush();
883
884                // flush input Postproc Queue
885                pme->m_inputPPQ.flush();
886
887                // flush input raw Queue
888                pme->m_inputRawQ.flush();
889
890                // signal cmd is completed
891                cam_sem_post(&cmdThread->sync_sem);
892            }
893            break;
894        case CAMERA_CMD_TYPE_DO_NEXT_JOB:
895            {
896                ALOGD("%s: Do next job, active is %d", __func__, is_active);
897                if (is_active == TRUE) {
898                    // check if there is any ongoing jpeg jobs
899                    if (pme->m_ongoingJpegQ.isEmpty()) {
900                        // no ongoing jpeg job, we are fine to send jpeg encoding job
901                        qcamera_jpeg_data_t *jpeg_job =
902                            (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
903
904                        if (NULL != jpeg_job) {
905                            //TBD_later - play shutter sound
906                            //pme->m_parent->playShutter();
907
908                            // add into ongoing jpeg job Q
909                            pme->m_ongoingJpegQ.enqueue((void *)jpeg_job);
910                            ret = pme->encodeData(jpeg_job, needNewSess);
911                            if (NO_ERROR != ret) {
912                                // dequeue the last one
913                                pme->m_ongoingJpegQ.dequeue(false);
914
915                                pme->releaseJpegJobData(jpeg_job);
916                                free(jpeg_job);
917                            }
918                        }
919                    }
920
921                    mm_camera_super_buf_t *pp_frame =
922                        (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue();
923                    if (NULL != pp_frame) {
924                        qcamera_pp_data_t *pp_job =
925                            (qcamera_pp_data_t *)malloc(sizeof(qcamera_pp_data_t));
926                        if (pp_job != NULL) {
927                            memset(pp_job, 0, sizeof(qcamera_pp_data_t));
928                        } else {
929                            ALOGE("%s: no mem for qcamera_pp_data_t", __func__);
930                            ret = -1;
931                        }
932
933                        if (0 != ret) {
934                            // free pp_job
935                            if (pp_job != NULL) {
936                                free(pp_job);
937                            }
938                            // free frame
939                            if (pp_frame != NULL) {
940                                pme->releaseSuperBuf(pp_frame);
941                                free(pp_frame);
942                            }
943                        }
944                    }
945                } else {
946                    // not active, simply return buf and do no op
947                    mm_camera_super_buf_t *super_buf =
948                        (mm_camera_super_buf_t *)pme->m_inputJpegQ.dequeue();
949                    if (NULL != super_buf) {
950                        pme->releaseSuperBuf(super_buf);
951                        free(super_buf);
952                    }
953                    super_buf = (mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue();
954                    if (NULL != super_buf) {
955                        pme->releaseSuperBuf(super_buf);
956                        free(super_buf);
957                    }
958                    super_buf = (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue();
959                    if (NULL != super_buf) {
960                        pme->releaseSuperBuf(super_buf);
961                        free(super_buf);
962                    }
963                }
964            }
965            break;
966        case CAMERA_CMD_TYPE_EXIT:
967            running = 0;
968            break;
969        default:
970            break;
971        }
972    } while (running);
973    ALOGV("%s: X", __func__);
974    return NULL;
975}
976
977/*===========================================================================
978 * FUNCTION   : QCamera3Exif
979 *
980 * DESCRIPTION: constructor of QCamera3Exif
981 *
982 * PARAMETERS : None
983 *
984 * RETURN     : None
985 *==========================================================================*/
986QCamera3Exif::QCamera3Exif()
987    : m_nNumEntries(0)
988{
989    memset(m_Entries, 0, sizeof(m_Entries));
990}
991
992/*===========================================================================
993 * FUNCTION   : ~QCamera3Exif
994 *
995 * DESCRIPTION: deconstructor of QCamera3Exif. Will release internal memory ptr.
996 *
997 * PARAMETERS : None
998 *
999 * RETURN     : None
1000 *==========================================================================*/
1001QCamera3Exif::~QCamera3Exif()
1002{
1003    for (uint32_t i = 0; i < m_nNumEntries; i++) {
1004        switch (m_Entries[i].tag_entry.type) {
1005            case EXIF_BYTE:
1006                {
1007                    if (m_Entries[i].tag_entry.count > 1 &&
1008                            m_Entries[i].tag_entry.data._bytes != NULL) {
1009                        free(m_Entries[i].tag_entry.data._bytes);
1010                        m_Entries[i].tag_entry.data._bytes = NULL;
1011                    }
1012                }
1013                break;
1014            case EXIF_ASCII:
1015                {
1016                    if (m_Entries[i].tag_entry.data._ascii != NULL) {
1017                        free(m_Entries[i].tag_entry.data._ascii);
1018                        m_Entries[i].tag_entry.data._ascii = NULL;
1019                    }
1020                }
1021                break;
1022            case EXIF_SHORT:
1023                {
1024                    if (m_Entries[i].tag_entry.count > 1 &&
1025                            m_Entries[i].tag_entry.data._shorts != NULL) {
1026                        free(m_Entries[i].tag_entry.data._shorts);
1027                        m_Entries[i].tag_entry.data._shorts = NULL;
1028                    }
1029                }
1030                break;
1031            case EXIF_LONG:
1032                {
1033                    if (m_Entries[i].tag_entry.count > 1 &&
1034                            m_Entries[i].tag_entry.data._longs != NULL) {
1035                        free(m_Entries[i].tag_entry.data._longs);
1036                        m_Entries[i].tag_entry.data._longs = NULL;
1037                    }
1038                }
1039                break;
1040            case EXIF_RATIONAL:
1041                {
1042                    if (m_Entries[i].tag_entry.count > 1 &&
1043                            m_Entries[i].tag_entry.data._rats != NULL) {
1044                        free(m_Entries[i].tag_entry.data._rats);
1045                        m_Entries[i].tag_entry.data._rats = NULL;
1046                    }
1047                }
1048                break;
1049            case EXIF_UNDEFINED:
1050                {
1051                    if (m_Entries[i].tag_entry.data._undefined != NULL) {
1052                        free(m_Entries[i].tag_entry.data._undefined);
1053                        m_Entries[i].tag_entry.data._undefined = NULL;
1054                    }
1055                }
1056                break;
1057            case EXIF_SLONG:
1058                {
1059                    if (m_Entries[i].tag_entry.count > 1 &&
1060                            m_Entries[i].tag_entry.data._slongs != NULL) {
1061                        free(m_Entries[i].tag_entry.data._slongs);
1062                        m_Entries[i].tag_entry.data._slongs = NULL;
1063                    }
1064                }
1065                break;
1066            case EXIF_SRATIONAL:
1067                {
1068                    if (m_Entries[i].tag_entry.count > 1 &&
1069                            m_Entries[i].tag_entry.data._srats != NULL) {
1070                        free(m_Entries[i].tag_entry.data._srats);
1071                        m_Entries[i].tag_entry.data._srats = NULL;
1072                    }
1073                }
1074                break;
1075            default:
1076                ALOGE("%s: Error, Unknown type",__func__);
1077                break;
1078        }
1079    }
1080}
1081
1082/*===========================================================================
1083 * FUNCTION   : addEntry
1084 *
1085 * DESCRIPTION: function to add an entry to exif data
1086 *
1087 * PARAMETERS :
1088 *   @tagid   : exif tag ID
1089 *   @type    : data type
1090 *   @count   : number of data in uint of its type
1091 *   @data    : input data ptr
1092 *
1093 * RETURN     : int32_t type of status
1094 *              NO_ERROR  -- success
1095 *              none-zero failure code
1096 *==========================================================================*/
1097int32_t QCamera3Exif::addEntry(exif_tag_id_t tagid,
1098                              exif_tag_type_t type,
1099                              uint32_t count,
1100                              void *data)
1101{
1102    int32_t rc = NO_ERROR;
1103    if(m_nNumEntries >= MAX_EXIF_TABLE_ENTRIES) {
1104        ALOGE("%s: Number of entries exceeded limit", __func__);
1105        return NO_MEMORY;
1106    }
1107
1108    m_Entries[m_nNumEntries].tag_id = tagid;
1109    m_Entries[m_nNumEntries].tag_entry.type = type;
1110    m_Entries[m_nNumEntries].tag_entry.count = count;
1111    m_Entries[m_nNumEntries].tag_entry.copy = 1;
1112    switch (type) {
1113        case EXIF_BYTE:
1114            {
1115                if (count > 1) {
1116                    uint8_t *values = (uint8_t *)malloc(count);
1117                    if (values == NULL) {
1118                        ALOGE("%s: No memory for byte array", __func__);
1119                        rc = NO_MEMORY;
1120                    } else {
1121                        memcpy(values, data, count);
1122                        m_Entries[m_nNumEntries].tag_entry.data._bytes = values;
1123                    }
1124                } else {
1125                    m_Entries[m_nNumEntries].tag_entry.data._byte =
1126                        *(uint8_t *)data;
1127                }
1128            }
1129            break;
1130        case EXIF_ASCII:
1131            {
1132                char *str = NULL;
1133                str = (char *)malloc(count + 1);
1134                if (str == NULL) {
1135                    ALOGE("%s: No memory for ascii string", __func__);
1136                    rc = NO_MEMORY;
1137                } else {
1138                    memset(str, 0, count + 1);
1139                    memcpy(str, data, count);
1140                    m_Entries[m_nNumEntries].tag_entry.data._ascii = str;
1141                }
1142            }
1143            break;
1144        case EXIF_SHORT:
1145            {
1146                if (count > 1) {
1147                    uint16_t *values =
1148                        (uint16_t *)malloc(count * sizeof(uint16_t));
1149                    if (values == NULL) {
1150                        ALOGE("%s: No memory for short array", __func__);
1151                        rc = NO_MEMORY;
1152                    } else {
1153                        memcpy(values, data, count * sizeof(uint16_t));
1154                        m_Entries[m_nNumEntries].tag_entry.data._shorts =values;
1155                    }
1156                } else {
1157                    m_Entries[m_nNumEntries].tag_entry.data._short =
1158                        *(uint16_t *)data;
1159                }
1160            }
1161            break;
1162        case EXIF_LONG:
1163            {
1164                if (count > 1) {
1165                    uint32_t *values =
1166                        (uint32_t *)malloc(count * sizeof(uint32_t));
1167                    if (values == NULL) {
1168                        ALOGE("%s: No memory for long array", __func__);
1169                        rc = NO_MEMORY;
1170                    } else {
1171                        memcpy(values, data, count * sizeof(uint32_t));
1172                        m_Entries[m_nNumEntries].tag_entry.data._longs = values;
1173                    }
1174                } else {
1175                    m_Entries[m_nNumEntries].tag_entry.data._long =
1176                        *(uint32_t *)data;
1177                }
1178            }
1179            break;
1180        case EXIF_RATIONAL:
1181            {
1182                if (count > 1) {
1183                    rat_t *values = (rat_t *)malloc(count * sizeof(rat_t));
1184                    if (values == NULL) {
1185                        ALOGE("%s: No memory for rational array", __func__);
1186                        rc = NO_MEMORY;
1187                    } else {
1188                        memcpy(values, data, count * sizeof(rat_t));
1189                        m_Entries[m_nNumEntries].tag_entry.data._rats = values;
1190                    }
1191                } else {
1192                    m_Entries[m_nNumEntries].tag_entry.data._rat =
1193                        *(rat_t *)data;
1194                }
1195            }
1196            break;
1197        case EXIF_UNDEFINED:
1198            {
1199                uint8_t *values = (uint8_t *)malloc(count);
1200                if (values == NULL) {
1201                    ALOGE("%s: No memory for undefined array", __func__);
1202                    rc = NO_MEMORY;
1203                } else {
1204                    memcpy(values, data, count);
1205                    m_Entries[m_nNumEntries].tag_entry.data._undefined = values;
1206                }
1207            }
1208            break;
1209        case EXIF_SLONG:
1210            {
1211                if (count > 1) {
1212                    int32_t *values =
1213                        (int32_t *)malloc(count * sizeof(int32_t));
1214                    if (values == NULL) {
1215                        ALOGE("%s: No memory for signed long array", __func__);
1216                        rc = NO_MEMORY;
1217                    } else {
1218                        memcpy(values, data, count * sizeof(int32_t));
1219                        m_Entries[m_nNumEntries].tag_entry.data._slongs =values;
1220                    }
1221                } else {
1222                    m_Entries[m_nNumEntries].tag_entry.data._slong =
1223                        *(int32_t *)data;
1224                }
1225            }
1226            break;
1227        case EXIF_SRATIONAL:
1228            {
1229                if (count > 1) {
1230                    srat_t *values = (srat_t *)malloc(count * sizeof(srat_t));
1231                    if (values == NULL) {
1232                        ALOGE("%s: No memory for sign rational array",__func__);
1233                        rc = NO_MEMORY;
1234                    } else {
1235                        memcpy(values, data, count * sizeof(srat_t));
1236                        m_Entries[m_nNumEntries].tag_entry.data._srats = values;
1237                    }
1238                } else {
1239                    m_Entries[m_nNumEntries].tag_entry.data._srat =
1240                        *(srat_t *)data;
1241                }
1242            }
1243            break;
1244        default:
1245            ALOGE("%s: Error, Unknown type",__func__);
1246            break;
1247    }
1248
1249    // Increase number of entries
1250    m_nNumEntries++;
1251    return rc;
1252}
1253
1254}; // namespace qcamera
1255