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