1/* Copyright (c) 2012-2014, The Linux Foundataion. All rights reserved.
2*
3* Redistribution and use in source and binary forms, with or without
4* modification, are permitted provided that the following conditions are
5* met:
6*     * Redistributions of source code must retain the above copyright
7*       notice, this list of conditions and the following disclaimer.
8*     * Redistributions in binary form must reproduce the above
9*       copyright notice, this list of conditions and the following
10*       disclaimer in the documentation and/or other materials provided
11*       with the distribution.
12*     * Neither the name of The Linux Foundation nor the names of its
13*       contributors may be used to endorse or promote products derived
14*       from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*
28*/
29
30#define LOG_TAG "QCameraPostProc"
31
32#include <fcntl.h>
33#include <stdlib.h>
34#include <utils/Errors.h>
35
36#include "QCamera2HWI.h"
37#include "QCameraPostProc.h"
38
39namespace qcamera {
40
41const char *QCameraPostProcessor::STORE_LOCATION = "/sdcard/img_%d.jpg";
42
43#define FREE_JPEG_OUTPUT_BUFFER(ptr,cnt)     \
44    int jpeg_bufs; \
45    for (jpeg_bufs = 0; jpeg_bufs < (int)cnt; jpeg_bufs++)  { \
46      if (ptr[jpeg_bufs] != NULL) { \
47          free(ptr[jpeg_bufs]); \
48          ptr[jpeg_bufs] = NULL; \
49      } \
50    }
51
52/*===========================================================================
53 * FUNCTION   : QCameraPostProcessor
54 *
55 * DESCRIPTION: constructor of QCameraPostProcessor.
56 *
57 * PARAMETERS :
58 *   @cam_ctrl : ptr to HWI object
59 *
60 * RETURN     : None
61 *==========================================================================*/
62QCameraPostProcessor::QCameraPostProcessor(QCamera2HardwareInterface *cam_ctrl)
63    : m_parent(cam_ctrl),
64      mJpegCB(NULL),
65      mJpegUserData(NULL),
66      mJpegClientHandle(0),
67      mJpegSessionId(0),
68      m_pJpegExifObj(NULL),
69      m_bThumbnailNeeded(TRUE),
70      m_pReprocChannel(NULL),
71      m_bInited(FALSE),
72      m_inputPPQ(releasePPInputData, this),
73      m_ongoingPPQ(releaseOngoingPPData, this),
74      m_inputJpegQ(releaseJpegData, this),
75      m_ongoingJpegQ(releaseJpegData, this),
76      m_inputRawQ(releaseRawData, this),
77      mSaveFrmCnt(0),
78      mUseSaveProc(false),
79      mUseJpegBurst(false),
80      mJpegMemOpt(true),
81      m_JpegOutputMemCount(0),
82      mNewJpegSessionNeeded(true)
83{
84    memset(&mJpegHandle, 0, sizeof(mJpegHandle));
85    memset(&m_pJpegOutputMem, 0, sizeof(m_pJpegOutputMem));
86}
87
88/*===========================================================================
89 * FUNCTION   : ~QCameraPostProcessor
90 *
91 * DESCRIPTION: deconstructor of QCameraPostProcessor.
92 *
93 * PARAMETERS : None
94 *
95 * RETURN     : None
96 *==========================================================================*/
97QCameraPostProcessor::~QCameraPostProcessor()
98{
99    FREE_JPEG_OUTPUT_BUFFER(m_pJpegOutputMem,m_JpegOutputMemCount);
100    if (m_pJpegExifObj != NULL) {
101        delete m_pJpegExifObj;
102        m_pJpegExifObj = NULL;
103    }
104    if (m_pReprocChannel != NULL) {
105        m_pReprocChannel->stop();
106        delete m_pReprocChannel;
107        m_pReprocChannel = NULL;
108    }
109}
110
111/*===========================================================================
112 * FUNCTION   : init
113 *
114 * DESCRIPTION: initialization of postprocessor
115 *
116 * PARAMETERS :
117 *   @jpeg_cb      : callback to handle jpeg event from mm-camera-interface
118 *   @user_data    : user data ptr for jpeg callback
119 *
120 * RETURN     : int32_t type of status
121 *              NO_ERROR  -- success
122 *              none-zero failure code
123 *==========================================================================*/
124int32_t QCameraPostProcessor::init(jpeg_encode_callback_t jpeg_cb, void *user_data)
125{
126    mJpegCB = jpeg_cb;
127    mJpegUserData = user_data;
128    mm_dimension max_size;
129
130    //set max pic size
131    memset(&max_size, 0, sizeof(mm_dimension));
132    max_size.w = m_parent->m_max_pic_width;
133    max_size.h = m_parent->m_max_pic_height;
134
135    mJpegClientHandle = jpeg_open(&mJpegHandle, max_size);
136    if(!mJpegClientHandle) {
137        ALOGE("%s : jpeg_open did not work", __func__);
138        return UNKNOWN_ERROR;
139    }
140
141    m_dataProcTh.launch(dataProcessRoutine, this);
142    m_saveProcTh.launch(dataSaveRoutine, this);
143
144    m_bInited = TRUE;
145    return NO_ERROR;
146}
147
148/*===========================================================================
149 * FUNCTION   : deinit
150 *
151 * DESCRIPTION: de-initialization of postprocessor
152 *
153 * PARAMETERS : None
154 *
155 * RETURN     : int32_t type of status
156 *              NO_ERROR  -- success
157 *              none-zero failure code
158 *==========================================================================*/
159int32_t QCameraPostProcessor::deinit()
160{
161    if (m_bInited == TRUE) {
162        m_dataProcTh.exit();
163        m_saveProcTh.exit();
164
165        if(mJpegClientHandle > 0) {
166            int rc = mJpegHandle.close(mJpegClientHandle);
167            CDBG_HIGH("%s: Jpeg closed, rc = %d, mJpegClientHandle = %x",
168                  __func__, rc, mJpegClientHandle);
169            mJpegClientHandle = 0;
170            memset(&mJpegHandle, 0, sizeof(mJpegHandle));
171        }
172        m_bInited = FALSE;
173    }
174    return NO_ERROR;
175}
176
177/*===========================================================================
178 * FUNCTION   : start
179 *
180 * DESCRIPTION: start postprocessor. Data process thread and data notify thread
181 *              will be launched.
182 *
183 * PARAMETERS :
184 *   @pSrcChannel : source channel obj ptr that possibly needs reprocess
185 *
186 * RETURN     : int32_t type of status
187 *              NO_ERROR  -- success
188 *              none-zero failure code
189 *
190 * NOTE       : if any reprocess is needed, a reprocess channel/stream
191 *              will be started.
192 *==========================================================================*/
193int32_t QCameraPostProcessor::start(QCameraChannel *pSrcChannel)
194{
195    char prop[PROPERTY_VALUE_MAX];
196    int32_t rc = NO_ERROR;
197    if (m_bInited == FALSE) {
198        ALOGE("%s: postproc not initialized yet", __func__);
199        return UNKNOWN_ERROR;
200    }
201
202    if (m_parent->needReprocess()) {
203        if (m_pReprocChannel != NULL) {
204            delete m_pReprocChannel;
205            m_pReprocChannel = NULL;
206        }
207        // if reprocess is needed, start reprocess channel
208        m_pReprocChannel = m_parent->addReprocChannel(pSrcChannel);
209        if (m_pReprocChannel == NULL) {
210            ALOGE("%s: cannot add reprocess channel", __func__);
211            return UNKNOWN_ERROR;
212        }
213
214        rc = m_pReprocChannel->start();
215        if (rc != 0) {
216            ALOGE("%s: cannot start reprocess channel", __func__);
217            delete m_pReprocChannel;
218            m_pReprocChannel = NULL;
219            return rc;
220        }
221    }
222
223    property_get("persist.camera.longshot.save", prop, "0");
224    mUseSaveProc = atoi(prop) > 0 ? true : false;
225
226    m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, TRUE, FALSE);
227    m_parent->m_cbNotifier.startSnapshots();
228
229    // Create Jpeg session
230    if ( !m_parent->mParameters.getRecordingHintValue() &&
231            !m_parent->isLongshotEnabled() &&
232            !m_parent->isZSLMode()) {
233
234        QCameraChannel *pChannel = NULL;
235        pChannel = m_parent->needReprocess() ? m_pReprocChannel : pSrcChannel;
236        QCameraStream *pSnapshotStream = NULL;
237        QCameraStream *pThumbStream = NULL;
238
239        for (int i = 0; i < pChannel->getNumOfStreams(); ++i) {
240            QCameraStream *pStream = pChannel->getStreamByIndex(i);
241
242            if ( NULL == pStream ) {
243                break;
244            }
245
246            if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
247                    pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT)) {
248                pSnapshotStream = pStream;
249            }
250
251            if (pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) ||
252                    pStream->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW)) {
253                pThumbStream = pStream;
254            }
255        }
256
257        // If thumbnail is not part of the reprocess channel, then
258        // try to get it from the source channel
259        if ((NULL == pThumbStream) && (pChannel == m_pReprocChannel)) {
260            for (int i = 0; i < pSrcChannel->getNumOfStreams(); ++i) {
261                QCameraStream *pStream = pSrcChannel->getStreamByIndex(i);
262
263                if ( NULL == pStream ) {
264                    break;
265                }
266
267                if (pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) ||
268                    pStream->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW)) {
269                    pThumbStream = pStream;
270                }
271            }
272        }
273
274        if (m_parent->mParameters.generateThumbFromMain()) {
275            pThumbStream = NULL;
276        }
277
278        if ( NULL != pSnapshotStream ) {
279            mm_jpeg_encode_params_t encodeParam;
280            memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t));
281            getJpegEncodingConfig(encodeParam, pSnapshotStream, pThumbStream);
282            CDBG_HIGH("[KPI Perf] %s : call jpeg create_session", __func__);
283
284            rc = mJpegHandle.create_session(mJpegClientHandle,
285                    &encodeParam,
286                    &mJpegSessionId);
287            if (rc != NO_ERROR) {
288                ALOGE("%s: error creating a new jpeg encoding session", __func__);
289                return rc;
290            }
291            mNewJpegSessionNeeded = false;
292        }
293    }
294
295    return rc;
296}
297
298/*===========================================================================
299 * FUNCTION   : stop
300 *
301 * DESCRIPTION: stop postprocessor. Data process and notify thread will be stopped.
302 *
303 * PARAMETERS : None
304 *
305 * RETURN     : int32_t type of status
306 *              NO_ERROR  -- success
307 *              none-zero failure code
308 *
309 * NOTE       : reprocess channel will be stopped and deleted if there is any
310 *==========================================================================*/
311int32_t QCameraPostProcessor::stop()
312{
313    if (m_bInited == TRUE) {
314        m_parent->m_cbNotifier.stopSnapshots();
315        // dataProc Thread need to process "stop" as sync call because abort jpeg job should be a sync call
316        m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE);
317    }
318
319    return NO_ERROR;
320}
321
322/*===========================================================================
323 * FUNCTION   : getJpegEncodingConfig
324 *
325 * DESCRIPTION: function to prepare encoding job information
326 *
327 * PARAMETERS :
328 *   @encode_parm   : param to be filled with encoding configuration
329 *
330 * RETURN     : int32_t type of status
331 *              NO_ERROR  -- success
332 *              none-zero failure code
333 *==========================================================================*/
334int32_t QCameraPostProcessor::getJpegEncodingConfig(mm_jpeg_encode_params_t& encode_parm,
335                                                    QCameraStream *main_stream,
336                                                    QCameraStream *thumb_stream)
337{
338    CDBG("%s : E", __func__);
339    int32_t ret = NO_ERROR;
340    uint32_t out_size;
341
342    char prop[PROPERTY_VALUE_MAX];
343    property_get("persist.camera.jpeg_burst", prop, "0");
344    mUseJpegBurst = (atoi(prop) > 0) && !mUseSaveProc;
345    encode_parm.burst_mode = mUseJpegBurst;
346
347    cam_rect_t crop;
348    memset(&crop, 0, sizeof(cam_rect_t));
349    main_stream->getCropInfo(crop);
350
351    cam_dimension_t src_dim, dst_dim;
352    memset(&src_dim, 0, sizeof(cam_dimension_t));
353    memset(&dst_dim, 0, sizeof(cam_dimension_t));
354    main_stream->getFrameDimension(src_dim);
355
356    bool hdr_output_crop = m_parent->mParameters.isHDROutputCropEnabled();
357    if (hdr_output_crop && crop.height) {
358        dst_dim.height = crop.height;
359    } else {
360        dst_dim.height = src_dim.height;
361    }
362    if (hdr_output_crop && crop.width) {
363        dst_dim.width = crop.width;
364    } else {
365        dst_dim.width = src_dim.width;
366    }
367
368    // set rotation only when no online rotation or offline pp rotation is done before
369    if (!m_parent->needRotationReprocess()) {
370        encode_parm.rotation = m_parent->getJpegRotation();
371    }
372
373    encode_parm.main_dim.src_dim = src_dim;
374    encode_parm.main_dim.dst_dim = dst_dim;
375
376    encode_parm.jpeg_cb = mJpegCB;
377    encode_parm.userdata = mJpegUserData;
378
379    m_bThumbnailNeeded = TRUE; // need encode thumbnail by default
380    cam_dimension_t thumbnailSize;
381    memset(&thumbnailSize, 0, sizeof(cam_dimension_t));
382    m_parent->getThumbnailSize(thumbnailSize);
383    if (thumbnailSize.width == 0 || thumbnailSize.height == 0) {
384        // (0,0) means no thumbnail
385        m_bThumbnailNeeded = FALSE;
386    }
387    encode_parm.encode_thumbnail = m_bThumbnailNeeded;
388
389    // get color format
390    cam_format_t img_fmt = CAM_FORMAT_YUV_420_NV12;
391    main_stream->getFormat(img_fmt);
392    encode_parm.color_format = getColorfmtFromImgFmt(img_fmt);
393
394    // get jpeg quality
395    encode_parm.quality = m_parent->getJpegQuality();
396    if (encode_parm.quality <= 0) {
397        encode_parm.quality = 85;
398    }
399    cam_frame_len_offset_t main_offset;
400    memset(&main_offset, 0, sizeof(cam_frame_len_offset_t));
401    main_stream->getFrameOffset(main_offset);
402
403    // src buf config
404    QCameraMemory *pStreamMem = main_stream->getStreamBufs();
405    if (pStreamMem == NULL) {
406        ALOGE("%s: cannot get stream bufs from main stream", __func__);
407        ret = BAD_VALUE;
408        goto on_error;
409    }
410    encode_parm.num_src_bufs = pStreamMem->getCnt();
411    for (uint32_t i = 0; i < encode_parm.num_src_bufs; i++) {
412        camera_memory_t *stream_mem = pStreamMem->getMemory(i, false);
413        if (stream_mem != NULL) {
414            encode_parm.src_main_buf[i].index = i;
415            encode_parm.src_main_buf[i].buf_size = stream_mem->size;
416            encode_parm.src_main_buf[i].buf_vaddr = (uint8_t *)stream_mem->data;
417            encode_parm.src_main_buf[i].fd = pStreamMem->getFd(i);
418            encode_parm.src_main_buf[i].format = MM_JPEG_FMT_YUV;
419            encode_parm.src_main_buf[i].offset = main_offset;
420        }
421    }
422
423    if (m_bThumbnailNeeded == TRUE) {
424        bool need_thumb_rotate = true;
425        int jpeg_rotation = m_parent->getJpegRotation();
426        m_parent->getThumbnailSize(encode_parm.thumb_dim.dst_dim);
427
428        if (thumb_stream == NULL) {
429            thumb_stream = main_stream;
430            need_thumb_rotate = false;
431        }
432        pStreamMem = thumb_stream->getStreamBufs();
433        if (pStreamMem == NULL) {
434            ALOGE("%s: cannot get stream bufs from thumb stream", __func__);
435            ret = BAD_VALUE;
436            goto on_error;
437        }
438        cam_frame_len_offset_t thumb_offset;
439        memset(&thumb_offset, 0, sizeof(cam_frame_len_offset_t));
440        thumb_stream->getFrameOffset(thumb_offset);
441        encode_parm.num_tmb_bufs =  pStreamMem->getCnt();
442        for (int i = 0; i < pStreamMem->getCnt(); i++) {
443            camera_memory_t *stream_mem = pStreamMem->getMemory(i, false);
444            if (stream_mem != NULL) {
445                encode_parm.src_thumb_buf[i].index = i;
446                encode_parm.src_thumb_buf[i].buf_size = stream_mem->size;
447                encode_parm.src_thumb_buf[i].buf_vaddr = (uint8_t *)stream_mem->data;
448                encode_parm.src_thumb_buf[i].fd = pStreamMem->getFd(i);
449                encode_parm.src_thumb_buf[i].format = MM_JPEG_FMT_YUV;
450                encode_parm.src_thumb_buf[i].offset = thumb_offset;
451            }
452        }
453        cam_format_t img_fmt_thumb = CAM_FORMAT_YUV_420_NV12;
454        thumb_stream->getFormat(img_fmt_thumb);
455        encode_parm.thumb_color_format = getColorfmtFromImgFmt(img_fmt_thumb);
456
457        // crop is the same if frame is the same
458        if (thumb_stream != main_stream) {
459            memset(&crop, 0, sizeof(cam_rect_t));
460            thumb_stream->getCropInfo(crop);
461        }
462
463        memset(&src_dim, 0, sizeof(cam_dimension_t));
464        thumb_stream->getFrameDimension(src_dim);
465        encode_parm.thumb_dim.src_dim = src_dim;
466
467        if (!m_parent->needRotationReprocess() || need_thumb_rotate) {
468            encode_parm.thumb_rotation = jpeg_rotation;
469        } else if ((90 == jpeg_rotation) || (270 == jpeg_rotation)) {
470            // swap thumbnail dimensions
471            cam_dimension_t tmp_dim = encode_parm.thumb_dim.dst_dim;
472            encode_parm.thumb_dim.dst_dim.width = tmp_dim.height;
473            encode_parm.thumb_dim.dst_dim.height = tmp_dim.width;
474        }
475        encode_parm.thumb_dim.crop = crop;
476    }
477
478    encode_parm.num_dst_bufs = 1;
479    if (mUseJpegBurst) {
480        encode_parm.num_dst_bufs = MAX_JPEG_BURST;
481    }
482    encode_parm.get_memory = NULL;
483    out_size = main_offset.frame_len;
484    if (mJpegMemOpt) {
485        encode_parm.get_memory = getJpegMemory;
486        out_size = sizeof(omx_jpeg_ouput_buf_t);
487        encode_parm.num_dst_bufs = encode_parm.num_src_bufs;
488    }
489    m_JpegOutputMemCount = encode_parm.num_dst_bufs;
490    for (int i = 0; i < (int)m_JpegOutputMemCount; i++) {
491        if (m_pJpegOutputMem[i] != NULL)
492          free(m_pJpegOutputMem[i]);
493        omx_jpeg_ouput_buf_t omx_out_buf;
494        omx_out_buf.handle = this;
495        // allocate output buf for jpeg encoding
496        m_pJpegOutputMem[i] = malloc(out_size);
497
498        if (NULL == m_pJpegOutputMem[i]) {
499          ret = NO_MEMORY;
500          ALOGE("%s : initHeapMem for jpeg, ret = NO_MEMORY", __func__);
501          goto on_error;
502        }
503
504        if (mJpegMemOpt) {
505            memcpy(m_pJpegOutputMem[i], &omx_out_buf, sizeof(omx_out_buf));
506        }
507
508
509        encode_parm.dest_buf[i].index = i;
510        encode_parm.dest_buf[i].buf_size = main_offset.frame_len;
511        encode_parm.dest_buf[i].buf_vaddr = (uint8_t *)m_pJpegOutputMem[i];
512        encode_parm.dest_buf[i].fd = 0;
513        encode_parm.dest_buf[i].format = MM_JPEG_FMT_YUV;
514        encode_parm.dest_buf[i].offset = main_offset;
515    }
516
517
518    CDBG("%s : X", __func__);
519    return NO_ERROR;
520
521on_error:
522    FREE_JPEG_OUTPUT_BUFFER(m_pJpegOutputMem, m_JpegOutputMemCount);
523
524    CDBG("%s : X with error %d", __func__, ret);
525    return ret;
526}
527
528/*===========================================================================
529 * FUNCTION   : sendEvtNotify
530 *
531 * DESCRIPTION: send event notify through notify callback registered by upper layer
532 *
533 * PARAMETERS :
534 *   @msg_type: msg type of notify
535 *   @ext1    : extension
536 *   @ext2    : extension
537 *
538 * RETURN     : int32_t type of status
539 *              NO_ERROR  -- success
540 *              none-zero failure code
541 *==========================================================================*/
542int32_t QCameraPostProcessor::sendEvtNotify(int32_t msg_type,
543                                            int32_t ext1,
544                                            int32_t ext2)
545{
546    return m_parent->sendEvtNotify(msg_type, ext1, ext2);
547}
548
549/*===========================================================================
550 * FUNCTION   : sendDataNotify
551 *
552 * DESCRIPTION: enqueue data into dataNotify thread
553 *
554 * PARAMETERS :
555 *   @msg_type: data callback msg type
556 *   @data    : ptr to data memory struct
557 *   @index   : index to data buffer
558 *   @metadata: ptr to meta data buffer if there is any
559 *   @release_data : ptr to struct indicating if data need to be released
560 *                   after notify
561 *
562 * RETURN     : int32_t type of status
563 *              NO_ERROR  -- success
564 *              none-zero failure code
565 *==========================================================================*/
566int32_t QCameraPostProcessor::sendDataNotify(int32_t msg_type,
567                                             camera_memory_t *data,
568                                             uint8_t index,
569                                             camera_frame_metadata_t *metadata,
570                                             qcamera_release_data_t *release_data)
571{
572    qcamera_data_argm_t *data_cb = (qcamera_data_argm_t *)malloc(sizeof(qcamera_data_argm_t));
573    if (NULL == data_cb) {
574        ALOGE("%s: no mem for acamera_data_argm_t", __func__);
575        return NO_MEMORY;
576    }
577    memset(data_cb, 0, sizeof(qcamera_data_argm_t));
578    data_cb->msg_type = msg_type;
579    data_cb->data = data;
580    data_cb->index = index;
581    data_cb->metadata = metadata;
582    if (release_data != NULL) {
583        data_cb->release_data = *release_data;
584    }
585
586    qcamera_callback_argm_t cbArg;
587    memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
588    cbArg.cb_type = QCAMERA_DATA_SNAPSHOT_CALLBACK;
589    cbArg.msg_type = msg_type;
590    cbArg.data = data;
591    cbArg.metadata = metadata;
592    cbArg.user_data = data_cb;
593    cbArg.cookie = this;
594    cbArg.release_cb = releaseNotifyData;
595    int rc = m_parent->m_cbNotifier.notifyCallback(cbArg);
596    if ( NO_ERROR != rc ) {
597        ALOGE("%s: Error enqueuing jpeg data into notify queue", __func__);
598        releaseNotifyData(data_cb, this, UNKNOWN_ERROR);
599        return UNKNOWN_ERROR;
600    }
601
602    return rc;
603}
604
605/*===========================================================================
606 * FUNCTION   : processData
607 *
608 * DESCRIPTION: enqueue data into dataProc thread
609 *
610 * PARAMETERS :
611 *   @frame   : process frame received from mm-camera-interface
612 *
613 * RETURN     : int32_t type of status
614 *              NO_ERROR  -- success
615 *              none-zero failure code
616 *
617 * NOTE       : depends on if offline reprocess is needed, received frame will
618 *              be sent to either input queue of postprocess or jpeg encoding
619 *==========================================================================*/
620int32_t QCameraPostProcessor::processData(mm_camera_super_buf_t *frame)
621{
622    if (m_bInited == FALSE) {
623        ALOGE("%s: postproc not initialized yet", __func__);
624        return UNKNOWN_ERROR;
625    }
626
627    if (m_parent->needReprocess()) {
628        if ((!m_parent->isLongshotEnabled() &&
629             !m_parent->m_stateMachine.isNonZSLCaptureRunning()) ||
630            (m_parent->isLongshotEnabled() &&
631             m_parent->isCaptureShutterEnabled())) {
632            //play shutter sound
633            m_parent->playShutter();
634        }
635
636        CDBG_HIGH("%s: need reprocess", __func__);
637        // enqueu to post proc input queue
638        m_inputPPQ.enqueue((void *)frame);
639    } else if (m_parent->mParameters.isNV16PictureFormat() ||
640        m_parent->mParameters.isNV21PictureFormat()) {
641        //check if raw frame information is needed.
642        if(m_parent->mParameters.isYUVFrameInfoNeeded())
643            setYUVFrameInfo(frame);
644
645        processRawData(frame);
646    } else {
647        //play shutter sound
648        if(!m_parent->m_stateMachine.isNonZSLCaptureRunning() &&
649           !m_parent->mLongshotEnabled)
650           m_parent->playShutter();
651
652        CDBG_HIGH("%s: no need offline reprocess, sending to jpeg encoding", __func__);
653        qcamera_jpeg_data_t *jpeg_job =
654            (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t));
655        if (jpeg_job == NULL) {
656            ALOGE("%s: No memory for jpeg job", __func__);
657            return NO_MEMORY;
658        }
659
660        memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t));
661        jpeg_job->src_frame = frame;
662
663        // find meta data frame
664        mm_camera_buf_def_t *meta_frame = NULL;
665        for (int i = 0; i < frame->num_bufs; i++) {
666            // look through input superbuf
667            if (frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) {
668                meta_frame = frame->bufs[i];
669                break;
670            }
671        }
672
673        if (meta_frame != NULL) {
674            // fill in meta data frame ptr
675            jpeg_job->metadata = (metadata_buffer_t *)meta_frame->buffer;
676        }
677
678        // enqueu to jpeg input queue
679        m_inputJpegQ.enqueue((void *)jpeg_job);
680    }
681    m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
682
683    return NO_ERROR;
684}
685
686/*===========================================================================
687 * FUNCTION   : processRawData
688 *
689 * DESCRIPTION: enqueue raw data into dataProc thread
690 *
691 * PARAMETERS :
692 *   @frame   : process frame received from mm-camera-interface
693 *
694 * RETURN     : int32_t type of status
695 *              NO_ERROR  -- success
696 *              none-zero failure code
697 *==========================================================================*/
698int32_t QCameraPostProcessor::processRawData(mm_camera_super_buf_t *frame)
699{
700    if (m_bInited == FALSE) {
701        ALOGE("%s: postproc not initialized yet", __func__);
702        return UNKNOWN_ERROR;
703    }
704
705    // enqueu to raw input queue
706    m_inputRawQ.enqueue((void *)frame);
707    m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
708    return NO_ERROR;
709}
710
711/*===========================================================================
712 * FUNCTION   : processJpegEvt
713 *
714 * DESCRIPTION: process jpeg event from mm-jpeg-interface.
715 *
716 * PARAMETERS :
717 *   @evt     : payload of jpeg event, including information about jpeg encoding
718 *              status, jpeg size and so on.
719 *
720 * RETURN     : int32_t type of status
721 *              NO_ERROR  -- success
722 *              none-zero failure code
723 *
724 * NOTE       : This event will also trigger DataProc thread to move to next job
725 *              processing (i.e., send a new jpeg encoding job to mm-jpeg-interface
726 *              if there is any pending job in jpeg input queue)
727 *==========================================================================*/
728int32_t QCameraPostProcessor::processJpegEvt(qcamera_jpeg_evt_payload_t *evt)
729{
730    if (m_bInited == FALSE) {
731        ALOGE("%s: postproc not initialized yet", __func__);
732        return UNKNOWN_ERROR;
733    }
734
735    int32_t rc = NO_ERROR;
736    camera_memory_t *jpeg_mem = NULL;
737    omx_jpeg_ouput_buf_t *jpeg_out = NULL;
738
739    if (mUseSaveProc && m_parent->isLongshotEnabled()) {
740        qcamera_jpeg_evt_payload_t *saveData = ( qcamera_jpeg_evt_payload_t * ) malloc(sizeof(qcamera_jpeg_evt_payload_t));
741        if ( NULL == saveData ) {
742            ALOGE("%s: Can not allocate save data message!", __func__);
743            return NO_MEMORY;
744        }
745        *saveData = *evt;
746        m_inputSaveQ.enqueue((void *) saveData);
747        m_saveProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
748    } else {
749        // Release jpeg job data
750        m_ongoingJpegQ.flushNodes(matchJobId, (void*)&evt->jobId);
751
752        CDBG_HIGH("[KPI Perf] %s : jpeg job %d", __func__, evt->jobId);
753
754        if (m_parent->mDataCb == NULL ||
755            m_parent->msgTypeEnabledWithLock(CAMERA_MSG_COMPRESSED_IMAGE) == 0 ) {
756            CDBG_HIGH("%s: No dataCB or CAMERA_MSG_COMPRESSED_IMAGE not enabled",
757                  __func__);
758            rc = NO_ERROR;
759            goto end;
760        }
761
762        if(evt->status == JPEG_JOB_STATUS_ERROR) {
763            ALOGE("%s: Error event handled from jpeg, status = %d",
764                  __func__, evt->status);
765            rc = FAILED_TRANSACTION;
766            goto end;
767        }
768
769        m_parent->dumpJpegToFile(evt->out_data.buf_vaddr,
770                                  evt->out_data.buf_filled_len,
771                                  evt->jobId);
772        CDBG_HIGH("%s: Dump jpeg_size=%d", __func__, evt->out_data.buf_filled_len);
773
774        /* check if the all the captures are done */
775        if (m_parent->mParameters.isUbiRefocus() &&
776            (m_parent->getOutputImageCount() <
777            m_parent->mParameters.UfOutputCount())) {
778            jpeg_out  = (omx_jpeg_ouput_buf_t*) evt->out_data.buf_vaddr;
779            jpeg_mem = (camera_memory_t *)jpeg_out->mem_hdl;
780            if (NULL != jpeg_mem) {
781                jpeg_mem->release(jpeg_mem);
782                jpeg_mem = NULL;
783            }
784            goto end;
785        }
786
787        if (!mJpegMemOpt) {
788            // alloc jpeg memory to pass to upper layer
789            jpeg_mem = m_parent->mGetMemory(-1, evt->out_data.buf_filled_len,
790                1, m_parent->mCallbackCookie);
791            if (NULL == jpeg_mem) {
792                rc = NO_MEMORY;
793                ALOGE("%s : getMemory for jpeg, ret = NO_MEMORY", __func__);
794                goto end;
795            }
796            memcpy(jpeg_mem->data, evt->out_data.buf_vaddr, evt->out_data.buf_filled_len);
797        } else {
798            jpeg_out  = (omx_jpeg_ouput_buf_t*) evt->out_data.buf_vaddr;
799            jpeg_mem = (camera_memory_t *)jpeg_out->mem_hdl;
800        }
801
802        CDBG_HIGH("%s : Calling upperlayer callback to store JPEG image", __func__);
803        qcamera_release_data_t release_data;
804        memset(&release_data, 0, sizeof(qcamera_release_data_t));
805        release_data.data = jpeg_mem;
806        CDBG_HIGH("[KPI Perf] %s: PROFILE_JPEG_CB ",__func__);
807        rc = sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE,
808                            jpeg_mem,
809                            0,
810                            NULL,
811                            &release_data);
812
813end:
814        if (rc != NO_ERROR) {
815            // send error msg to upper layer
816            sendEvtNotify(CAMERA_MSG_ERROR,
817                          UNKNOWN_ERROR,
818                          0);
819
820            if (NULL != jpeg_mem) {
821                jpeg_mem->release(jpeg_mem);
822                jpeg_mem = NULL;
823            }
824        }
825    }
826
827    // wait up data proc thread to do next job,
828    // if previous request is blocked due to ongoing jpeg job
829    m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
830
831    return rc;
832}
833
834/*===========================================================================
835 * FUNCTION   : processPPData
836 *
837 * DESCRIPTION: process received frame after reprocess.
838 *
839 * PARAMETERS :
840 *   @frame   : received frame from reprocess channel.
841 *
842 * RETURN     : int32_t type of status
843 *              NO_ERROR  -- success
844 *              none-zero failure code
845 *
846 * NOTE       : The frame after reprocess need to send to jpeg encoding.
847 *==========================================================================*/
848int32_t QCameraPostProcessor::processPPData(mm_camera_super_buf_t *frame)
849{
850    bool needSuperBufMatch = m_parent->mParameters.generateThumbFromMain();
851    if (m_bInited == FALSE) {
852        ALOGE("%s: postproc not initialized yet", __func__);
853        return UNKNOWN_ERROR;
854    }
855
856    qcamera_pp_data_t *job = (qcamera_pp_data_t *)m_ongoingPPQ.dequeue();
857
858    if (!needSuperBufMatch && (job == NULL || job->src_frame == NULL) ) {
859        ALOGE("%s: Cannot find reprocess job", __func__);
860        return BAD_VALUE;
861    }
862
863    if (!needSuperBufMatch && (m_parent->mParameters.isNV16PictureFormat() ||
864        m_parent->mParameters.isNV21PictureFormat())) {
865        releaseSuperBuf(job->src_frame);
866        free(job->src_frame);
867        free(job);
868
869        if(m_parent->mParameters.isYUVFrameInfoNeeded())
870            setYUVFrameInfo(frame);
871        return processRawData(frame);
872    }
873
874    if (m_parent->isLongshotEnabled() &&
875            !m_parent->isCaptureShutterEnabled()) {
876        // play shutter sound for longshot
877        // after reprocess is done
878        // TODO: Move this after CAC done event
879        m_parent->playShutter();
880    }
881
882    qcamera_jpeg_data_t *jpeg_job =
883        (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t));
884    if (jpeg_job == NULL) {
885        ALOGE("%s: No memory for jpeg job", __func__);
886        return NO_MEMORY;
887    }
888
889    memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t));
890    jpeg_job->src_frame = frame;
891    jpeg_job->src_reproc_frame = job ? job->src_frame : NULL;
892    jpeg_job->src_reproc_bufs = job ? job->src_reproc_bufs : NULL;
893    jpeg_job->reproc_frame_release = job ? job->reproc_frame_release : false;
894
895    // find meta data frame
896    mm_camera_buf_def_t *meta_frame = NULL;
897    for (int i = 0; job && (i < job->src_frame->num_bufs); i++) {
898        // look through input superbuf
899        if (job->src_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) {
900            meta_frame = job->src_frame->bufs[i];
901            break;
902        }
903    }
904
905    if (meta_frame == NULL) {
906        // look through reprocess superbuf
907        for (int i = 0; i < frame->num_bufs; i++) {
908            if (frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) {
909                meta_frame = frame->bufs[i];
910                break;
911            }
912        }
913    }
914
915    if (meta_frame != NULL) {
916        // fill in meta data frame ptr
917        jpeg_job->metadata = (metadata_buffer_t *)meta_frame->buffer;
918    }
919
920    // free pp job buf
921    if (job) {
922        free(job);
923    }
924
925    // enqueu reprocessed frame to jpeg input queue
926    m_inputJpegQ.enqueue((void *)jpeg_job);
927
928    ALOGD("%s: %d] ", __func__, __LINE__);
929    // wait up data proc thread
930    m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
931
932    return NO_ERROR;
933}
934
935/*===========================================================================
936 * FUNCTION   : findJpegJobByJobId
937 *
938 * DESCRIPTION: find a jpeg job from ongoing Jpeg queue by its job ID
939 *
940 * PARAMETERS :
941 *   @jobId   : job Id of the job
942 *
943 * RETURN     : ptr to a jpeg job struct. NULL if not found.
944 *
945 * NOTE       : Currently only one job is sending to mm-jpeg-interface for jpeg
946 *              encoding. Therefore simply dequeue from the ongoing Jpeg Queue
947 *              will serve the purpose to find the jpeg job.
948 *==========================================================================*/
949qcamera_jpeg_data_t *QCameraPostProcessor::findJpegJobByJobId(uint32_t jobId)
950{
951    qcamera_jpeg_data_t * job = NULL;
952    if (jobId == 0) {
953        ALOGE("%s: not a valid jpeg jobId", __func__);
954        return NULL;
955    }
956
957    // currely only one jpeg job ongoing, so simply dequeue the head
958    job = (qcamera_jpeg_data_t *)m_ongoingJpegQ.dequeue();
959    return job;
960}
961
962/*===========================================================================
963 * FUNCTION   : releasePPInputData
964 *
965 * DESCRIPTION: callback function to release post process input data node
966 *
967 * PARAMETERS :
968 *   @data      : ptr to post process input data
969 *   @user_data : user data ptr (QCameraReprocessor)
970 *
971 * RETURN     : None
972 *==========================================================================*/
973void QCameraPostProcessor::releasePPInputData(void *data, void *user_data)
974{
975    QCameraPostProcessor *pme = (QCameraPostProcessor *)user_data;
976    if (NULL != pme) {
977        pme->releaseSuperBuf((mm_camera_super_buf_t *)data);
978    }
979}
980
981/*===========================================================================
982 * FUNCTION   : releaseJpegData
983 *
984 * DESCRIPTION: callback function to release jpeg job node
985 *
986 * PARAMETERS :
987 *   @data      : ptr to ongoing jpeg job data
988 *   @user_data : user data ptr (QCameraReprocessor)
989 *
990 * RETURN     : None
991 *==========================================================================*/
992void QCameraPostProcessor::releaseJpegData(void *data, void *user_data)
993{
994    QCameraPostProcessor *pme = (QCameraPostProcessor *)user_data;
995    if (NULL != pme) {
996        pme->releaseJpegJobData((qcamera_jpeg_data_t *)data);
997        CDBG_HIGH("%s : Rleased job ID %u", __func__,
998            ((qcamera_jpeg_data_t *)data)->jobId);
999    }
1000}
1001
1002/*===========================================================================
1003 * FUNCTION   : releaseOngoingPPData
1004 *
1005 * DESCRIPTION: callback function to release ongoing postprocess job node
1006 *
1007 * PARAMETERS :
1008 *   @data      : ptr to onging postprocess job
1009 *   @user_data : user data ptr (QCameraReprocessor)
1010 *
1011 * RETURN     : None
1012 *==========================================================================*/
1013void QCameraPostProcessor::releaseOngoingPPData(void *data, void *user_data)
1014{
1015    QCameraPostProcessor *pme = (QCameraPostProcessor *)user_data;
1016    if (NULL != pme) {
1017        qcamera_pp_data_t *pp_job = (qcamera_pp_data_t *)data;
1018        if (NULL != pp_job->src_frame) {
1019            if (!pp_job->reproc_frame_release) {
1020                pme->releaseSuperBuf(pp_job->src_frame);
1021            }
1022            free(pp_job->src_frame);
1023            pp_job->src_frame = NULL;
1024        }
1025    }
1026}
1027
1028/*===========================================================================
1029 * FUNCTION   : releaseNotifyData
1030 *
1031 * DESCRIPTION: function to release internal resources in notify data struct
1032 *
1033 * PARAMETERS :
1034 *   @user_data  : ptr user data
1035 *   @cookie     : callback cookie
1036 *   @cb_status  : callback status
1037 *
1038 * RETURN     : None
1039 *
1040 * NOTE       : deallocate jpeg heap memory if it's not NULL
1041 *==========================================================================*/
1042void QCameraPostProcessor::releaseNotifyData(void *user_data,
1043                                             void *cookie,
1044                                             int32_t cb_status)
1045{
1046    qcamera_data_argm_t *app_cb = ( qcamera_data_argm_t * ) user_data;
1047    QCameraPostProcessor *postProc = ( QCameraPostProcessor * ) cookie;
1048    if ( ( NULL != app_cb ) && ( NULL != postProc ) ) {
1049
1050        if ( postProc->mUseSaveProc &&
1051             app_cb->release_data.unlinkFile &&
1052             ( NO_ERROR != cb_status ) ) {
1053
1054            String8 unlinkPath((const char *) app_cb->release_data.data->data,
1055                                app_cb->release_data.data->size);
1056            int rc = unlink(unlinkPath.string());
1057            CDBG_HIGH("%s : Unlinking stored file rc = %d",
1058                  __func__,
1059                  rc);
1060        }
1061
1062        if (app_cb && NULL != app_cb->release_data.data) {
1063            app_cb->release_data.data->release(app_cb->release_data.data);
1064            app_cb->release_data.data = NULL;
1065        }
1066        if (app_cb && NULL != app_cb->release_data.frame) {
1067            postProc->releaseSuperBuf(app_cb->release_data.frame);
1068            free(app_cb->release_data.frame);
1069            app_cb->release_data.frame = NULL;
1070        }
1071        if (app_cb && NULL != app_cb->release_data.streamBufs) {
1072            app_cb->release_data.streamBufs->deallocate();
1073            delete app_cb->release_data.streamBufs;
1074            app_cb->release_data.streamBufs = NULL;
1075        }
1076        free(app_cb);
1077    }
1078}
1079
1080/*===========================================================================
1081 * FUNCTION   : releaseSuperBuf
1082 *
1083 * DESCRIPTION: function to release a superbuf frame by returning back to kernel
1084 *
1085 * PARAMETERS :
1086 *   @super_buf : ptr to the superbuf frame
1087 *
1088 * RETURN     : None
1089 *==========================================================================*/
1090void QCameraPostProcessor::releaseSuperBuf(mm_camera_super_buf_t *super_buf)
1091{
1092    QCameraChannel *pChannel = NULL;
1093
1094    if (NULL != super_buf) {
1095        pChannel = m_parent->getChannelByHandle(super_buf->ch_id);
1096
1097        if ( NULL == pChannel ) {
1098            if (m_pReprocChannel != NULL &&
1099                m_pReprocChannel->getMyHandle() == super_buf->ch_id) {
1100                pChannel = m_pReprocChannel;
1101            }
1102        }
1103
1104        if (pChannel != NULL) {
1105            pChannel->bufDone(super_buf);
1106        } else {
1107            ALOGE(" %s : Channel id %d not found!!",
1108                  __func__,
1109                  super_buf->ch_id);
1110        }
1111    }
1112}
1113
1114/*===========================================================================
1115 * FUNCTION   : releaseJpegJobData
1116 *
1117 * DESCRIPTION: function to release internal resources in jpeg job struct
1118 *
1119 * PARAMETERS :
1120 *   @job     : ptr to jpeg job struct
1121 *
1122 * RETURN     : None
1123 *
1124 * NOTE       : original source frame need to be queued back to kernel for
1125 *              future use. Output buf of jpeg job need to be released since
1126 *              it's allocated for each job. Exif object need to be deleted.
1127 *==========================================================================*/
1128void QCameraPostProcessor::releaseJpegJobData(qcamera_jpeg_data_t *job)
1129{
1130    CDBG("%s: E", __func__);
1131    if (NULL != job) {
1132        if (NULL != job->src_reproc_frame) {
1133            if (!job->reproc_frame_release) {
1134                releaseSuperBuf(job->src_reproc_frame);
1135            }
1136            free(job->src_reproc_frame);
1137            job->src_reproc_frame = NULL;
1138        }
1139
1140        if (NULL != job->src_frame) {
1141            releaseSuperBuf(job->src_frame);
1142            free(job->src_frame);
1143            job->src_frame = NULL;
1144        }
1145
1146        if (NULL != job->pJpegExifObj) {
1147            delete job->pJpegExifObj;
1148            job->pJpegExifObj = NULL;
1149        }
1150
1151        if (NULL != job->src_reproc_bufs) {
1152            delete [] job->src_reproc_bufs;
1153        }
1154
1155    }
1156    CDBG("%s: X", __func__);
1157}
1158
1159/*===========================================================================
1160 * FUNCTION   : releaseSaveJobData
1161 *
1162 * DESCRIPTION: function to release internal resources in store jobs
1163 *
1164 * PARAMETERS :
1165 *   @job     : ptr to save job struct
1166 *
1167 * RETURN     : None
1168 *
1169 *==========================================================================*/
1170void QCameraPostProcessor::releaseSaveJobData(void *data, void *user_data)
1171{
1172    CDBG("%s: E", __func__);
1173
1174    QCameraPostProcessor *pme = (QCameraPostProcessor *) user_data;
1175    if (NULL == pme) {
1176        ALOGE("%s: Invalid postproc handle", __func__);
1177        return;
1178    }
1179
1180    qcamera_jpeg_evt_payload_t *job_data = (qcamera_jpeg_evt_payload_t *) data;
1181    if (job_data == NULL) {
1182        ALOGE("%s: Invalid jpeg event data", __func__);
1183        return;
1184    }
1185
1186    // find job by jobId
1187    qcamera_jpeg_data_t *job = pme->findJpegJobByJobId(job_data->jobId);
1188
1189    if (NULL != job) {
1190        pme->releaseJpegJobData(job);
1191        free(job);
1192    } else {
1193        ALOGE("%s : Invalid jpeg job", __func__);
1194    }
1195
1196    CDBG("%s: X", __func__);
1197}
1198
1199/*===========================================================================
1200 * FUNCTION   : releaseRawData
1201 *
1202 * DESCRIPTION: function to release internal resources in store jobs
1203 *
1204 * PARAMETERS :
1205 *   @job     : ptr to save job struct
1206 *
1207 * RETURN     : None
1208 *
1209 *==========================================================================*/
1210void QCameraPostProcessor::releaseRawData(void *data, void *user_data)
1211{
1212    CDBG("%s: E", __func__);
1213
1214    QCameraPostProcessor *pme = (QCameraPostProcessor *) user_data;
1215    if (NULL == pme) {
1216        ALOGE("%s: Invalid postproc handle", __func__);
1217        return;
1218    }
1219    mm_camera_super_buf_t *super_buf = (mm_camera_super_buf_t *) data;
1220    pme->releaseSuperBuf(super_buf);
1221
1222    CDBG("%s: X", __func__);
1223}
1224
1225
1226/*===========================================================================
1227 * FUNCTION   : getColorfmtFromImgFmt
1228 *
1229 * DESCRIPTION: function to return jpeg color format based on its image format
1230 *
1231 * PARAMETERS :
1232 *   @img_fmt : image format
1233 *
1234 * RETURN     : jpeg color format that can be understandable by omx lib
1235 *==========================================================================*/
1236mm_jpeg_color_format QCameraPostProcessor::getColorfmtFromImgFmt(cam_format_t img_fmt)
1237{
1238    switch (img_fmt) {
1239    case CAM_FORMAT_YUV_420_NV21:
1240        return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
1241    case CAM_FORMAT_YUV_420_NV21_ADRENO:
1242        return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
1243    case CAM_FORMAT_YUV_420_NV12:
1244        return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2;
1245    case CAM_FORMAT_YUV_420_YV12:
1246        return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2;
1247    case CAM_FORMAT_YUV_422_NV61:
1248        return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1;
1249    case CAM_FORMAT_YUV_422_NV16:
1250        return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1;
1251    default:
1252        return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
1253    }
1254}
1255
1256/*===========================================================================
1257 * FUNCTION   : getJpegImgTypeFromImgFmt
1258 *
1259 * DESCRIPTION: function to return jpeg encode image type based on its image format
1260 *
1261 * PARAMETERS :
1262 *   @img_fmt : image format
1263 *
1264 * RETURN     : return jpeg source image format (YUV or Bitstream)
1265 *==========================================================================*/
1266mm_jpeg_format_t QCameraPostProcessor::getJpegImgTypeFromImgFmt(cam_format_t img_fmt)
1267{
1268    switch (img_fmt) {
1269    case CAM_FORMAT_YUV_420_NV21:
1270    case CAM_FORMAT_YUV_420_NV21_ADRENO:
1271    case CAM_FORMAT_YUV_420_NV12:
1272    case CAM_FORMAT_YUV_420_YV12:
1273    case CAM_FORMAT_YUV_422_NV61:
1274    case CAM_FORMAT_YUV_422_NV16:
1275        return MM_JPEG_FMT_YUV;
1276    default:
1277        return MM_JPEG_FMT_YUV;
1278    }
1279}
1280
1281/*===========================================================================
1282 * FUNCTION   : queryStreams
1283 *
1284 * DESCRIPTION: utility method for retrieving main, thumbnail and reprocess
1285 *              streams and frame from bundled super buffer
1286 *
1287 * PARAMETERS :
1288 *   @main    : ptr to main stream if present
1289 *   @thumb   : ptr to thumbnail stream if present
1290 *   @reproc  : ptr to reprocess stream if present
1291 *   @main_image : ptr to main image if present
1292 *   @thumb_image: ptr to thumbnail image if present
1293 *   @frame   : bundled super buffer
1294 *   @reproc_frame : bundled source frame buffer
1295 *
1296 * RETURN     : int32_t type of status
1297 *              NO_ERROR  -- success
1298 *              none-zero failure code
1299 *==========================================================================*/
1300int32_t QCameraPostProcessor::queryStreams(QCameraStream **main,
1301        QCameraStream **thumb,
1302        QCameraStream **reproc,
1303        mm_camera_buf_def_t **main_image,
1304        mm_camera_buf_def_t **thumb_image,
1305        mm_camera_super_buf_t *frame,
1306        mm_camera_super_buf_t *reproc_frame)
1307{
1308    if (NULL == frame) {
1309        return NO_INIT;
1310    }
1311
1312    QCameraChannel *pChannel = m_parent->getChannelByHandle(frame->ch_id);
1313    // check reprocess channel if not found
1314    if (pChannel == NULL) {
1315        if (m_pReprocChannel != NULL &&
1316            m_pReprocChannel->getMyHandle() == frame->ch_id) {
1317            pChannel = m_pReprocChannel;
1318        }
1319    }
1320    if (pChannel == NULL) {
1321        ALOGD("%s: No corresponding channel (ch_id = %d) exist, return here",
1322              __func__, frame->ch_id);
1323        return BAD_VALUE;
1324    }
1325
1326    // Use snapshot stream to create thumbnail if snapshot and preview
1327    // flip settings doesn't match in ZSL mode.
1328    bool thumb_stream_needed = !m_parent->isZSLMode() ||
1329        (m_parent->mParameters.getFlipMode(CAM_STREAM_TYPE_SNAPSHOT) ==
1330         m_parent->mParameters.getFlipMode(CAM_STREAM_TYPE_PREVIEW));
1331
1332    *main = *thumb = *reproc = NULL;
1333    *main_image = *thumb_image = NULL;
1334    // find snapshot frame and thumnail frame
1335    for (int i = 0; i < frame->num_bufs; i++) {
1336        QCameraStream *pStream =
1337                pChannel->getStreamByHandle(frame->bufs[i]->stream_id);
1338        if (pStream != NULL) {
1339            if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
1340                pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT)) {
1341                *main= pStream;
1342                *main_image = frame->bufs[i];
1343            } else if (thumb_stream_needed &&
1344                       (pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
1345                        pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) ||
1346                        pStream->isOrignalTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
1347                        pStream->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW))) {
1348                *thumb = pStream;
1349                *thumb_image = frame->bufs[i];
1350            }
1351            if (pStream->isTypeOf(CAM_STREAM_TYPE_OFFLINE_PROC) ) {
1352                *reproc = pStream;
1353            }
1354        }
1355    }
1356
1357    if (thumb_stream_needed && *thumb_image == NULL && reproc_frame != NULL) {
1358        QCameraChannel *pSrcReprocChannel = NULL;
1359        pSrcReprocChannel = m_parent->getChannelByHandle(reproc_frame->ch_id);
1360        if (pSrcReprocChannel != NULL) {
1361            // find thumbnail frame
1362            for (int i = 0; i < reproc_frame->num_bufs; i++) {
1363                QCameraStream *pStream =
1364                        pSrcReprocChannel->getStreamByHandle(
1365                                reproc_frame->bufs[i]->stream_id);
1366                if (pStream != NULL) {
1367                    if (pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
1368                        pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW)) {
1369                        *thumb = pStream;
1370                        *thumb_image = reproc_frame->bufs[i];
1371                    }
1372                }
1373            }
1374        }
1375    }
1376
1377    if (m_parent->mParameters.generateThumbFromMain()) {
1378        *thumb = NULL;
1379        *thumb_image = NULL;
1380    }
1381
1382    return NO_ERROR;
1383}
1384
1385/*===========================================================================
1386* FUNCTION   : syncStreamParams
1387*
1388* DESCRIPTION: Query the runtime parameters of all streams included
1389*              in the main and reprocessed frames
1390*
1391* PARAMETERS :
1392*   @frame : Main image super buffer
1393*   @reproc_frame : Image supper buffer that got processed
1394*
1395* RETURN     : int32_t type of status
1396*              NO_ERROR  -- success
1397*              none-zero failure code
1398*==========================================================================*/
1399int32_t QCameraPostProcessor::syncStreamParams(mm_camera_super_buf_t *frame,
1400        mm_camera_super_buf_t *reproc_frame)
1401{
1402    QCameraStream *reproc_stream = NULL;
1403    QCameraStream *main_stream = NULL;
1404    QCameraStream *thumb_stream = NULL;
1405    mm_camera_buf_def_t *main_frame = NULL;
1406    mm_camera_buf_def_t *thumb_frame = NULL;
1407    int32_t ret = NO_ERROR;
1408
1409    ret = queryStreams(&main_stream,
1410            &thumb_stream,
1411            &reproc_stream,
1412            &main_frame,
1413            &thumb_frame,
1414            frame,
1415            reproc_frame);
1416    if (NO_ERROR != ret) {
1417        ALOGE("%s : Camera streams query from input frames failed %d",
1418                __func__,
1419                ret);
1420        return ret;
1421    }
1422
1423    if (NULL != main_stream) {
1424        ret = main_stream->syncRuntimeParams();
1425        if (NO_ERROR != ret) {
1426            ALOGE("%s : Syncing of main stream runtime parameters failed %d",
1427                    __func__,
1428                    ret);
1429            return ret;
1430        }
1431    }
1432
1433    if (NULL != thumb_stream) {
1434        ret = thumb_stream->syncRuntimeParams();
1435        if (NO_ERROR != ret) {
1436            ALOGE("%s : Syncing of thumb stream runtime parameters failed %d",
1437                    __func__,
1438                    ret);
1439            return ret;
1440        }
1441    }
1442
1443    if ((NULL != reproc_stream) && (reproc_stream != main_stream)) {
1444        ret = reproc_stream->syncRuntimeParams();
1445        if (NO_ERROR != ret) {
1446            ALOGE("%s : Syncing of reproc stream runtime parameters failed %d",
1447                    __func__,
1448                    ret);
1449            return ret;
1450        }
1451    }
1452
1453    return ret;
1454}
1455
1456/*===========================================================================
1457 * FUNCTION   : encodeData
1458 *
1459 * DESCRIPTION: function to prepare encoding job information and send to
1460 *              mm-jpeg-interface to do the encoding job
1461 *
1462 * PARAMETERS :
1463 *   @jpeg_job_data : ptr to a struct saving job related information
1464 *   @needNewSess   : flag to indicate if a new jpeg encoding session need
1465 *                    to be created. After creation, this flag will be toggled
1466 *
1467 * RETURN     : int32_t type of status
1468 *              NO_ERROR  -- success
1469 *              none-zero failure code
1470 *==========================================================================*/
1471int32_t QCameraPostProcessor::encodeData(qcamera_jpeg_data_t *jpeg_job_data,
1472                                         uint8_t &needNewSess)
1473{
1474    CDBG("%s : E", __func__);
1475    int32_t ret = NO_ERROR;
1476    mm_jpeg_job_t jpg_job;
1477    uint32_t jobId = 0;
1478    QCameraStream *reproc_stream = NULL;
1479    QCameraStream *main_stream = NULL;
1480    mm_camera_buf_def_t *main_frame = NULL;
1481    QCameraStream *thumb_stream = NULL;
1482    mm_camera_buf_def_t *thumb_frame = NULL;
1483    mm_camera_super_buf_t *recvd_frame = jpeg_job_data->src_frame;
1484    cam_rect_t crop;
1485    cam_stream_parm_buffer_t param;
1486    cam_stream_img_prop_t imgProp;
1487
1488    // find channel
1489    QCameraChannel *pChannel = m_parent->getChannelByHandle(recvd_frame->ch_id);
1490    // check reprocess channel if not found
1491    if (pChannel == NULL) {
1492        if (m_pReprocChannel != NULL &&
1493            m_pReprocChannel->getMyHandle() == recvd_frame->ch_id) {
1494            pChannel = m_pReprocChannel;
1495        }
1496    }
1497
1498    if (pChannel == NULL) {
1499        ALOGE("%s:%d] No corresponding channel (ch_id = %d) exist, return here",
1500              __func__, __LINE__, recvd_frame->ch_id);
1501        return BAD_VALUE;
1502    }
1503
1504    const int jpeg_rotation = m_parent->getJpegRotation();
1505
1506    ret = queryStreams(&main_stream,
1507            &thumb_stream,
1508            &reproc_stream,
1509            &main_frame,
1510            &thumb_frame,
1511            recvd_frame,
1512            jpeg_job_data->src_reproc_frame);
1513    if (NO_ERROR != ret) {
1514        return ret;
1515    }
1516
1517    if(NULL == main_frame){
1518       ALOGE("%s : Main frame is NULL", __func__);
1519       return BAD_VALUE;
1520    }
1521
1522    if(NULL == thumb_frame){
1523       CDBG("%s : Thumbnail frame does not exist", __func__);
1524    }
1525
1526    QCameraMemory *memObj = (QCameraMemory *)main_frame->mem_info;
1527    if (NULL == memObj) {
1528        ALOGE("%s : Memeory Obj of main frame is NULL", __func__);
1529        return NO_MEMORY;
1530    }
1531
1532    // dump snapshot frame if enabled
1533    m_parent->dumpFrameToFile(main_stream, main_frame, QCAMERA_DUMP_FRM_SNAPSHOT);
1534
1535    // send upperlayer callback for raw image
1536    camera_memory_t *mem = memObj->getMemory(main_frame->buf_idx, false);
1537    if (NULL != m_parent->mDataCb &&
1538        m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE) > 0) {
1539        qcamera_callback_argm_t cbArg;
1540        memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
1541        cbArg.cb_type = QCAMERA_DATA_CALLBACK;
1542        cbArg.msg_type = CAMERA_MSG_RAW_IMAGE;
1543        cbArg.data = mem;
1544        cbArg.index = 1;
1545        m_parent->m_cbNotifier.notifyCallback(cbArg);
1546    }
1547    if (NULL != m_parent->mNotifyCb &&
1548        m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE_NOTIFY) > 0) {
1549        qcamera_callback_argm_t cbArg;
1550        memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
1551        cbArg.cb_type = QCAMERA_NOTIFY_CALLBACK;
1552        cbArg.msg_type = CAMERA_MSG_RAW_IMAGE_NOTIFY;
1553        cbArg.ext1 = 0;
1554        cbArg.ext2 = 0;
1555        m_parent->m_cbNotifier.notifyCallback(cbArg);
1556    }
1557
1558    if (thumb_frame != NULL) {
1559        // dump thumbnail frame if enabled
1560        m_parent->dumpFrameToFile(thumb_stream, thumb_frame, QCAMERA_DUMP_FRM_THUMBNAIL);
1561    }
1562
1563    if (mJpegClientHandle <= 0) {
1564        ALOGE("%s: Error: bug here, mJpegClientHandle is 0", __func__);
1565        return UNKNOWN_ERROR;
1566    }
1567
1568    if (needNewSess) {
1569        // create jpeg encoding session
1570        mm_jpeg_encode_params_t encodeParam;
1571        memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t));
1572        getJpegEncodingConfig(encodeParam, main_stream, thumb_stream);
1573        CDBG_HIGH("[KPI Perf] %s : call jpeg create_session", __func__);
1574        ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId);
1575        if (ret != NO_ERROR) {
1576            ALOGE("%s: error creating a new jpeg encoding session", __func__);
1577            return ret;
1578        }
1579        needNewSess = FALSE;
1580    }
1581    // Fill in new job
1582    memset(&jpg_job, 0, sizeof(mm_jpeg_job_t));
1583    jpg_job.job_type = JPEG_JOB_TYPE_ENCODE;
1584    jpg_job.encode_job.session_id = mJpegSessionId;
1585    jpg_job.encode_job.src_index = main_frame->buf_idx;
1586    jpg_job.encode_job.dst_index = 0;
1587
1588    if (mJpegMemOpt) {
1589        jpg_job.encode_job.dst_index = jpg_job.encode_job.src_index;
1590    } else if (mUseJpegBurst) {
1591        jpg_job.encode_job.dst_index = -1;
1592    }
1593
1594    cam_dimension_t src_dim;
1595    memset(&src_dim, 0, sizeof(cam_dimension_t));
1596    main_stream->getFrameDimension(src_dim);
1597
1598    bool hdr_output_crop = m_parent->mParameters.isHDROutputCropEnabled();
1599    bool img_feature_enabled =
1600      m_parent->mParameters.isUbiFocusEnabled() ||
1601      m_parent->mParameters.isChromaFlashEnabled() ||
1602      m_parent->mParameters.isOptiZoomEnabled();
1603
1604    CDBG_HIGH("%s:%d] Crop needed %d", __func__, __LINE__, img_feature_enabled);
1605    crop.left = 0;
1606    crop.top = 0;
1607    crop.height = src_dim.height;
1608    crop.width = src_dim.width;
1609
1610    param = main_stream->getOutputCrop();
1611    for (int i = 0; i < param.outputCrop.num_of_streams; i++) {
1612       if (param.outputCrop.crop_info[i].stream_id
1613           == main_stream->getMyServerID()) {
1614               crop = param.outputCrop.crop_info[i].crop;
1615               main_stream->setCropInfo(crop);
1616       }
1617    }
1618    if (img_feature_enabled) {
1619        memset(&param, 0, sizeof(cam_stream_parm_buffer_t));
1620
1621        param = main_stream->getImgProp();
1622        imgProp = param.imgProp;
1623        main_stream->setCropInfo(imgProp.crop);
1624        crop = imgProp.crop;
1625        thumb_stream = NULL; /* use thumbnail from main image */
1626        if (imgProp.is_raw_image) {
1627           camera_memory_t *mem = memObj->getMemory(
1628               main_frame->buf_idx, false);
1629           ALOGE("%s:%d] Process raw image %p %d", __func__, __LINE__,
1630               mem, imgProp.size);
1631           /* dump image */
1632           if (mem && mem->data) {
1633               CAM_DUMP_TO_FILE("/data/local/ubifocus", "DepthMapImage",
1634                                -1, "y",
1635                                (uint8_t *)mem->data,
1636                                imgProp.size);
1637           }
1638           return NO_ERROR;
1639        }
1640    }
1641
1642    cam_dimension_t dst_dim;
1643
1644    if (hdr_output_crop && crop.height) {
1645        dst_dim.height = crop.height;
1646    } else {
1647        dst_dim.height = src_dim.height;
1648    }
1649    if (hdr_output_crop && crop.width) {
1650        dst_dim.width = crop.width;
1651    } else {
1652        dst_dim.width = src_dim.width;
1653    }
1654
1655    // main dim
1656    jpg_job.encode_job.main_dim.src_dim = src_dim;
1657    jpg_job.encode_job.main_dim.dst_dim = dst_dim;
1658    jpg_job.encode_job.main_dim.crop = crop;
1659
1660    // get exif data
1661    QCameraExif *pJpegExifObj = m_parent->getExifData();
1662    jpeg_job_data->pJpegExifObj = pJpegExifObj;
1663    if (pJpegExifObj != NULL) {
1664        jpg_job.encode_job.exif_info.exif_data = pJpegExifObj->getEntries();
1665        jpg_job.encode_job.exif_info.numOfEntries =
1666            pJpegExifObj->getNumOfEntries();
1667    }
1668
1669    // set rotation only when no online rotation or offline pp rotation is done before
1670    if (!m_parent->needRotationReprocess()) {
1671        jpg_job.encode_job.rotation = jpeg_rotation;
1672    }
1673    CDBG_HIGH("%s: jpeg rotation is set to %d", __func__, jpg_job.encode_job.rotation);
1674
1675    // thumbnail dim
1676    if (m_bThumbnailNeeded == TRUE) {
1677        m_parent->getThumbnailSize(jpg_job.encode_job.thumb_dim.dst_dim);
1678
1679        if (thumb_stream == NULL) {
1680            // need jpeg thumbnail, but no postview/preview stream exists
1681            // we use the main stream/frame to encode thumbnail
1682            thumb_stream = main_stream;
1683            thumb_frame = main_frame;
1684            if (m_parent->needRotationReprocess() &&
1685                ((90 == jpeg_rotation) || (270 == jpeg_rotation))) {
1686                // swap thumbnail dimensions
1687                cam_dimension_t tmp_dim = jpg_job.encode_job.thumb_dim.dst_dim;
1688                jpg_job.encode_job.thumb_dim.dst_dim.width = tmp_dim.height;
1689                jpg_job.encode_job.thumb_dim.dst_dim.height = tmp_dim.width;
1690            }
1691        }
1692
1693        memset(&src_dim, 0, sizeof(cam_dimension_t));
1694        thumb_stream->getFrameDimension(src_dim);
1695        jpg_job.encode_job.thumb_dim.src_dim = src_dim;
1696
1697        // crop is the same if frame is the same
1698        if (thumb_frame != main_frame) {
1699            crop.left = 0;
1700            crop.top = 0;
1701            crop.height = src_dim.height;
1702            crop.width = src_dim.width;
1703
1704            param = thumb_stream->getOutputCrop();
1705            for (int i = 0; i < param.outputCrop.num_of_streams; i++) {
1706               if (param.outputCrop.crop_info[i].stream_id
1707                   == thumb_stream->getMyServerID()) {
1708                       crop = param.outputCrop.crop_info[i].crop;
1709                       thumb_stream->setCropInfo(crop);
1710               }
1711           }
1712        }
1713
1714        jpg_job.encode_job.thumb_dim.crop = crop;
1715        jpg_job.encode_job.thumb_index = thumb_frame->buf_idx;
1716        CDBG_HIGH("%s, thumbnail src w/h (%dx%d), dst w/h (%dx%d)", __func__,
1717            jpg_job.encode_job.thumb_dim.src_dim.width,
1718            jpg_job.encode_job.thumb_dim.src_dim.height,
1719            jpg_job.encode_job.thumb_dim.dst_dim.width,
1720            jpg_job.encode_job.thumb_dim.dst_dim.height);
1721    }
1722
1723    if (jpeg_job_data->metadata != NULL) {
1724        // fill in meta data frame ptr
1725        jpg_job.encode_job.p_metadata = jpeg_job_data->metadata;
1726    }
1727
1728    jpg_job.encode_job.hal_version = CAM_HAL_V1;
1729    jpg_job.encode_job.cam_exif_params = m_parent->mExifParams;
1730
1731    /* Init the QTable */
1732    for (int i = 0; i < QTABLE_MAX; i++) {
1733        jpg_job.encode_job.qtable_set[i] = 0;
1734    }
1735
1736    CDBG_HIGH("[KPI Perf] %s : PROFILE_JPEG_JOB_START", __func__);
1737    ret = mJpegHandle.start_job(&jpg_job, &jobId);
1738    if (ret == NO_ERROR) {
1739        // remember job info
1740        jpeg_job_data->jobId = jobId;
1741    }
1742
1743    return ret;
1744}
1745
1746/*===========================================================================
1747 * FUNCTION   : processRawImageImpl
1748 *
1749 * DESCRIPTION: function to send raw image to upper layer
1750 *
1751 * PARAMETERS :
1752 *   @recvd_frame   : frame to be encoded
1753 *
1754 * RETURN     : int32_t type of status
1755 *              NO_ERROR  -- success
1756 *              none-zero failure code
1757 *==========================================================================*/
1758int32_t QCameraPostProcessor::processRawImageImpl(mm_camera_super_buf_t *recvd_frame)
1759{
1760    int32_t rc = NO_ERROR;
1761
1762    QCameraChannel *pChannel = m_parent->getChannelByHandle(recvd_frame->ch_id);
1763    QCameraStream *pStream = NULL;
1764    mm_camera_buf_def_t *frame = NULL;
1765    // check reprocess channel if not found
1766    if (pChannel == NULL) {
1767        if (m_pReprocChannel != NULL &&
1768            m_pReprocChannel->getMyHandle() == recvd_frame->ch_id) {
1769            pChannel = m_pReprocChannel;
1770        }
1771    }
1772    if (pChannel == NULL) {
1773        ALOGE("%s:%d] No corresponding channel (ch_id = %d) exist, return here",
1774              __func__, __LINE__, recvd_frame->ch_id);
1775        return BAD_VALUE;
1776    }
1777
1778    // find snapshot frame
1779    for (int i = 0; i < recvd_frame->num_bufs; i++) {
1780        QCameraStream *pCurStream =
1781            pChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id);
1782        if (pCurStream != NULL) {
1783            if (pCurStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
1784                pCurStream->isTypeOf(CAM_STREAM_TYPE_RAW) ||
1785                pCurStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
1786                pCurStream->isOrignalTypeOf(CAM_STREAM_TYPE_RAW)) {
1787                pStream = pCurStream;
1788                frame = recvd_frame->bufs[i];
1789                break;
1790            }
1791        }
1792    }
1793
1794    if ( NULL == frame ) {
1795        ALOGE("%s: No valid raw buffer", __func__);
1796        return BAD_VALUE;
1797    }
1798
1799    QCameraMemory *rawMemObj = (QCameraMemory *)frame->mem_info;
1800    bool zslChannelUsed = m_parent->isZSLMode() &&
1801            ( pChannel != m_pReprocChannel );
1802    camera_memory_t *raw_mem = NULL;
1803
1804    if (rawMemObj != NULL) {
1805        if (zslChannelUsed) {
1806            raw_mem = rawMemObj->getMemory(frame->buf_idx, false);
1807        } else {
1808            raw_mem = m_parent->mGetMemory(-1,
1809                                           frame->frame_len,
1810                                           1,
1811                                           m_parent->mCallbackCookie);
1812            if (NULL == raw_mem) {
1813                ALOGE("%s : Not enough memory for RAW cb ", __func__);
1814                return NO_MEMORY;
1815            }
1816            memcpy(raw_mem->data, frame->buffer, frame->frame_len);
1817        }
1818    }
1819
1820    if (NULL != rawMemObj && NULL != raw_mem) {
1821        // dump frame into file
1822        if (frame->stream_type == CAM_STREAM_TYPE_SNAPSHOT ||
1823            pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT)) {
1824            // for YUV422 NV16 case
1825            m_parent->dumpFrameToFile(pStream, frame, QCAMERA_DUMP_FRM_SNAPSHOT);
1826        } else {
1827            m_parent->dumpFrameToFile(pStream, frame, QCAMERA_DUMP_FRM_RAW);
1828        }
1829
1830        // send data callback / notify for RAW_IMAGE
1831        if (NULL != m_parent->mDataCb &&
1832            m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE) > 0) {
1833            qcamera_callback_argm_t cbArg;
1834            memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
1835            cbArg.cb_type = QCAMERA_DATA_CALLBACK;
1836            cbArg.msg_type = CAMERA_MSG_RAW_IMAGE;
1837            cbArg.data = raw_mem;
1838            cbArg.index = 0;
1839            m_parent->m_cbNotifier.notifyCallback(cbArg);
1840        }
1841        if (NULL != m_parent->mNotifyCb &&
1842            m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE_NOTIFY) > 0) {
1843            qcamera_callback_argm_t cbArg;
1844            memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
1845            cbArg.cb_type = QCAMERA_NOTIFY_CALLBACK;
1846            cbArg.msg_type = CAMERA_MSG_RAW_IMAGE_NOTIFY;
1847            cbArg.ext1 = 0;
1848            cbArg.ext2 = 0;
1849            m_parent->m_cbNotifier.notifyCallback(cbArg);
1850        }
1851
1852        if ((m_parent->mDataCb != NULL) &&
1853            m_parent->msgTypeEnabledWithLock(CAMERA_MSG_COMPRESSED_IMAGE) > 0) {
1854            qcamera_release_data_t release_data;
1855            memset(&release_data, 0, sizeof(qcamera_release_data_t));
1856            if ( zslChannelUsed ) {
1857                release_data.frame = recvd_frame;
1858            } else {
1859                release_data.data = raw_mem;
1860            }
1861            rc = sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE,
1862                                raw_mem,
1863                                0,
1864                                NULL,
1865                                &release_data);
1866        } else {
1867            raw_mem->release(raw_mem);
1868        }
1869    } else {
1870        ALOGE("%s: Cannot get raw mem", __func__);
1871        rc = UNKNOWN_ERROR;
1872    }
1873
1874    return rc;
1875}
1876
1877/*===========================================================================
1878 * FUNCTION   : dataSaveRoutine
1879 *
1880 * DESCRIPTION: data saving routine
1881 *
1882 * PARAMETERS :
1883 *   @data    : user data ptr (QCameraPostProcessor)
1884 *
1885 * RETURN     : None
1886 *==========================================================================*/
1887void *QCameraPostProcessor::dataSaveRoutine(void *data)
1888{
1889    int running = 1;
1890    int ret;
1891    uint8_t is_active = FALSE;
1892    QCameraPostProcessor *pme = (QCameraPostProcessor *)data;
1893    QCameraCmdThread *cmdThread = &pme->m_saveProcTh;
1894    char saveName[PROPERTY_VALUE_MAX];
1895
1896    CDBG_HIGH("%s: E", __func__);
1897    do {
1898        do {
1899            ret = cam_sem_wait(&cmdThread->cmd_sem);
1900            if (ret != 0 && errno != EINVAL) {
1901                ALOGE("%s: cam_sem_wait error (%s)",
1902                           __func__, strerror(errno));
1903                return NULL;
1904            }
1905        } while (ret != 0);
1906
1907        // we got notified about new cmd avail in cmd queue
1908        camera_cmd_type_t cmd = cmdThread->getCmd();
1909        switch (cmd) {
1910        case CAMERA_CMD_TYPE_START_DATA_PROC:
1911            CDBG_HIGH("%s: start data proc", __func__);
1912            is_active = TRUE;
1913            pme->m_inputSaveQ.init();
1914            break;
1915        case CAMERA_CMD_TYPE_STOP_DATA_PROC:
1916            {
1917                CDBG_HIGH("%s: stop data proc", __func__);
1918                is_active = FALSE;
1919
1920                // flush input save Queue
1921                pme->m_inputSaveQ.flush();
1922
1923                // signal cmd is completed
1924                cam_sem_post(&cmdThread->sync_sem);
1925            }
1926            break;
1927        case CAMERA_CMD_TYPE_DO_NEXT_JOB:
1928            {
1929                CDBG_HIGH("%s: Do next job, active is %d", __func__, is_active);
1930
1931                qcamera_jpeg_evt_payload_t *job_data = (qcamera_jpeg_evt_payload_t *) pme->m_inputSaveQ.dequeue();
1932                if (job_data == NULL) {
1933                    ALOGE("%s: Invalid jpeg event data", __func__);
1934                    continue;
1935                }
1936
1937                pme->m_ongoingJpegQ.flushNodes(matchJobId, (void*)&job_data->jobId);
1938
1939                CDBG_HIGH("[KPI Perf] %s : jpeg job %d", __func__, job_data->jobId);
1940
1941                if (is_active == TRUE) {
1942                    memset(saveName, '\0', sizeof(saveName));
1943                    snprintf(saveName,
1944                             sizeof(saveName),
1945                             QCameraPostProcessor::STORE_LOCATION,
1946                             pme->mSaveFrmCnt);
1947
1948                    int file_fd = open(saveName, O_RDWR | O_CREAT, 0655);
1949                    if (file_fd > 0) {
1950                        size_t written_len = write(file_fd,
1951                                                job_data->out_data.buf_vaddr,
1952                                                job_data->out_data.buf_filled_len);
1953                        if ( job_data->out_data.buf_filled_len != written_len ) {
1954                            ALOGE("%s: Failed save complete data %d bytes written instead of %d bytes!",
1955                                  __func__,
1956                                  written_len,
1957                                  job_data->out_data.buf_filled_len);
1958                        } else {
1959                            CDBG_HIGH("%s: written number of bytes %d\n", __func__, written_len);
1960                        }
1961
1962                        close(file_fd);
1963                    } else {
1964                        ALOGE("%s: fail t open file for saving", __func__);
1965                    }
1966                    pme->mSaveFrmCnt++;
1967
1968                    camera_memory_t* jpeg_mem = pme->m_parent->mGetMemory(-1,
1969                                                         strlen(saveName),
1970                                                         1,
1971                                                         pme->m_parent->mCallbackCookie);
1972                    if (NULL == jpeg_mem) {
1973                        ret = NO_MEMORY;
1974                        ALOGE("%s : getMemory for jpeg, ret = NO_MEMORY", __func__);
1975                        goto end;
1976                    }
1977                    memcpy(jpeg_mem->data, saveName, strlen(saveName));
1978
1979                    CDBG_HIGH("%s : Calling upperlayer callback to store JPEG image", __func__);
1980                    qcamera_release_data_t release_data;
1981                    memset(&release_data, 0, sizeof(qcamera_release_data_t));
1982                    release_data.data = jpeg_mem;
1983                    release_data.unlinkFile = true;
1984                    CDBG_HIGH("[KPI Perf] %s: PROFILE_JPEG_CB ",__func__);
1985                    ret = pme->sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE,
1986                                        jpeg_mem,
1987                                        0,
1988                                        NULL,
1989                                        &release_data);
1990                }
1991
1992end:
1993                free(job_data);
1994            }
1995            break;
1996        case CAMERA_CMD_TYPE_EXIT:
1997            CDBG_HIGH("%s : save thread exit", __func__);
1998            running = 0;
1999            break;
2000        default:
2001            break;
2002        }
2003    } while (running);
2004    CDBG_HIGH("%s: X", __func__);
2005    return NULL;
2006}
2007
2008/*===========================================================================
2009 * FUNCTION   : dataProcessRoutine
2010 *
2011 * DESCRIPTION: data process routine that handles input data either from input
2012 *              Jpeg Queue to do jpeg encoding, or from input PP Queue to do
2013 *              reprocess.
2014 *
2015 * PARAMETERS :
2016 *   @data    : user data ptr (QCameraPostProcessor)
2017 *
2018 * RETURN     : None
2019 *==========================================================================*/
2020void *QCameraPostProcessor::dataProcessRoutine(void *data)
2021{
2022    int running = 1;
2023    int ret;
2024    uint8_t is_active = FALSE;
2025    QCameraPostProcessor *pme = (QCameraPostProcessor *)data;
2026    QCameraCmdThread *cmdThread = &pme->m_dataProcTh;
2027
2028    CDBG_HIGH("%s: E", __func__);
2029    do {
2030        do {
2031            ret = cam_sem_wait(&cmdThread->cmd_sem);
2032            if (ret != 0 && errno != EINVAL) {
2033                ALOGE("%s: cam_sem_wait error (%s)",
2034                           __func__, strerror(errno));
2035                return NULL;
2036            }
2037        } while (ret != 0);
2038
2039        // we got notified about new cmd avail in cmd queue
2040        camera_cmd_type_t cmd = cmdThread->getCmd();
2041        switch (cmd) {
2042        case CAMERA_CMD_TYPE_START_DATA_PROC:
2043            CDBG_HIGH("%s: start data proc", __func__);
2044            is_active = TRUE;
2045
2046            pme->m_ongoingPPQ.init();
2047            pme->m_inputJpegQ.init();
2048            pme->m_inputPPQ.init();
2049            pme->m_inputRawQ.init();
2050
2051            pme->m_saveProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC,
2052                                      FALSE,
2053                                      FALSE);
2054
2055            // signal cmd is completed
2056            cam_sem_post(&cmdThread->sync_sem);
2057
2058            break;
2059        case CAMERA_CMD_TYPE_STOP_DATA_PROC:
2060            {
2061                CDBG_HIGH("%s: stop data proc", __func__);
2062                is_active = FALSE;
2063
2064                pme->m_saveProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC,
2065                                           TRUE,
2066                                           TRUE);
2067                // cancel all ongoing jpeg jobs
2068                qcamera_jpeg_data_t *jpeg_job =
2069                    (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
2070                while (jpeg_job != NULL) {
2071                    pme->mJpegHandle.abort_job(jpeg_job->jobId);
2072
2073                    pme->releaseJpegJobData(jpeg_job);
2074                    free(jpeg_job);
2075
2076                    jpeg_job = (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
2077                }
2078
2079                // destroy jpeg encoding session
2080                if ( 0 < pme->mJpegSessionId ) {
2081                    pme->mJpegHandle.destroy_session(pme->mJpegSessionId);
2082                    pme->mJpegSessionId = 0;
2083                }
2084
2085                // free jpeg out buf and exif obj
2086                FREE_JPEG_OUTPUT_BUFFER(pme->m_pJpegOutputMem,
2087                    pme->m_JpegOutputMemCount);
2088
2089                if (pme->m_pJpegExifObj != NULL) {
2090                    delete pme->m_pJpegExifObj;
2091                    pme->m_pJpegExifObj = NULL;
2092                }
2093
2094                // stop reproc channel if exists
2095                if (pme->m_pReprocChannel != NULL) {
2096                    pme->m_pReprocChannel->stop();
2097                    delete pme->m_pReprocChannel;
2098                    pme->m_pReprocChannel = NULL;
2099                }
2100
2101                // flush ongoing postproc Queue
2102                pme->m_ongoingPPQ.flush();
2103
2104                // flush input jpeg Queue
2105                pme->m_inputJpegQ.flush();
2106
2107                // flush input Postproc Queue
2108                pme->m_inputPPQ.flush();
2109
2110                // flush input raw Queue
2111                pme->m_inputRawQ.flush();
2112
2113                // signal cmd is completed
2114                cam_sem_post(&cmdThread->sync_sem);
2115
2116                pme->mNewJpegSessionNeeded = true;
2117            }
2118            break;
2119        case CAMERA_CMD_TYPE_DO_NEXT_JOB:
2120            {
2121                CDBG_HIGH("%s: Do next job, active is %d", __func__, is_active);
2122                if (is_active == TRUE) {
2123                    qcamera_jpeg_data_t *jpeg_job =
2124                        (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
2125
2126                    if (NULL != jpeg_job) {
2127                        // To avoid any race conditions,
2128                        // sync any stream specific parameters here.
2129                        pme->syncStreamParams(jpeg_job->src_frame, NULL);
2130
2131                        // add into ongoing jpeg job Q
2132                        pme->m_ongoingJpegQ.enqueue((void *)jpeg_job);
2133                        ret = pme->encodeData(jpeg_job,
2134                                  pme->mNewJpegSessionNeeded);
2135                        if (NO_ERROR != ret) {
2136                            // dequeue the last one
2137                            pme->m_ongoingJpegQ.dequeue(false);
2138                            pme->releaseJpegJobData(jpeg_job);
2139                            free(jpeg_job);
2140                            pme->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
2141                        }
2142                    }
2143
2144
2145                    // process raw data if any
2146                    mm_camera_super_buf_t *super_buf =
2147                        (mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue();
2148
2149                    if (NULL != super_buf) {
2150                        //play shutter sound
2151                        pme->m_parent->playShutter();
2152                        ret = pme->processRawImageImpl(super_buf);
2153                        if (NO_ERROR != ret) {
2154                            pme->releaseSuperBuf(super_buf);
2155                            free(super_buf);
2156                            pme->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
2157                        }
2158                    }
2159
2160                    mm_camera_super_buf_t *pp_frame =
2161                        (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue();
2162                    if (NULL != pp_frame) {
2163                        qcamera_pp_data_t *pp_job =
2164                            (qcamera_pp_data_t *)malloc(sizeof(qcamera_pp_data_t));
2165                        if (pp_job != NULL) {
2166                            pme->syncStreamParams(pp_frame, NULL);
2167                            memset(pp_job, 0, sizeof(qcamera_pp_data_t));
2168                            if (pme->m_pReprocChannel != NULL) {
2169                                // add into ongoing PP job Q
2170                                pp_job->src_frame = pp_frame;
2171                                ret = pme->reprocess(pp_job);
2172                                if (NO_ERROR == ret) {
2173                                    pme->stopCapture();
2174                                }
2175                            } else {
2176                                ALOGE("%s: Reprocess channel is NULL", __func__);
2177                                ret = -1;
2178                            }
2179                        } else {
2180                            ALOGE("%s: no mem for qcamera_pp_data_t", __func__);
2181                            ret = -1;
2182                        }
2183
2184                        if (0 != ret) {
2185                            // free pp_job
2186                            if (pp_job != NULL) {
2187                                free(pp_job);
2188                            }
2189                            // free frame
2190                            if (pp_frame != NULL) {
2191                                pme->releaseSuperBuf(pp_frame);
2192                                free(pp_frame);
2193                            }
2194                            // send error notify
2195                            pme->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
2196                        }
2197                    }
2198                } else {
2199                    // not active, simply return buf and do no op
2200                    qcamera_jpeg_data_t *jpeg_data =
2201                        (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
2202                    if (NULL != jpeg_data) {
2203                        pme->releaseJpegJobData(jpeg_data);
2204                        free(jpeg_data);
2205                    }
2206                    mm_camera_super_buf_t *super_buf =
2207                        (mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue();
2208                    if (NULL != super_buf) {
2209                        pme->releaseSuperBuf(super_buf);
2210                        free(super_buf);
2211                    }
2212                    super_buf = (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue();
2213                    if (NULL != super_buf) {
2214                        pme->releaseSuperBuf(super_buf);
2215                        free(super_buf);
2216                    }
2217                }
2218            }
2219            break;
2220        case CAMERA_CMD_TYPE_EXIT:
2221            running = 0;
2222            break;
2223        default:
2224            break;
2225        }
2226    } while (running);
2227    CDBG_HIGH("%s: X", __func__);
2228    return NULL;
2229}
2230
2231/*===========================================================================
2232 * FUNCTION   : reprocess
2233 *
2234 * DESCRIPTION: Trigger reprocessing
2235 *
2236 * PARAMETERS :
2237 *   @pp_job  : Postproc job
2238 *
2239 * RETURN     : int32_t type of status
2240 *              NO_ERROR  -- success
2241 *              none-zero failure code
2242 *==========================================================================*/
2243int32_t QCameraPostProcessor::reprocess(qcamera_pp_data_t *pp_job)
2244{
2245    int rc = NO_ERROR;
2246
2247    if (NULL == pp_job) {
2248        return BAD_VALUE;
2249    }
2250
2251    if (m_parent->isRegularCapture()) {
2252       if ((NULL != pp_job->src_frame) &&
2253           (0 < pp_job->src_frame->num_bufs)) {
2254           mm_camera_buf_def_t *bufs = NULL;
2255           uint8_t num_bufs = -1;
2256           num_bufs = pp_job->src_frame->num_bufs;
2257           bufs = new mm_camera_buf_def_t[num_bufs];
2258           if (NULL == bufs) {
2259               ALOGE("%s:Unable to allocate cached buffers",
2260                     __func__);
2261               return NO_MEMORY;
2262           }
2263
2264           for (int i = 0; i < num_bufs; i++) {
2265               bufs[i] = *pp_job->src_frame->bufs[i];
2266               pp_job->src_frame->bufs[i] = &bufs[i];
2267           }
2268           pp_job->src_reproc_bufs = bufs;
2269       }
2270
2271       // Don't release source frame after encoding
2272       // at this point the source channel will not exist.
2273       pp_job->reproc_frame_release = true;
2274       m_ongoingPPQ.enqueue((void *)pp_job);
2275       rc = m_pReprocChannel->doReprocessOffline(pp_job->src_frame);
2276    } else {
2277        m_ongoingPPQ.enqueue((void *)pp_job);
2278        rc = m_pReprocChannel->doReprocess(pp_job->src_frame);
2279    }
2280
2281    if (NO_ERROR != rc) {
2282        // remove from ongoing PP job Q
2283        m_ongoingPPQ.dequeue(false);
2284    }
2285
2286    return rc;
2287}
2288
2289/*===========================================================================
2290 * FUNCTION   : stopCapture
2291 *
2292 * DESCRIPTION: Trigger image capture stop
2293 *
2294 * PARAMETERS :
2295 * None
2296 *
2297 * RETURN     : int32_t type of status
2298 *              NO_ERROR  -- success
2299 *              none-zero failure code
2300 *==========================================================================*/
2301int32_t QCameraPostProcessor::stopCapture()
2302{
2303     int rc = NO_ERROR;
2304
2305     if (m_parent->isRegularCapture()) {
2306        rc = m_parent->processAPI(
2307                        QCAMERA_SM_EVT_STOP_CAPTURE_CHANNEL,
2308                        NULL);
2309     }
2310
2311     return rc;
2312}
2313
2314/*===========================================================================
2315 * FUNCTION   : getJpegPaddingReq
2316 *
2317 * DESCRIPTION: function to add an entry to exif data
2318 *
2319 * PARAMETERS :
2320 *   @padding_info : jpeg specific padding requirement
2321 *
2322 * RETURN     : int32_t type of status
2323 *              NO_ERROR  -- success
2324 *              none-zero failure code
2325 *==========================================================================*/
2326int32_t QCameraPostProcessor::getJpegPaddingReq(cam_padding_info_t &padding_info)
2327{
2328    // TODO: hardcode for now, needs to query from mm-jpeg-interface
2329    padding_info.width_padding  = CAM_PAD_NONE;
2330    padding_info.height_padding  = CAM_PAD_TO_16;
2331    padding_info.plane_padding  = CAM_PAD_TO_WORD;
2332    return NO_ERROR;
2333}
2334
2335/*===========================================================================
2336 * FUNCTION   : setYUVFrameInfo
2337 *
2338 * DESCRIPTION: set Raw YUV frame data info for up-layer
2339 *
2340 * PARAMETERS :
2341 *   @frame   : process frame received from mm-camera-interface
2342 *
2343 * RETURN     : int32_t type of status
2344 *              NO_ERROR  -- success
2345 *              none-zero failure code
2346 *
2347 * NOTE       : currently we return frame len, y offset, cbcr offset and frame format
2348 *==========================================================================*/
2349int32_t QCameraPostProcessor::setYUVFrameInfo(mm_camera_super_buf_t *recvd_frame)
2350{
2351    QCameraChannel *pChannel = m_parent->getChannelByHandle(recvd_frame->ch_id);
2352    // check reprocess channel if not found
2353    if (pChannel == NULL) {
2354        if (m_pReprocChannel != NULL &&
2355            m_pReprocChannel->getMyHandle() == recvd_frame->ch_id) {
2356            pChannel = m_pReprocChannel;
2357        }
2358    }
2359
2360    if (pChannel == NULL) {
2361        ALOGE("%s:%d] No corresponding channel (ch_id = %d) exist, return here",
2362              __func__, __LINE__, recvd_frame->ch_id);
2363        return BAD_VALUE;
2364    }
2365
2366    // find snapshot frame
2367    for (int i = 0; i < recvd_frame->num_bufs; i++) {
2368        QCameraStream *pStream =
2369            pChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id);
2370        if (pStream != NULL) {
2371            if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
2372                pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT)) {
2373                //get the main frame, use stream info
2374                cam_frame_len_offset_t frame_offset;
2375                cam_dimension_t frame_dim;
2376                cam_format_t frame_fmt;
2377                const char *fmt_string;
2378                pStream->getFrameDimension(frame_dim);
2379                pStream->getFrameOffset(frame_offset);
2380                pStream->getFormat(frame_fmt);
2381                fmt_string = m_parent->mParameters.getFrameFmtString(frame_fmt);
2382
2383                int cbcr_offset = frame_offset.mp[0].len - frame_dim.width * frame_dim.height;
2384                m_parent->mParameters.set("snapshot-framelen", frame_offset.frame_len);
2385                m_parent->mParameters.set("snapshot-yoff", frame_offset.mp[0].offset);
2386                m_parent->mParameters.set("snapshot-cbcroff", cbcr_offset);
2387                if(fmt_string != NULL){
2388                    m_parent->mParameters.set("snapshot-format", fmt_string);
2389                }else{
2390                    m_parent->mParameters.set("snapshot-format", "");
2391                }
2392
2393                CDBG_HIGH("%s: frame width=%d, height=%d, yoff=%d, cbcroff=%d, fmt_string=%s", __func__,
2394                        frame_dim.width, frame_dim.height, frame_offset.mp[0].offset, cbcr_offset, fmt_string);
2395                return NO_ERROR;
2396            }
2397        }
2398    }
2399
2400    return BAD_VALUE;
2401}
2402
2403bool QCameraPostProcessor::matchJobId(void *data, void *, void *match_data)
2404{
2405  qcamera_jpeg_data_t * job = (qcamera_jpeg_data_t *) data;
2406  uint32_t job_id = *((uint32_t *) match_data);
2407  return job->jobId == job_id;
2408}
2409
2410/*===========================================================================
2411 * FUNCTION   : getJpegMemory
2412 *
2413 * DESCRIPTION: buffer allocation function
2414 *   to pass to jpeg interface
2415 *
2416 * PARAMETERS :
2417 *   @out_buf : buffer descriptor struct
2418 *
2419 * RETURN     : int32_t type of status
2420 *              NO_ERROR  -- success
2421 *              none-zero failure code
2422 *==========================================================================*/
2423int QCameraPostProcessor::getJpegMemory(omx_jpeg_ouput_buf_t *out_buf)
2424{
2425    CDBG_HIGH("%s: Allocating jpeg out buffer of size: %d", __func__, out_buf->size);
2426    QCameraPostProcessor *procInst = (QCameraPostProcessor *) out_buf->handle;
2427    camera_memory_t *cam_mem = procInst->m_parent->mGetMemory(-1, out_buf->size,
2428        1, procInst->m_parent->mCallbackCookie);
2429    out_buf->mem_hdl = cam_mem;
2430    out_buf->vaddr = cam_mem->data;
2431
2432    return 0;
2433}
2434
2435/*===========================================================================
2436 * FUNCTION   : QCameraExif
2437 *
2438 * DESCRIPTION: constructor of QCameraExif
2439 *
2440 * PARAMETERS : None
2441 *
2442 * RETURN     : None
2443 *==========================================================================*/
2444QCameraExif::QCameraExif()
2445    : m_nNumEntries(0)
2446{
2447    memset(m_Entries, 0, sizeof(m_Entries));
2448}
2449
2450/*===========================================================================
2451 * FUNCTION   : ~QCameraExif
2452 *
2453 * DESCRIPTION: deconstructor of QCameraExif. Will release internal memory ptr.
2454 *
2455 * PARAMETERS : None
2456 *
2457 * RETURN     : None
2458 *==========================================================================*/
2459QCameraExif::~QCameraExif()
2460{
2461    for (uint32_t i = 0; i < m_nNumEntries; i++) {
2462        switch (m_Entries[i].tag_entry.type) {
2463        case EXIF_BYTE:
2464            {
2465                if (m_Entries[i].tag_entry.count > 1 &&
2466                    m_Entries[i].tag_entry.data._bytes != NULL) {
2467                    free(m_Entries[i].tag_entry.data._bytes);
2468                    m_Entries[i].tag_entry.data._bytes = NULL;
2469                }
2470            }
2471            break;
2472        case EXIF_ASCII:
2473            {
2474                if (m_Entries[i].tag_entry.data._ascii != NULL) {
2475                    free(m_Entries[i].tag_entry.data._ascii);
2476                    m_Entries[i].tag_entry.data._ascii = NULL;
2477                }
2478            }
2479            break;
2480        case EXIF_SHORT:
2481            {
2482                if (m_Entries[i].tag_entry.count > 1 &&
2483                    m_Entries[i].tag_entry.data._shorts != NULL) {
2484                    free(m_Entries[i].tag_entry.data._shorts);
2485                    m_Entries[i].tag_entry.data._shorts = NULL;
2486                }
2487            }
2488            break;
2489        case EXIF_LONG:
2490            {
2491                if (m_Entries[i].tag_entry.count > 1 &&
2492                    m_Entries[i].tag_entry.data._longs != NULL) {
2493                    free(m_Entries[i].tag_entry.data._longs);
2494                    m_Entries[i].tag_entry.data._longs = NULL;
2495                }
2496            }
2497            break;
2498        case EXIF_RATIONAL:
2499            {
2500                if (m_Entries[i].tag_entry.count > 1 &&
2501                    m_Entries[i].tag_entry.data._rats != NULL) {
2502                    free(m_Entries[i].tag_entry.data._rats);
2503                    m_Entries[i].tag_entry.data._rats = NULL;
2504                }
2505            }
2506            break;
2507        case EXIF_UNDEFINED:
2508            {
2509                if (m_Entries[i].tag_entry.data._undefined != NULL) {
2510                    free(m_Entries[i].tag_entry.data._undefined);
2511                    m_Entries[i].tag_entry.data._undefined = NULL;
2512                }
2513            }
2514            break;
2515        case EXIF_SLONG:
2516            {
2517                if (m_Entries[i].tag_entry.count > 1 &&
2518                    m_Entries[i].tag_entry.data._slongs != NULL) {
2519                    free(m_Entries[i].tag_entry.data._slongs);
2520                    m_Entries[i].tag_entry.data._slongs = NULL;
2521                }
2522            }
2523            break;
2524        case EXIF_SRATIONAL:
2525            {
2526                if (m_Entries[i].tag_entry.count > 1 &&
2527                    m_Entries[i].tag_entry.data._srats != NULL) {
2528                    free(m_Entries[i].tag_entry.data._srats);
2529                    m_Entries[i].tag_entry.data._srats = NULL;
2530                }
2531            }
2532            break;
2533        }
2534    }
2535}
2536
2537/*===========================================================================
2538 * FUNCTION   : addEntry
2539 *
2540 * DESCRIPTION: function to add an entry to exif data
2541 *
2542 * PARAMETERS :
2543 *   @tagid   : exif tag ID
2544 *   @type    : data type
2545 *   @count   : number of data in uint of its type
2546 *   @data    : input data ptr
2547 *
2548 * RETURN     : int32_t type of status
2549 *              NO_ERROR  -- success
2550 *              none-zero failure code
2551 *==========================================================================*/
2552int32_t QCameraExif::addEntry(exif_tag_id_t tagid,
2553                              exif_tag_type_t type,
2554                              uint32_t count,
2555                              void *data)
2556{
2557    int32_t rc = NO_ERROR;
2558    if(m_nNumEntries >= MAX_EXIF_TABLE_ENTRIES) {
2559        ALOGE("%s: Number of entries exceeded limit", __func__);
2560        return NO_MEMORY;
2561    }
2562
2563    m_Entries[m_nNumEntries].tag_id = tagid;
2564    m_Entries[m_nNumEntries].tag_entry.type = type;
2565    m_Entries[m_nNumEntries].tag_entry.count = count;
2566    m_Entries[m_nNumEntries].tag_entry.copy = 1;
2567    switch (type) {
2568    case EXIF_BYTE:
2569        {
2570            if (count > 1) {
2571                uint8_t *values = (uint8_t *)malloc(count);
2572                if (values == NULL) {
2573                    ALOGE("%s: No memory for byte array", __func__);
2574                    rc = NO_MEMORY;
2575                } else {
2576                    memcpy(values, data, count);
2577                    m_Entries[m_nNumEntries].tag_entry.data._bytes = values;
2578                }
2579            } else {
2580                m_Entries[m_nNumEntries].tag_entry.data._byte = *(uint8_t *)data;
2581            }
2582        }
2583        break;
2584    case EXIF_ASCII:
2585        {
2586            char *str = NULL;
2587            str = (char *)malloc(count + 1);
2588            if (str == NULL) {
2589                ALOGE("%s: No memory for ascii string", __func__);
2590                rc = NO_MEMORY;
2591            } else {
2592                memset(str, 0, count + 1);
2593                memcpy(str, data, count);
2594                m_Entries[m_nNumEntries].tag_entry.data._ascii = str;
2595            }
2596        }
2597        break;
2598    case EXIF_SHORT:
2599        {
2600            if (count > 1) {
2601                uint16_t *values = (uint16_t *)malloc(count * sizeof(uint16_t));
2602                if (values == NULL) {
2603                    ALOGE("%s: No memory for short array", __func__);
2604                    rc = NO_MEMORY;
2605                } else {
2606                    memcpy(values, data, count * sizeof(uint16_t));
2607                    m_Entries[m_nNumEntries].tag_entry.data._shorts = values;
2608                }
2609            } else {
2610                m_Entries[m_nNumEntries].tag_entry.data._short = *(uint16_t *)data;
2611            }
2612        }
2613        break;
2614    case EXIF_LONG:
2615        {
2616            if (count > 1) {
2617                uint32_t *values = (uint32_t *)malloc(count * sizeof(uint32_t));
2618                if (values == NULL) {
2619                    ALOGE("%s: No memory for long array", __func__);
2620                    rc = NO_MEMORY;
2621                } else {
2622                    memcpy(values, data, count * sizeof(uint32_t));
2623                    m_Entries[m_nNumEntries].tag_entry.data._longs = values;
2624                }
2625            } else {
2626                m_Entries[m_nNumEntries].tag_entry.data._long = *(uint32_t *)data;
2627            }
2628        }
2629        break;
2630    case EXIF_RATIONAL:
2631        {
2632            if (count > 1) {
2633                rat_t *values = (rat_t *)malloc(count * sizeof(rat_t));
2634                if (values == NULL) {
2635                    ALOGE("%s: No memory for rational array", __func__);
2636                    rc = NO_MEMORY;
2637                } else {
2638                    memcpy(values, data, count * sizeof(rat_t));
2639                    m_Entries[m_nNumEntries].tag_entry.data._rats = values;
2640                }
2641            } else {
2642                m_Entries[m_nNumEntries].tag_entry.data._rat = *(rat_t *)data;
2643            }
2644        }
2645        break;
2646    case EXIF_UNDEFINED:
2647        {
2648            uint8_t *values = (uint8_t *)malloc(count);
2649            if (values == NULL) {
2650                ALOGE("%s: No memory for undefined array", __func__);
2651                rc = NO_MEMORY;
2652            } else {
2653                memcpy(values, data, count);
2654                m_Entries[m_nNumEntries].tag_entry.data._undefined = values;
2655            }
2656        }
2657        break;
2658    case EXIF_SLONG:
2659        {
2660            if (count > 1) {
2661                int32_t *values = (int32_t *)malloc(count * sizeof(int32_t));
2662                if (values == NULL) {
2663                    ALOGE("%s: No memory for signed long array", __func__);
2664                    rc = NO_MEMORY;
2665                } else {
2666                    memcpy(values, data, count * sizeof(int32_t));
2667                    m_Entries[m_nNumEntries].tag_entry.data._slongs = values;
2668                }
2669            } else {
2670                m_Entries[m_nNumEntries].tag_entry.data._slong = *(int32_t *)data;
2671            }
2672        }
2673        break;
2674    case EXIF_SRATIONAL:
2675        {
2676            if (count > 1) {
2677                srat_t *values = (srat_t *)malloc(count * sizeof(srat_t));
2678                if (values == NULL) {
2679                    ALOGE("%s: No memory for signed rational array", __func__);
2680                    rc = NO_MEMORY;
2681                } else {
2682                    memcpy(values, data, count * sizeof(srat_t));
2683                    m_Entries[m_nNumEntries].tag_entry.data._srats = values;
2684                }
2685            } else {
2686                m_Entries[m_nNumEntries].tag_entry.data._srat = *(srat_t *)data;
2687            }
2688        }
2689        break;
2690    }
2691
2692    // Increase number of entries
2693    m_nNumEntries++;
2694    return rc;
2695}
2696
2697}; // namespace qcamera
2698