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