QCamera3PostProc.cpp revision a4f99c05471ae7d2b57f20b1178e0a8597596fb0
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        ALOGE("%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    ALOGE("%s: Need new session?:%d",__func__, needNewSess);
696    if (needNewSess) {
697        // create jpeg encoding session
698        mm_jpeg_encode_params_t encodeParam;
699        memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t));
700
701        getJpegEncodingConfig(encodeParam, main_stream, thumb_stream);
702        ALOGE("%s: #src bufs:%d # tmb bufs:%d #dst_bufs:%d", __func__,
703                     encodeParam.num_src_bufs,encodeParam.num_tmb_bufs,encodeParam.num_dst_bufs);
704        ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId);
705        if (ret != NO_ERROR) {
706            ALOGE("%s: error creating a new jpeg encoding session", __func__);
707            return ret;
708        }
709        needNewSess = FALSE;
710    }
711
712    // Fill in new job
713    memset(&jpg_job, 0, sizeof(mm_jpeg_job_t));
714    jpg_job.job_type = JPEG_JOB_TYPE_ENCODE;
715    jpg_job.encode_job.session_id = mJpegSessionId;
716    jpg_job.encode_job.src_index = main_frame->buf_idx;
717    jpg_job.encode_job.dst_index = 0;
718
719    cam_rect_t crop;
720    memset(&crop, 0, sizeof(cam_rect_t));
721    //TBD_later - Zoom event removed in stream
722    //main_stream->getCropInfo(crop);
723
724    cam_dimension_t src_dim;
725    memset(&src_dim, 0, sizeof(cam_dimension_t));
726    main_stream->getFrameDimension(src_dim);
727
728    // main dim
729    jpg_job.encode_job.main_dim.src_dim = src_dim;
730    jpg_job.encode_job.main_dim.dst_dim = src_dim;
731    jpg_job.encode_job.main_dim.crop = crop;
732
733    // thumbnail dim
734    ALOGE("%s: Thumbnail needed:%d",__func__, m_bThumbnailNeeded);
735    if (m_bThumbnailNeeded == TRUE) {
736        if (thumb_stream == NULL) {
737            // need jpeg thumbnail, but no postview/preview stream exists
738            // we use the main stream/frame to encode thumbnail
739            thumb_stream = main_stream;
740            thumb_frame = main_frame;
741        }
742        memset(&crop, 0, sizeof(cam_rect_t));
743        //TBD_later - Zoom event removed in stream
744        //thumb_stream->getCropInfo(crop);
745        memset(&src_dim, 0, sizeof(cam_dimension_t));
746        thumb_stream->getFrameDimension(src_dim);
747        jpg_job.encode_job.thumb_dim.src_dim = src_dim;
748        m_parent->getThumbnailSize(jpg_job.encode_job.thumb_dim.dst_dim);
749        jpg_job.encode_job.thumb_dim.crop = crop;
750        jpg_job.encode_job.thumb_index = thumb_frame->buf_idx;
751    }
752
753    // set rotation only when no online rotation or offline pp rotation is done before
754
755    if (!m_parent->needOnlineRotation()) {
756        jpg_job.encode_job.rotation = m_parent->getJpegRotation();
757    }
758    ALOGV("%s: jpeg rotation is set to %d", __func__, jpg_job.encode_job.rotation);
759
760    // Find meta data frame. Meta data frame contains additional exif info
761    // which will be extracted and filled in by encoder.
762    //Note: In this version meta data will be null
763    //as we don't support bundling of snapshot and metadata streams.
764
765    mm_camera_buf_def_t *meta_frame = NULL;
766    for (int i = 0; i < jpeg_job_data->src_frame->num_bufs; i++) {
767        // look through input superbuf
768        if (jpeg_job_data->src_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) {
769            meta_frame = jpeg_job_data->src_frame->bufs[i];
770            break;
771        }
772    }
773    if (meta_frame == NULL && jpeg_job_data->src_reproc_frame != NULL) {
774        // look through reprocess source superbuf
775        for (int i = 0; i < jpeg_job_data->src_reproc_frame->num_bufs; i++) {
776            if (jpeg_job_data->src_reproc_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) {
777                meta_frame = jpeg_job_data->src_reproc_frame->bufs[i];
778                break;
779            }
780        }
781    }
782    if (meta_frame != NULL) {
783        // fill in meta data frame ptr
784        jpg_job.encode_job.p_metadata = (cam_metadata_info_t *)meta_frame->buffer;
785    }
786
787    //Start jpeg encoding
788    ret = mJpegHandle.start_job(&jpg_job, &jobId);
789    if (ret == NO_ERROR) {
790        // remember job info
791        jpeg_job_data->jobId = jobId;
792    }
793
794    ALOGD("%s : X", __func__);
795    return ret;
796}
797
798/*===========================================================================
799 * FUNCTION   : dataProcessRoutine
800 *
801 * DESCRIPTION: data process routine that handles input data either from input
802 *              Jpeg Queue to do jpeg encoding, or from input PP Queue to do
803 *              reprocess.
804 *
805 * PARAMETERS :
806 *   @data    : user data ptr (QCamera3PostProcessor)
807 *
808 * RETURN     : None
809 *==========================================================================*/
810void *QCamera3PostProcessor::dataProcessRoutine(void *data)
811{
812    int running = 1;
813    int ret;
814    uint8_t is_active = FALSE;
815    uint8_t needNewSess = TRUE;
816    QCamera3PostProcessor *pme = (QCamera3PostProcessor *)data;
817    QCameraCmdThread *cmdThread = &pme->m_dataProcTh;
818
819    ALOGD("%s: E", __func__);
820    do {
821        do {
822            ret = cam_sem_wait(&cmdThread->cmd_sem);
823            if (ret != 0 && errno != EINVAL) {
824                ALOGE("%s: cam_sem_wait error (%s)",
825                           __func__, strerror(errno));
826                return NULL;
827            }
828        } while (ret != 0);
829
830        // we got notified about new cmd avail in cmd queue
831        camera_cmd_type_t cmd = cmdThread->getCmd();
832        switch (cmd) {
833        case CAMERA_CMD_TYPE_START_DATA_PROC:
834            ALOGD("%s: start data proc", __func__);
835            is_active = TRUE;
836            needNewSess = TRUE;
837            break;
838        case CAMERA_CMD_TYPE_STOP_DATA_PROC:
839            {
840                ALOGD("%s: stop data proc", __func__);
841                is_active = FALSE;
842
843                // cancel all ongoing jpeg jobs
844                qcamera_jpeg_data_t *jpeg_job =
845                    (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
846                while (jpeg_job != NULL) {
847                    pme->mJpegHandle.abort_job(jpeg_job->jobId);
848
849                    pme->releaseJpegJobData(jpeg_job);
850                    free(jpeg_job);
851
852                    jpeg_job = (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
853                }
854
855                // destroy jpeg encoding session
856                if ( 0 < pme->mJpegSessionId ) {
857                    pme->mJpegHandle.destroy_session(pme->mJpegSessionId);
858                    pme->mJpegSessionId = 0;
859                }
860
861                // free jpeg exif obj
862                if (pme->m_pJpegExifObj != NULL) {
863                    delete pme->m_pJpegExifObj;
864                    pme->m_pJpegExifObj = NULL;
865                }
866                needNewSess = TRUE;
867
868                // flush ongoing postproc Queue
869                pme->m_ongoingPPQ.flush();
870
871                // flush input jpeg Queue
872                pme->m_inputJpegQ.flush();
873
874                // flush input Postproc Queue
875                pme->m_inputPPQ.flush();
876
877                // flush input raw Queue
878                pme->m_inputRawQ.flush();
879
880                // signal cmd is completed
881                cam_sem_post(&cmdThread->sync_sem);
882            }
883            break;
884        case CAMERA_CMD_TYPE_DO_NEXT_JOB:
885            {
886                ALOGD("%s: Do next job, active is %d", __func__, is_active);
887                if (is_active == TRUE) {
888                    // check if there is any ongoing jpeg jobs
889                    if (pme->m_ongoingJpegQ.isEmpty()) {
890                        // no ongoing jpeg job, we are fine to send jpeg encoding job
891                        qcamera_jpeg_data_t *jpeg_job =
892                            (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
893
894                        if (NULL != jpeg_job) {
895                            //TBD_later - play shutter sound
896                            //pme->m_parent->playShutter();
897
898                            // add into ongoing jpeg job Q
899                            pme->m_ongoingJpegQ.enqueue((void *)jpeg_job);
900                            ret = pme->encodeData(jpeg_job, needNewSess);
901                            if (NO_ERROR != ret) {
902                                // dequeue the last one
903                                pme->m_ongoingJpegQ.dequeue(false);
904
905                                pme->releaseJpegJobData(jpeg_job);
906                                free(jpeg_job);
907                            }
908                        }
909                    }
910
911                    mm_camera_super_buf_t *pp_frame =
912                        (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue();
913                    if (NULL != pp_frame) {
914                        qcamera_pp_data_t *pp_job =
915                            (qcamera_pp_data_t *)malloc(sizeof(qcamera_pp_data_t));
916                        if (pp_job != NULL) {
917                            memset(pp_job, 0, sizeof(qcamera_pp_data_t));
918                        } else {
919                            ALOGE("%s: no mem for qcamera_pp_data_t", __func__);
920                            ret = -1;
921                        }
922
923                        if (0 != ret) {
924                            // free pp_job
925                            if (pp_job != NULL) {
926                                free(pp_job);
927                            }
928                            // free frame
929                            if (pp_frame != NULL) {
930                                pme->releaseSuperBuf(pp_frame);
931                                free(pp_frame);
932                            }
933                        }
934                    }
935                } else {
936                    // not active, simply return buf and do no op
937                    mm_camera_super_buf_t *super_buf =
938                        (mm_camera_super_buf_t *)pme->m_inputJpegQ.dequeue();
939                    if (NULL != super_buf) {
940                        pme->releaseSuperBuf(super_buf);
941                        free(super_buf);
942                    }
943                    super_buf = (mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue();
944                    if (NULL != super_buf) {
945                        pme->releaseSuperBuf(super_buf);
946                        free(super_buf);
947                    }
948                    super_buf = (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue();
949                    if (NULL != super_buf) {
950                        pme->releaseSuperBuf(super_buf);
951                        free(super_buf);
952                    }
953                }
954            }
955            break;
956        case CAMERA_CMD_TYPE_EXIT:
957            running = 0;
958            break;
959        default:
960            break;
961        }
962    } while (running);
963    ALOGD("%s: X", __func__);
964    return NULL;
965}
966
967/*===========================================================================
968 * FUNCTION   : getJpegPaddingReq
969 *
970 * DESCRIPTION: function to add an entry to exif data
971 *
972 * PARAMETERS :
973 *   @padding_info : jpeg specific padding requirement
974 *
975 * RETURN     : int32_t type of status
976 *              NO_ERROR  -- success
977 *              none-zero failure code
978 *==========================================================================*/
979int32_t QCamera3PostProcessor::getJpegPaddingReq(cam_padding_info_t &padding_info)
980{
981    // TODO: hardcode for now, needs to query from mm-jpeg-interface
982    padding_info.width_padding  = CAM_PAD_NONE;
983    padding_info.height_padding  = CAM_PAD_TO_16;
984    padding_info.plane_padding  = CAM_PAD_TO_WORD;
985    return NO_ERROR;
986}
987
988/*===========================================================================
989 * FUNCTION   : QCamera3Exif
990 *
991 * DESCRIPTION: constructor of QCamera3Exif
992 *
993 * PARAMETERS : None
994 *
995 * RETURN     : None
996 *==========================================================================*/
997QCamera3Exif::QCamera3Exif()
998    : m_nNumEntries(0)
999{
1000    memset(m_Entries, 0, sizeof(m_Entries));
1001}
1002
1003/*===========================================================================
1004 * FUNCTION   : ~QCamera3Exif
1005 *
1006 * DESCRIPTION: deconstructor of QCamera3Exif. Will release internal memory ptr.
1007 *
1008 * PARAMETERS : None
1009 *
1010 * RETURN     : None
1011 *==========================================================================*/
1012QCamera3Exif::~QCamera3Exif()
1013{
1014    for (uint32_t i = 0; i < m_nNumEntries; i++) {
1015        switch (m_Entries[i].tag_entry.type) {
1016            case EXIF_BYTE:
1017                {
1018                    if (m_Entries[i].tag_entry.count > 1 &&
1019                            m_Entries[i].tag_entry.data._bytes != NULL) {
1020                        free(m_Entries[i].tag_entry.data._bytes);
1021                        m_Entries[i].tag_entry.data._bytes = NULL;
1022                    }
1023                }
1024                break;
1025            case EXIF_ASCII:
1026                {
1027                    if (m_Entries[i].tag_entry.data._ascii != NULL) {
1028                        free(m_Entries[i].tag_entry.data._ascii);
1029                        m_Entries[i].tag_entry.data._ascii = NULL;
1030                    }
1031                }
1032                break;
1033            case EXIF_SHORT:
1034                {
1035                    if (m_Entries[i].tag_entry.count > 1 &&
1036                            m_Entries[i].tag_entry.data._shorts != NULL) {
1037                        free(m_Entries[i].tag_entry.data._shorts);
1038                        m_Entries[i].tag_entry.data._shorts = NULL;
1039                    }
1040                }
1041                break;
1042            case EXIF_LONG:
1043                {
1044                    if (m_Entries[i].tag_entry.count > 1 &&
1045                            m_Entries[i].tag_entry.data._longs != NULL) {
1046                        free(m_Entries[i].tag_entry.data._longs);
1047                        m_Entries[i].tag_entry.data._longs = NULL;
1048                    }
1049                }
1050                break;
1051            case EXIF_RATIONAL:
1052                {
1053                    if (m_Entries[i].tag_entry.count > 1 &&
1054                            m_Entries[i].tag_entry.data._rats != NULL) {
1055                        free(m_Entries[i].tag_entry.data._rats);
1056                        m_Entries[i].tag_entry.data._rats = NULL;
1057                    }
1058                }
1059                break;
1060            case EXIF_UNDEFINED:
1061                {
1062                    if (m_Entries[i].tag_entry.data._undefined != NULL) {
1063                        free(m_Entries[i].tag_entry.data._undefined);
1064                        m_Entries[i].tag_entry.data._undefined = NULL;
1065                    }
1066                }
1067                break;
1068            case EXIF_SLONG:
1069                {
1070                    if (m_Entries[i].tag_entry.count > 1 &&
1071                            m_Entries[i].tag_entry.data._slongs != NULL) {
1072                        free(m_Entries[i].tag_entry.data._slongs);
1073                        m_Entries[i].tag_entry.data._slongs = NULL;
1074                    }
1075                }
1076                break;
1077            case EXIF_SRATIONAL:
1078                {
1079                    if (m_Entries[i].tag_entry.count > 1 &&
1080                            m_Entries[i].tag_entry.data._srats != NULL) {
1081                        free(m_Entries[i].tag_entry.data._srats);
1082                        m_Entries[i].tag_entry.data._srats = NULL;
1083                    }
1084                }
1085                break;
1086            default:
1087                ALOGE("%s: Error, Unknown type",__func__);
1088                break;
1089        }
1090    }
1091}
1092
1093/*===========================================================================
1094 * FUNCTION   : addEntry
1095 *
1096 * DESCRIPTION: function to add an entry to exif data
1097 *
1098 * PARAMETERS :
1099 *   @tagid   : exif tag ID
1100 *   @type    : data type
1101 *   @count   : number of data in uint of its type
1102 *   @data    : input data ptr
1103 *
1104 * RETURN     : int32_t type of status
1105 *              NO_ERROR  -- success
1106 *              none-zero failure code
1107 *==========================================================================*/
1108int32_t QCamera3Exif::addEntry(exif_tag_id_t tagid,
1109                              exif_tag_type_t type,
1110                              uint32_t count,
1111                              void *data)
1112{
1113    int32_t rc = NO_ERROR;
1114    if(m_nNumEntries >= MAX_EXIF_TABLE_ENTRIES) {
1115        ALOGE("%s: Number of entries exceeded limit", __func__);
1116        return NO_MEMORY;
1117    }
1118
1119    m_Entries[m_nNumEntries].tag_id = tagid;
1120    m_Entries[m_nNumEntries].tag_entry.type = type;
1121    m_Entries[m_nNumEntries].tag_entry.count = count;
1122    m_Entries[m_nNumEntries].tag_entry.copy = 1;
1123    switch (type) {
1124        case EXIF_BYTE:
1125            {
1126                if (count > 1) {
1127                    uint8_t *values = (uint8_t *)malloc(count);
1128                    if (values == NULL) {
1129                        ALOGE("%s: No memory for byte array", __func__);
1130                        rc = NO_MEMORY;
1131                    } else {
1132                        memcpy(values, data, count);
1133                        m_Entries[m_nNumEntries].tag_entry.data._bytes = values;
1134                    }
1135                } else {
1136                    m_Entries[m_nNumEntries].tag_entry.data._byte =
1137                        *(uint8_t *)data;
1138                }
1139            }
1140            break;
1141        case EXIF_ASCII:
1142            {
1143                char *str = NULL;
1144                str = (char *)malloc(count + 1);
1145                if (str == NULL) {
1146                    ALOGE("%s: No memory for ascii string", __func__);
1147                    rc = NO_MEMORY;
1148                } else {
1149                    memset(str, 0, count + 1);
1150                    memcpy(str, data, count);
1151                    m_Entries[m_nNumEntries].tag_entry.data._ascii = str;
1152                }
1153            }
1154            break;
1155        case EXIF_SHORT:
1156            {
1157                if (count > 1) {
1158                    uint16_t *values =
1159                        (uint16_t *)malloc(count * sizeof(uint16_t));
1160                    if (values == NULL) {
1161                        ALOGE("%s: No memory for short array", __func__);
1162                        rc = NO_MEMORY;
1163                    } else {
1164                        memcpy(values, data, count * sizeof(uint16_t));
1165                        m_Entries[m_nNumEntries].tag_entry.data._shorts =values;
1166                    }
1167                } else {
1168                    m_Entries[m_nNumEntries].tag_entry.data._short =
1169                        *(uint16_t *)data;
1170                }
1171            }
1172            break;
1173        case EXIF_LONG:
1174            {
1175                if (count > 1) {
1176                    uint32_t *values =
1177                        (uint32_t *)malloc(count * sizeof(uint32_t));
1178                    if (values == NULL) {
1179                        ALOGE("%s: No memory for long array", __func__);
1180                        rc = NO_MEMORY;
1181                    } else {
1182                        memcpy(values, data, count * sizeof(uint32_t));
1183                        m_Entries[m_nNumEntries].tag_entry.data._longs = values;
1184                    }
1185                } else {
1186                    m_Entries[m_nNumEntries].tag_entry.data._long =
1187                        *(uint32_t *)data;
1188                }
1189            }
1190            break;
1191        case EXIF_RATIONAL:
1192            {
1193                if (count > 1) {
1194                    rat_t *values = (rat_t *)malloc(count * sizeof(rat_t));
1195                    if (values == NULL) {
1196                        ALOGE("%s: No memory for rational array", __func__);
1197                        rc = NO_MEMORY;
1198                    } else {
1199                        memcpy(values, data, count * sizeof(rat_t));
1200                        m_Entries[m_nNumEntries].tag_entry.data._rats = values;
1201                    }
1202                } else {
1203                    m_Entries[m_nNumEntries].tag_entry.data._rat =
1204                        *(rat_t *)data;
1205                }
1206            }
1207            break;
1208        case EXIF_UNDEFINED:
1209            {
1210                uint8_t *values = (uint8_t *)malloc(count);
1211                if (values == NULL) {
1212                    ALOGE("%s: No memory for undefined array", __func__);
1213                    rc = NO_MEMORY;
1214                } else {
1215                    memcpy(values, data, count);
1216                    m_Entries[m_nNumEntries].tag_entry.data._undefined = values;
1217                }
1218            }
1219            break;
1220        case EXIF_SLONG:
1221            {
1222                if (count > 1) {
1223                    int32_t *values =
1224                        (int32_t *)malloc(count * sizeof(int32_t));
1225                    if (values == NULL) {
1226                        ALOGE("%s: No memory for signed long array", __func__);
1227                        rc = NO_MEMORY;
1228                    } else {
1229                        memcpy(values, data, count * sizeof(int32_t));
1230                        m_Entries[m_nNumEntries].tag_entry.data._slongs =values;
1231                    }
1232                } else {
1233                    m_Entries[m_nNumEntries].tag_entry.data._slong =
1234                        *(int32_t *)data;
1235                }
1236            }
1237            break;
1238        case EXIF_SRATIONAL:
1239            {
1240                if (count > 1) {
1241                    srat_t *values = (srat_t *)malloc(count * sizeof(srat_t));
1242                    if (values == NULL) {
1243                        ALOGE("%s: No memory for sign rational array",__func__);
1244                        rc = NO_MEMORY;
1245                    } else {
1246                        memcpy(values, data, count * sizeof(srat_t));
1247                        m_Entries[m_nNumEntries].tag_entry.data._srats = values;
1248                    }
1249                } else {
1250                    m_Entries[m_nNumEntries].tag_entry.data._srat =
1251                        *(srat_t *)data;
1252                }
1253            }
1254            break;
1255        default:
1256            ALOGE("%s: Error, Unknown type",__func__);
1257            break;
1258    }
1259
1260    // Increase number of entries
1261    m_nNumEntries++;
1262    return rc;
1263}
1264
1265}; // namespace qcamera
1266