1 /* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 *     * Redistributions of source code must retain the above copyright
7 *       notice, this list of conditions and the following disclaimer.
8 *     * Redistributions in binary form must reproduce the above
9 *       copyright notice, this list of conditions and the following
10 *       disclaimer in the documentation and/or other materials provided
11 *       with the distribution.
12 *     * Neither the name of The Linux Foundation nor the names of its
13 *       contributors may be used to endorse or promote products derived
14 *       from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29 
30 #define LOG_TAG "QCamera3PostProc"
31 
32 // To remove
33 #include <cutils/properties.h>
34 
35 // System dependencies
36 #include <stdio.h>
37 
38 // Camera dependencies
39 #include "QCamera3Channel.h"
40 #include "QCamera3HWI.h"
41 #include "QCamera3PostProc.h"
42 #include "QCamera3Stream.h"
43 #include "QCameraTrace.h"
44 
45 extern "C" {
46 #include "mm_camera_dbg.h"
47 }
48 
49 #define ENABLE_MODEL_INFO_EXIF
50 
51 namespace qcamera {
52 
53 static const char ExifAsciiPrefix[] =
54     { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };          // "ASCII\0\0\0"
55 
56 __unused
57 static const char ExifUndefinedPrefix[] =
58     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };   // "\0\0\0\0\0\0\0\0"
59 
60 #define EXIF_ASCII_PREFIX_SIZE           8   //(sizeof(ExifAsciiPrefix))
61 #define FOCAL_LENGTH_DECIMAL_PRECISION   1000
62 
63 /*===========================================================================
64  * FUNCTION   : QCamera3PostProcessor
65  *
66  * DESCRIPTION: constructor of QCamera3PostProcessor.
67  *
68  * PARAMETERS :
69  *   @cam_ctrl : ptr to HWI object
70  *
71  * RETURN     : None
72  *==========================================================================*/
QCamera3PostProcessor(QCamera3ProcessingChannel * ch_ctrl)73 QCamera3PostProcessor::QCamera3PostProcessor(QCamera3ProcessingChannel* ch_ctrl)
74     : m_parent(ch_ctrl),
75       mJpegCB(NULL),
76       mJpegUserData(NULL),
77       mJpegClientHandle(0),
78       mJpegSessionId(0),
79       m_bThumbnailNeeded(TRUE),
80       m_pReprocChannel(NULL),
81       m_inputPPQ(releasePPInputData, this),
82       m_inputFWKPPQ(NULL, this),
83       m_ongoingPPQ(releaseOngoingPPData, this),
84       m_inputJpegQ(releaseJpegData, this),
85       m_ongoingJpegQ(releaseJpegData, this),
86       m_inputMetaQ(releaseMetadata, this),
87       m_jpegSettingsQ(NULL, this)
88 {
89     memset(&mJpegHandle, 0, sizeof(mJpegHandle));
90     pthread_mutex_init(&mReprocJobLock, NULL);
91 }
92 
93 /*===========================================================================
94  * FUNCTION   : ~QCamera3PostProcessor
95  *
96  * DESCRIPTION: deconstructor of QCamera3PostProcessor.
97  *
98  * PARAMETERS : None
99  *
100  * RETURN     : None
101  *==========================================================================*/
~QCamera3PostProcessor()102 QCamera3PostProcessor::~QCamera3PostProcessor()
103 {
104     pthread_mutex_destroy(&mReprocJobLock);
105 }
106 
107 /*===========================================================================
108  * FUNCTION   : init
109  *
110  * DESCRIPTION: initialization of postprocessor
111  *
112  * PARAMETERS :
113  *   @memory              : output buffer memory
114  *
115  * RETURN     : int32_t type of status
116  *              NO_ERROR  -- success
117  *              none-zero failure code
118  *==========================================================================*/
init(QCamera3StreamMem * memory)119 int32_t QCamera3PostProcessor::init(QCamera3StreamMem *memory)
120 {
121     ATRACE_CALL();
122     mOutputMem = memory;
123     m_dataProcTh.launch(dataProcessRoutine, this);
124 
125     return NO_ERROR;
126 }
127 
128 /*===========================================================================
129  * FUNCTION   : deinit
130  *
131  * DESCRIPTION: de-initialization of postprocessor
132  *
133  * PARAMETERS : None
134  *
135  * RETURN     : int32_t type of status
136  *              NO_ERROR  -- success
137  *              none-zero failure code
138  *==========================================================================*/
deinit()139 int32_t QCamera3PostProcessor::deinit()
140 {
141     int rc = NO_ERROR;
142     m_dataProcTh.exit();
143 
144     if (m_pReprocChannel != NULL) {
145         m_pReprocChannel->stop();
146         delete m_pReprocChannel;
147         m_pReprocChannel = NULL;
148     }
149 
150     if(mJpegClientHandle > 0) {
151         rc = mJpegHandle.close(mJpegClientHandle);
152         LOGH("Jpeg closed, rc = %d, mJpegClientHandle = %x",
153                rc, mJpegClientHandle);
154         mJpegClientHandle = 0;
155         memset(&mJpegHandle, 0, sizeof(mJpegHandle));
156     }
157 
158     mOutputMem = NULL;
159     return rc;
160 }
161 
162 /*===========================================================================
163  * FUNCTION   : initJpeg
164  *
165  * DESCRIPTION: initialization of jpeg through postprocessor
166  *
167  * PARAMETERS :
168  *   @jpeg_cb      : callback to handle jpeg event from mm-camera-interface
169  *   @max_pic_dim  : max picture dimensions
170  *   @user_data    : user data ptr for jpeg callback
171  *
172  * RETURN     : int32_t type of status
173  *              NO_ERROR  -- success
174  *              none-zero failure code
175  *==========================================================================*/
initJpeg(jpeg_encode_callback_t jpeg_cb,cam_dimension_t * max_pic_dim,void * user_data)176 int32_t QCamera3PostProcessor::initJpeg(jpeg_encode_callback_t jpeg_cb,
177         cam_dimension_t* max_pic_dim,
178         void *user_data)
179 {
180     ATRACE_CALL();
181     mJpegCB = jpeg_cb;
182     mJpegUserData = user_data;
183     mm_dimension max_size;
184 
185     if ((0 > max_pic_dim->width) || (0 > max_pic_dim->height)) {
186         LOGE("Negative dimension %dx%d",
187                 max_pic_dim->width, max_pic_dim->height);
188         return BAD_VALUE;
189     }
190 
191     //set max pic size
192     memset(&max_size, 0, sizeof(mm_dimension));
193     max_size.w =  max_pic_dim->width;
194     max_size.h =  max_pic_dim->height;
195 
196     mJpegClientHandle = jpeg_open(&mJpegHandle, NULL, max_size, NULL);
197     if(!mJpegClientHandle) {
198         LOGE("jpeg_open did not work");
199         return UNKNOWN_ERROR;
200     }
201     return NO_ERROR;
202 }
203 
204 /*===========================================================================
205  * FUNCTION   : start
206  *
207  * DESCRIPTION: start postprocessor. Data process thread and data notify thread
208  *              will be launched.
209  *
210  * PARAMETERS :
211  *   @config        : reprocess configuration
212  *
213  * RETURN     : int32_t type of status
214  *              NO_ERROR  -- success
215  *              none-zero failure code
216  *
217  * NOTE       : if any reprocess is needed, a reprocess channel/stream
218  *              will be started.
219  *==========================================================================*/
start(const reprocess_config_t & config)220 int32_t QCamera3PostProcessor::start(const reprocess_config_t &config)
221 {
222     int32_t rc = NO_ERROR;
223     QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
224 
225     if (config.reprocess_type != REPROCESS_TYPE_NONE) {
226         if (m_pReprocChannel != NULL) {
227             m_pReprocChannel->stop();
228             delete m_pReprocChannel;
229             m_pReprocChannel = NULL;
230         }
231 
232         // if reprocess is needed, start reprocess channel
233         LOGD("Setting input channel as pInputChannel");
234         m_pReprocChannel = hal_obj->addOfflineReprocChannel(config, m_parent);
235         if (m_pReprocChannel == NULL) {
236             LOGE("cannot add reprocess channel");
237             return UNKNOWN_ERROR;
238         }
239         /*start the reprocess channel only if buffers are already allocated, thus
240           only start it in an intermediate reprocess type, defer it for others*/
241         if (config.reprocess_type == REPROCESS_TYPE_JPEG) {
242             rc = m_pReprocChannel->start();
243             if (rc != 0) {
244                 LOGE("cannot start reprocess channel");
245                 delete m_pReprocChannel;
246                 m_pReprocChannel = NULL;
247                 return rc;
248             }
249         }
250     }
251     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, TRUE, FALSE);
252 
253     return rc;
254 }
255 
256 /*===========================================================================
257  * FUNCTION   : flush
258  *
259  * DESCRIPTION: stop ongoing postprocess and jpeg jobs
260  *
261  * PARAMETERS : None
262  *
263  * RETURN     : int32_t type of status
264  *              NO_ERROR  -- success
265  *              none-zero failure code
266  *
267  *==========================================================================*/
flush()268 int32_t QCamera3PostProcessor::flush()
269 {
270     int32_t rc = NO_ERROR;
271     qcamera_hal3_jpeg_data_t *jpeg_job =
272             (qcamera_hal3_jpeg_data_t *)m_ongoingJpegQ.dequeue();
273     while (jpeg_job != NULL) {
274         rc = mJpegHandle.abort_job(jpeg_job->jobId);
275         releaseJpegJobData(jpeg_job);
276         free(jpeg_job);
277 
278         jpeg_job = (qcamera_hal3_jpeg_data_t *)m_ongoingJpegQ.dequeue();
279     }
280     rc = releaseOfflineBuffers(true);
281     return rc;
282 }
283 
284 /*===========================================================================
285  * FUNCTION   : stop
286  *
287  * DESCRIPTION: stop postprocessor. Data process and notify thread will be stopped.
288  *
289  * PARAMETERS : None
290  *
291  * RETURN     : int32_t type of status
292  *              NO_ERROR  -- success
293  *              none-zero failure code
294  *
295  * NOTE       : reprocess channel will be stopped and deleted if there is any
296  *==========================================================================*/
stop()297 int32_t QCamera3PostProcessor::stop()
298 {
299     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE);
300 
301     if (m_pReprocChannel != NULL) {
302         m_pReprocChannel->stop();
303         delete m_pReprocChannel;
304         m_pReprocChannel = NULL;
305     }
306 
307     return NO_ERROR;
308 }
309 
310 /*===========================================================================
311  * FUNCTION   : getFWKJpegEncodeConfig
312  *
313  * DESCRIPTION: function to prepare encoding job information
314  *
315  * PARAMETERS :
316  *   @encode_parm   : param to be filled with encoding configuration
317  *   @frame         : framework input buffer
318  *   @jpeg_settings : jpeg settings to be applied for encoding
319  *
320  * RETURN     : int32_t type of status
321  *              NO_ERROR  -- success
322  *              none-zero failure code
323  *==========================================================================*/
getFWKJpegEncodeConfig(mm_jpeg_encode_params_t & encode_parm,qcamera_fwk_input_pp_data_t * frame,jpeg_settings_t * jpeg_settings)324 int32_t QCamera3PostProcessor::getFWKJpegEncodeConfig(
325         mm_jpeg_encode_params_t& encode_parm,
326         qcamera_fwk_input_pp_data_t *frame,
327         jpeg_settings_t *jpeg_settings)
328 {
329     LOGD("E");
330     int32_t ret = NO_ERROR;
331 
332     if ((NULL == frame) || (NULL == jpeg_settings)) {
333         return BAD_VALUE;
334     }
335 
336     ssize_t bufSize = mOutputMem->getSize(jpeg_settings->out_buf_index);
337     if (BAD_INDEX == bufSize) {
338         LOGE("cannot retrieve buffer size for buffer %u",
339                 jpeg_settings->out_buf_index);
340         return BAD_VALUE;
341     }
342 
343     encode_parm.jpeg_cb = mJpegCB;
344     encode_parm.userdata = mJpegUserData;
345 
346     if (jpeg_settings->thumbnail_size.width > 0 &&
347             jpeg_settings->thumbnail_size.height > 0)
348         m_bThumbnailNeeded = TRUE;
349     else
350         m_bThumbnailNeeded = FALSE;
351     encode_parm.encode_thumbnail = m_bThumbnailNeeded;
352 
353     // get color format
354     cam_format_t img_fmt = frame->reproc_config.stream_format;
355     encode_parm.color_format = getColorfmtFromImgFmt(img_fmt);
356 
357     // get jpeg quality
358     encode_parm.quality = jpeg_settings->jpeg_quality;
359     if (encode_parm.quality <= 0) {
360         encode_parm.quality = 85;
361     }
362 
363     // get jpeg thumbnail quality
364     encode_parm.thumb_quality = jpeg_settings->jpeg_thumb_quality;
365 
366     cam_frame_len_offset_t main_offset =
367             frame->reproc_config.input_stream_plane_info.plane_info;
368 
369     encode_parm.num_src_bufs = 1;
370     encode_parm.src_main_buf[0].index = 0;
371     encode_parm.src_main_buf[0].buf_size = frame->input_buffer.frame_len;
372     encode_parm.src_main_buf[0].buf_vaddr = (uint8_t *) frame->input_buffer.buffer;
373     encode_parm.src_main_buf[0].fd = frame->input_buffer.fd;
374     encode_parm.src_main_buf[0].format = MM_JPEG_FMT_YUV;
375     encode_parm.src_main_buf[0].offset = main_offset;
376 
377     //Pass input thumbnail buffer info to encoder.
378     //Note: Use main buffer to encode thumbnail
379     if (m_bThumbnailNeeded == TRUE) {
380         encode_parm.num_tmb_bufs = 1;
381         encode_parm.src_thumb_buf[0] = encode_parm.src_main_buf[0];
382     }
383 
384     //Pass output jpeg buffer info to encoder.
385     //mOutputMem is allocated by framework.
386     encode_parm.num_dst_bufs = 1;
387     encode_parm.dest_buf[0].index = 0;
388     encode_parm.dest_buf[0].buf_size = (size_t)bufSize;
389     encode_parm.dest_buf[0].buf_vaddr = (uint8_t *)mOutputMem->getPtr(
390             jpeg_settings->out_buf_index);
391     encode_parm.dest_buf[0].fd = mOutputMem->getFd(
392             jpeg_settings->out_buf_index);
393     encode_parm.dest_buf[0].format = MM_JPEG_FMT_YUV;
394     encode_parm.dest_buf[0].offset = main_offset;
395 
396     LOGD("X");
397     return NO_ERROR;
398 
399     LOGD("X with error %d", ret);
400     return ret;
401 }
402 
403 /*===========================================================================
404  * FUNCTION   : getJpegEncodeConfig
405  *
406  * DESCRIPTION: function to prepare encoding job information
407  *
408  * PARAMETERS :
409  *   @encode_parm   : param to be filled with encoding configuration
410  *   #main_stream   : stream object where the input buffer comes from
411  *   @jpeg_settings : jpeg settings to be applied for encoding
412  *
413  * RETURN     : int32_t type of status
414  *              NO_ERROR  -- success
415  *              none-zero failure code
416  *==========================================================================*/
getJpegEncodeConfig(mm_jpeg_encode_params_t & encode_parm,QCamera3Stream * main_stream,jpeg_settings_t * jpeg_settings)417 int32_t QCamera3PostProcessor::getJpegEncodeConfig(
418                 mm_jpeg_encode_params_t& encode_parm,
419                 QCamera3Stream *main_stream,
420                 jpeg_settings_t *jpeg_settings)
421 {
422     LOGD("E");
423     int32_t ret = NO_ERROR;
424     ssize_t bufSize = 0;
425 
426     encode_parm.jpeg_cb = mJpegCB;
427     encode_parm.userdata = mJpegUserData;
428 
429     if (jpeg_settings->thumbnail_size.width > 0 &&
430             jpeg_settings->thumbnail_size.height > 0)
431         m_bThumbnailNeeded = TRUE;
432     else
433         m_bThumbnailNeeded = FALSE;
434     encode_parm.encode_thumbnail = m_bThumbnailNeeded;
435 
436     // get color format
437     cam_format_t img_fmt = CAM_FORMAT_YUV_420_NV12;  //default value
438     main_stream->getFormat(img_fmt);
439     encode_parm.color_format = getColorfmtFromImgFmt(img_fmt);
440 
441     // get jpeg quality
442     encode_parm.quality = jpeg_settings->jpeg_quality;
443     if (encode_parm.quality <= 0) {
444         encode_parm.quality = 85;
445     }
446 
447     // get jpeg thumbnail quality
448     encode_parm.thumb_quality = jpeg_settings->jpeg_thumb_quality;
449 
450     cam_frame_len_offset_t main_offset;
451     memset(&main_offset, 0, sizeof(cam_frame_len_offset_t));
452     main_stream->getFrameOffset(main_offset);
453 
454     // src buf config
455     //Pass input main image buffer info to encoder.
456     QCamera3StreamMem *pStreamMem = main_stream->getStreamBufs();
457     if (pStreamMem == NULL) {
458         LOGE("cannot get stream bufs from main stream");
459         ret = BAD_VALUE;
460         goto on_error;
461     }
462     encode_parm.num_src_bufs = MIN(pStreamMem->getCnt(), MM_JPEG_MAX_BUF);
463     for (uint32_t i = 0; i < encode_parm.num_src_bufs; i++) {
464         if (pStreamMem != NULL) {
465             encode_parm.src_main_buf[i].index = i;
466             bufSize = pStreamMem->getSize(i);
467             if (BAD_INDEX == bufSize) {
468                 LOGE("cannot retrieve buffer size for buffer %u", i);
469                 ret = BAD_VALUE;
470                 goto on_error;
471             }
472             encode_parm.src_main_buf[i].buf_size = (size_t)bufSize;
473             encode_parm.src_main_buf[i].buf_vaddr = (uint8_t *)pStreamMem->getPtr(i);
474             encode_parm.src_main_buf[i].fd = pStreamMem->getFd(i);
475             encode_parm.src_main_buf[i].format = MM_JPEG_FMT_YUV;
476             encode_parm.src_main_buf[i].offset = main_offset;
477         }
478     }
479 
480     //Pass input thumbnail buffer info to encoder.
481     //Note: Use main buffer to encode thumbnail
482     if (m_bThumbnailNeeded == TRUE) {
483         pStreamMem = main_stream->getStreamBufs();
484         if (pStreamMem == NULL) {
485             LOGE("cannot get stream bufs from thumb stream");
486             ret = BAD_VALUE;
487             goto on_error;
488         }
489         cam_frame_len_offset_t thumb_offset;
490         memset(&thumb_offset, 0, sizeof(cam_frame_len_offset_t));
491         main_stream->getFrameOffset(thumb_offset);
492         encode_parm.num_tmb_bufs = MIN(pStreamMem->getCnt(), MM_JPEG_MAX_BUF);
493         for (uint32_t i = 0; i < encode_parm.num_tmb_bufs; i++) {
494             if (pStreamMem != NULL) {
495                 encode_parm.src_thumb_buf[i].index = i;
496                 bufSize = pStreamMem->getSize(i);
497                 if (BAD_INDEX == bufSize) {
498                     LOGE("cannot retrieve buffer size for buffer %u", i);
499                     ret = BAD_VALUE;
500                     goto on_error;
501                 }
502                 encode_parm.src_thumb_buf[i].buf_size = (uint32_t)bufSize;
503                 encode_parm.src_thumb_buf[i].buf_vaddr = (uint8_t *)pStreamMem->getPtr(i);
504                 encode_parm.src_thumb_buf[i].fd = pStreamMem->getFd(i);
505                 encode_parm.src_thumb_buf[i].format = MM_JPEG_FMT_YUV;
506                 encode_parm.src_thumb_buf[i].offset = thumb_offset;
507             }
508         }
509     }
510 
511     //Pass output jpeg buffer info to encoder.
512     //mJpegMem is allocated by framework.
513     bufSize = mOutputMem->getSize(jpeg_settings->out_buf_index);
514     if (BAD_INDEX == bufSize) {
515         LOGE("cannot retrieve buffer size for buffer %u",
516                 jpeg_settings->out_buf_index);
517         ret = BAD_VALUE;
518         goto on_error;
519     }
520     encode_parm.num_dst_bufs = 1;
521     encode_parm.dest_buf[0].index = 0;
522     encode_parm.dest_buf[0].buf_size = (size_t)bufSize;
523     encode_parm.dest_buf[0].buf_vaddr = (uint8_t *)mOutputMem->getPtr(
524             jpeg_settings->out_buf_index);
525     encode_parm.dest_buf[0].fd = mOutputMem->getFd(
526             jpeg_settings->out_buf_index);
527     encode_parm.dest_buf[0].format = MM_JPEG_FMT_YUV;
528     encode_parm.dest_buf[0].offset = main_offset;
529 
530     LOGD("X");
531     return NO_ERROR;
532 
533 on_error:
534     LOGD("X with error %d", ret);
535     return ret;
536 }
537 
processData(mm_camera_super_buf_t * input)538 int32_t QCamera3PostProcessor::processData(mm_camera_super_buf_t *input) {
539     return processData(input, NULL, 0);
540 }
541 
542 /*===========================================================================
543  * FUNCTION   : processData
544  *
545  * DESCRIPTION: enqueue data into dataProc thread
546  *
547  * PARAMETERS :
548  *   @frame   : process input frame
549  *   @output  : process output frame
550  *
551  * RETURN     : int32_t type of status
552  *              NO_ERROR  -- success
553  *              none-zero failure code
554  *
555  * NOTE       : depends on if offline reprocess is needed, received frame will
556  *              be sent to either input queue of postprocess or jpeg encoding
557  *==========================================================================*/
processData(mm_camera_super_buf_t * input,buffer_handle_t * output,uint32_t frameNumber)558 int32_t QCamera3PostProcessor::processData(mm_camera_super_buf_t *input,
559         buffer_handle_t *output, uint32_t frameNumber)
560 {
561     LOGD("E");
562     pthread_mutex_lock(&mReprocJobLock);
563 
564     // enqueue to post proc input queue
565     qcamera_hal3_pp_buffer_t *pp_buffer = (qcamera_hal3_pp_buffer_t *)malloc(
566             sizeof(qcamera_hal3_pp_buffer_t));
567     if (NULL == pp_buffer) {
568         LOGE("out of memory");
569         return NO_MEMORY;
570     }
571     memset(pp_buffer, 0, sizeof(*pp_buffer));
572     pp_buffer->input = input;
573     pp_buffer->output = output;
574     pp_buffer->frameNumber = frameNumber;
575     m_inputPPQ.enqueue((void *)pp_buffer);
576     if (!(m_inputMetaQ.isEmpty())) {
577         LOGD("meta queue is not empty, do next job");
578         m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
579     } else
580         LOGD("metadata queue is empty");
581     pthread_mutex_unlock(&mReprocJobLock);
582 
583     return NO_ERROR;
584 }
585 
586 /*===========================================================================
587  * FUNCTION   : processData
588  *
589  * DESCRIPTION: enqueue data into dataProc thread
590  *
591  * PARAMETERS :
592  *   @frame   : process frame
593  *
594  * RETURN     : int32_t type of status
595  *              NO_ERROR  -- success
596  *              none-zero failure code
597  *
598  * NOTE       : depends on if offline reprocess is needed, received frame will
599  *              be sent to either input queue of postprocess or jpeg encoding
600  *==========================================================================*/
processData(qcamera_fwk_input_pp_data_t * frame)601 int32_t QCamera3PostProcessor::processData(qcamera_fwk_input_pp_data_t *frame)
602 {
603     if (frame->reproc_config.reprocess_type != REPROCESS_TYPE_NONE) {
604         KPI_ATRACE_ASYNC_BEGIN("Camera:Reprocess", frame->frameNumber);
605         pthread_mutex_lock(&mReprocJobLock);
606         // enqueu to post proc input queue
607         m_inputFWKPPQ.enqueue((void *)frame);
608         m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
609         pthread_mutex_unlock(&mReprocJobLock);
610     } else {
611         jpeg_settings_t *jpeg_settings = (jpeg_settings_t *)m_jpegSettingsQ.dequeue();
612 
613         if (jpeg_settings == NULL) {
614             LOGE("Cannot find jpeg settings");
615             return BAD_VALUE;
616         }
617 
618         LOGH("no need offline reprocess, sending to jpeg encoding");
619         qcamera_hal3_jpeg_data_t *jpeg_job =
620             (qcamera_hal3_jpeg_data_t *)malloc(sizeof(qcamera_hal3_jpeg_data_t));
621         if (jpeg_job == NULL) {
622             LOGE("No memory for jpeg job");
623             return NO_MEMORY;
624         }
625 
626         memset(jpeg_job, 0, sizeof(qcamera_hal3_jpeg_data_t));
627         jpeg_job->fwk_frame = frame;
628         jpeg_job->jpeg_settings = jpeg_settings;
629         jpeg_job->metadata =
630                 (metadata_buffer_t *) frame->metadata_buffer.buffer;
631 
632         // enqueu to jpeg input queue
633         m_inputJpegQ.enqueue((void *)jpeg_job);
634         m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
635     }
636 
637     return NO_ERROR;
638 }
639 
640 /*===========================================================================
641  * FUNCTION   : processPPMetadata
642  *
643  * DESCRIPTION: enqueue data into dataProc thread
644  *
645  * PARAMETERS :
646  *   @frame   : process metadata frame received from pic channel
647  *
648  * RETURN     : int32_t type of status
649  *              NO_ERROR  -- success
650  *              none-zero failure code
651  *
652  *==========================================================================*/
processPPMetadata(mm_camera_super_buf_t * reproc_meta)653 int32_t QCamera3PostProcessor::processPPMetadata(mm_camera_super_buf_t *reproc_meta)
654 {
655     LOGD("E");
656     pthread_mutex_lock(&mReprocJobLock);
657     // enqueue to metadata input queue
658     m_inputMetaQ.enqueue((void *)reproc_meta);
659     if (!(m_inputPPQ.isEmpty())) {
660        LOGD("pp queue is not empty, do next job");
661        m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
662     } else {
663        LOGD("pp queue is empty, not calling do next job");
664     }
665     pthread_mutex_unlock(&mReprocJobLock);
666     return NO_ERROR;
667 }
668 
669 /*===========================================================================
670  * FUNCTION   : processJpegSettingData
671  *
672  * DESCRIPTION: enqueue jpegSetting into dataProc thread
673  *
674  * PARAMETERS :
675  *   @jpeg_settings : jpeg settings data received from pic channel
676  *
677  * RETURN     : int32_t type of status
678  *              NO_ERROR  -- success
679  *              none-zero failure code
680  *
681  *==========================================================================*/
processJpegSettingData(jpeg_settings_t * jpeg_settings)682 int32_t QCamera3PostProcessor::processJpegSettingData(
683         jpeg_settings_t *jpeg_settings)
684 {
685     if (!jpeg_settings) {
686         LOGE("invalid jpeg settings pointer");
687         return -EINVAL;
688     }
689     return m_jpegSettingsQ.enqueue((void *)jpeg_settings);
690 }
691 
692 /*===========================================================================
693  * FUNCTION   : processPPData
694  *
695  * DESCRIPTION: process received frame after reprocess.
696  *
697  * PARAMETERS :
698  *   @frame   : received frame from reprocess channel.
699  *
700  * RETURN     : int32_t type of status
701  *              NO_ERROR  -- success
702  *              none-zero failure code
703  *
704  * NOTE       : The frame after reprocess need to send to jpeg encoding.
705  *==========================================================================*/
processPPData(mm_camera_super_buf_t * frame)706 int32_t QCamera3PostProcessor::processPPData(mm_camera_super_buf_t *frame)
707 {
708     qcamera_hal3_pp_data_t *job = (qcamera_hal3_pp_data_t *)m_ongoingPPQ.dequeue();
709     if (job == NULL || ((NULL == job->src_frame) && (NULL == job->fwk_src_frame))) {
710         LOGE("Cannot find reprocess job");
711         return BAD_VALUE;
712     }
713     if (job->jpeg_settings == NULL) {
714         LOGE("Cannot find jpeg settings");
715         return BAD_VALUE;
716     }
717 
718     qcamera_hal3_jpeg_data_t *jpeg_job =
719         (qcamera_hal3_jpeg_data_t *)malloc(sizeof(qcamera_hal3_jpeg_data_t));
720     if (jpeg_job == NULL) {
721         LOGE("No memory for jpeg job");
722         return NO_MEMORY;
723     }
724 
725     memset(jpeg_job, 0, sizeof(qcamera_hal3_jpeg_data_t));
726     jpeg_job->src_frame = frame;
727     if(frame != job->src_frame)
728         jpeg_job->src_reproc_frame = job->src_frame;
729     if (NULL == job->fwk_src_frame) {
730         jpeg_job->metadata = job->metadata;
731     } else {
732         KPI_ATRACE_ASYNC_END("Camera:Reprocess", job->fwk_src_frame->frameNumber);
733         jpeg_job->metadata =
734                 (metadata_buffer_t *) job->fwk_src_frame->metadata_buffer.buffer;
735         jpeg_job->fwk_src_buffer = job->fwk_src_frame;
736     }
737     jpeg_job->src_metadata = job->src_metadata;
738     jpeg_job->jpeg_settings = job->jpeg_settings;
739 
740     // free pp job buf
741     free(job);
742 
743     // enqueu reprocessed frame to jpeg input queue
744     m_inputJpegQ.enqueue((void *)jpeg_job);
745 
746     // wait up data proc thread
747     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
748 
749     return NO_ERROR;
750 }
751 
752 /*===========================================================================
753  * FUNCTION   : dequeuePPJob
754  *
755  * DESCRIPTION: find a postprocessing job from ongoing pp queue by frame number
756  *
757  * PARAMETERS :
758  *   @frameNumber : frame number for the pp job
759  *
760  * RETURN     : ptr to a pp job struct. NULL if not found.
761  *==========================================================================*/
dequeuePPJob(uint32_t frameNumber)762 qcamera_hal3_pp_data_t *QCamera3PostProcessor::dequeuePPJob(uint32_t frameNumber) {
763     qcamera_hal3_pp_data_t *pp_job = NULL;
764     pp_job = (qcamera_hal3_pp_data_t *)m_ongoingPPQ.dequeue();
765 
766     if (pp_job == NULL) {
767         LOGE("Fatal: ongoing PP queue is empty");
768         return NULL;
769     }
770     if (pp_job->fwk_src_frame &&
771             (pp_job->fwk_src_frame->frameNumber != frameNumber)) {
772         LOGE("head of pp queue doesn't match requested frame number");
773     }
774     return pp_job;
775 }
776 
777 /*===========================================================================
778  * FUNCTION   : findJpegJobByJobId
779  *
780  * DESCRIPTION: find a jpeg job from ongoing Jpeg queue by its job ID
781  *
782  * PARAMETERS :
783  *   @jobId   : job Id of the job
784  *
785  * RETURN     : ptr to a jpeg job struct. NULL if not found.
786  *
787  * NOTE       : Currently only one job is sending to mm-jpeg-interface for jpeg
788  *              encoding. Therefore simply dequeue from the ongoing Jpeg Queue
789  *              will serve the purpose to find the jpeg job.
790  *==========================================================================*/
findJpegJobByJobId(uint32_t jobId)791 qcamera_hal3_jpeg_data_t *QCamera3PostProcessor::findJpegJobByJobId(uint32_t jobId)
792 {
793     qcamera_hal3_jpeg_data_t * job = NULL;
794     if (jobId == 0) {
795         LOGE("not a valid jpeg jobId");
796         return NULL;
797     }
798 
799     // currely only one jpeg job ongoing, so simply dequeue the head
800     job = (qcamera_hal3_jpeg_data_t *)m_ongoingJpegQ.dequeue();
801     return job;
802 }
803 
804 /*===========================================================================
805  * FUNCTION   : releasePPInputData
806  *
807  * DESCRIPTION: callback function to release post process input data node
808  *
809  * PARAMETERS :
810  *   @data      : ptr to post process input data
811  *   @user_data : user data ptr (QCamera3Reprocessor)
812  *
813  * RETURN     : None
814  *==========================================================================*/
releasePPInputData(void * data,void * user_data)815 void QCamera3PostProcessor::releasePPInputData(void *data, void *user_data)
816 {
817     QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data;
818     if (NULL != pme) {
819         qcamera_hal3_pp_buffer_t *buf = (qcamera_hal3_pp_buffer_t *)data;
820         if (NULL != buf) {
821             if (buf->input) {
822                 pme->releaseSuperBuf(buf->input);
823                 free(buf->input);
824                 buf->input = NULL;
825             }
826         }
827     }
828 }
829 
830 /*===========================================================================
831  * FUNCTION   : releaseMetaData
832  *
833  * DESCRIPTION: callback function to release metadata camera buffer
834  *
835  * PARAMETERS :
836  *   @data      : ptr to post process input data
837  *   @user_data : user data ptr (QCamera3Reprocessor)
838  *
839  * RETURN     : None
840  *==========================================================================*/
releaseMetadata(void * data,void * user_data)841 void QCamera3PostProcessor::releaseMetadata(void *data, void *user_data)
842 {
843     QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data;
844     if (NULL != pme) {
845         pme->m_parent->metadataBufDone((mm_camera_super_buf_t *)data);
846     }
847 }
848 
849 /*===========================================================================
850  * FUNCTION   : releaseJpegData
851  *
852  * DESCRIPTION: callback function to release jpeg job node
853  *
854  * PARAMETERS :
855  *   @data      : ptr to ongoing jpeg job data
856  *   @user_data : user data ptr (QCamera3Reprocessor)
857  *
858  * RETURN     : None
859  *==========================================================================*/
releaseJpegData(void * data,void * user_data)860 void QCamera3PostProcessor::releaseJpegData(void *data, void *user_data)
861 {
862     QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data;
863     if (NULL != pme) {
864         pme->releaseJpegJobData((qcamera_hal3_jpeg_data_t *)data);
865     }
866 }
867 
868 /*===========================================================================
869  * FUNCTION   : releaseOngoingPPData
870  *
871  * DESCRIPTION: callback function to release ongoing postprocess job node
872  *
873  * PARAMETERS :
874  *   @data      : ptr to onging postprocess job
875  *   @user_data : user data ptr (QCamera3Reprocessor)
876  *
877  * RETURN     : None
878  *==========================================================================*/
releaseOngoingPPData(void * data,void * user_data)879 void QCamera3PostProcessor::releaseOngoingPPData(void *data, void *user_data)
880 {
881     QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data;
882     if (NULL != pme) {
883         qcamera_hal3_pp_data_t *pp_data = (qcamera_hal3_pp_data_t *)data;
884 
885         if (pp_data && pp_data->src_frame)
886           pme->releaseSuperBuf(pp_data->src_frame);
887 
888         pme->releasePPJobData(pp_data);
889 
890     }
891 }
892 
893 /*===========================================================================
894  * FUNCTION   : releaseSuperBuf
895  *
896  * DESCRIPTION: function to release a superbuf frame by returning back to kernel
897  *
898  * PARAMETERS :
899  *   @super_buf : ptr to the superbuf frame
900  *
901  * RETURN     : None
902  *==========================================================================*/
releaseSuperBuf(mm_camera_super_buf_t * super_buf)903 void QCamera3PostProcessor::releaseSuperBuf(mm_camera_super_buf_t *super_buf)
904 {
905     if (NULL != super_buf) {
906         if (m_parent != NULL) {
907             m_parent->bufDone(super_buf);
908         }
909     }
910 }
911 
912 /*===========================================================================
913  * FUNCTION   : releaseOfflineBuffers
914  *
915  * DESCRIPTION: function to release/unmap offline buffers if any
916  *
917  * PARAMETERS :
918  * @allBuffers : flag that asks to release all buffers or only one
919  *
920  * RETURN     : int32_t type of status
921  *              NO_ERROR  -- success
922  *              none-zero failure code
923  *==========================================================================*/
releaseOfflineBuffers(bool allBuffers)924 int32_t QCamera3PostProcessor::releaseOfflineBuffers(bool allBuffers)
925 {
926     int32_t rc = NO_ERROR;
927 
928     if(NULL != m_pReprocChannel) {
929         rc = m_pReprocChannel->unmapOfflineBuffers(allBuffers);
930     }
931 
932     return rc;
933 }
934 
935 /*===========================================================================
936  * FUNCTION   : releaseJpegJobData
937  *
938  * DESCRIPTION: function to release internal resources in jpeg job struct
939  *
940  * PARAMETERS :
941  *   @job     : ptr to jpeg job struct
942  *
943  * RETURN     : None
944  *
945  * NOTE       : original source frame need to be queued back to kernel for
946  *              future use. Output buf of jpeg job need to be released since
947  *              it's allocated for each job. Exif object need to be deleted.
948  *==========================================================================*/
releaseJpegJobData(qcamera_hal3_jpeg_data_t * job)949 void QCamera3PostProcessor::releaseJpegJobData(qcamera_hal3_jpeg_data_t *job)
950 {
951     ATRACE_CALL();
952     int32_t rc = NO_ERROR;
953     LOGD("E");
954     if (NULL != job) {
955         if (NULL != job->src_reproc_frame) {
956             free(job->src_reproc_frame);
957             job->src_reproc_frame = NULL;
958         }
959 
960         if (NULL != job->src_frame) {
961             if (NULL != m_pReprocChannel) {
962                 rc = m_pReprocChannel->bufDone(job->src_frame);
963                 if (NO_ERROR != rc)
964                     LOGE("bufDone error: %d", rc);
965             }
966             free(job->src_frame);
967             job->src_frame = NULL;
968         }
969 
970         if (NULL != job->fwk_src_buffer) {
971             free(job->fwk_src_buffer);
972             job->fwk_src_buffer = NULL;
973         } else if (NULL != job->src_metadata) {
974             m_parent->metadataBufDone(job->src_metadata);
975             free(job->src_metadata);
976             job->src_metadata = NULL;
977         }
978 
979         if (NULL != job->fwk_frame) {
980             free(job->fwk_frame);
981             job->fwk_frame = NULL;
982         }
983 
984         if (NULL != job->pJpegExifObj) {
985             delete job->pJpegExifObj;
986             job->pJpegExifObj = NULL;
987         }
988 
989         if (NULL != job->jpeg_settings) {
990             free(job->jpeg_settings);
991             job->jpeg_settings = NULL;
992         }
993     }
994     /* Additional trigger to process any pending jobs in the input queue */
995     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
996     LOGD("X");
997 }
998 
999 /*===========================================================================
1000  * FUNCTION   : releasePPJobData
1001  *
1002  * DESCRIPTION: function to release internal resources in p pjob struct
1003  *
1004  * PARAMETERS :
1005  *   @job     : ptr to pp job struct
1006  *
1007  * RETURN     : None
1008  *
1009  * NOTE       : Original source metadata buffer needs to be released and
1010  *              queued back to kernel for future use. src_frame, src_metadata,
1011  *              and fwk_src_frame structures need to be freed.
1012  *==========================================================================*/
releasePPJobData(qcamera_hal3_pp_data_t * pp_job)1013 void QCamera3PostProcessor::releasePPJobData(qcamera_hal3_pp_data_t *pp_job)
1014 {
1015     ATRACE_CALL();
1016     LOGD("E");
1017     if (NULL != pp_job) {
1018         if (NULL != pp_job->src_frame) {
1019             free(pp_job->src_frame);
1020             if (NULL != pp_job->src_metadata) {
1021                 m_parent->metadataBufDone(pp_job->src_metadata);
1022                 free(pp_job->src_metadata);
1023             }
1024             pp_job->src_frame = NULL;
1025             pp_job->metadata = NULL;
1026         }
1027 
1028         if (NULL != pp_job->fwk_src_frame) {
1029             free(pp_job->fwk_src_frame);
1030             pp_job->fwk_src_frame = NULL;
1031         }
1032     }
1033 
1034     /* Additional trigger to process any pending jobs in the input queue */
1035     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
1036     LOGD("X");
1037 }
1038 
1039 /*===========================================================================
1040  * FUNCTION   : getColorfmtFromImgFmt
1041  *
1042  * DESCRIPTION: function to return jpeg color format based on its image format
1043  *
1044  * PARAMETERS :
1045  *   @img_fmt : image format
1046  *
1047  * RETURN     : jpeg color format that can be understandable by omx lib
1048  *==========================================================================*/
getColorfmtFromImgFmt(cam_format_t img_fmt)1049 mm_jpeg_color_format QCamera3PostProcessor::getColorfmtFromImgFmt(cam_format_t img_fmt)
1050 {
1051     switch (img_fmt) {
1052     case CAM_FORMAT_YUV_420_NV21:
1053     case CAM_FORMAT_YUV_420_NV21_VENUS:
1054         return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
1055     case CAM_FORMAT_YUV_420_NV21_ADRENO:
1056         return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
1057     case CAM_FORMAT_YUV_420_NV12:
1058     case CAM_FORMAT_YUV_420_NV12_VENUS:
1059         return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2;
1060     case CAM_FORMAT_YUV_420_YV12:
1061         return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2;
1062     case CAM_FORMAT_YUV_422_NV61:
1063         return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1;
1064     case CAM_FORMAT_YUV_422_NV16:
1065         return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1;
1066     default:
1067         return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
1068     }
1069 }
1070 
1071 /*===========================================================================
1072  * FUNCTION   : getJpegImgTypeFromImgFmt
1073  *
1074  * DESCRIPTION: function to return jpeg encode image type based on its image format
1075  *
1076  * PARAMETERS :
1077  *   @img_fmt : image format
1078  *
1079  * RETURN     : return jpeg source image format (YUV or Bitstream)
1080  *==========================================================================*/
getJpegImgTypeFromImgFmt(cam_format_t img_fmt)1081 mm_jpeg_format_t QCamera3PostProcessor::getJpegImgTypeFromImgFmt(cam_format_t img_fmt)
1082 {
1083     switch (img_fmt) {
1084     case CAM_FORMAT_YUV_420_NV21:
1085     case CAM_FORMAT_YUV_420_NV21_ADRENO:
1086     case CAM_FORMAT_YUV_420_NV12:
1087     case CAM_FORMAT_YUV_420_NV12_VENUS:
1088     case CAM_FORMAT_YUV_420_NV21_VENUS:
1089     case CAM_FORMAT_YUV_420_YV12:
1090     case CAM_FORMAT_YUV_422_NV61:
1091     case CAM_FORMAT_YUV_422_NV16:
1092         return MM_JPEG_FMT_YUV;
1093     default:
1094         return MM_JPEG_FMT_YUV;
1095     }
1096 }
1097 
1098 /*===========================================================================
1099  * FUNCTION   : encodeFWKData
1100  *
1101  * DESCRIPTION: function to prepare encoding job information and send to
1102  *              mm-jpeg-interface to do the encoding job
1103  *
1104  * PARAMETERS :
1105  *   @jpeg_job_data : ptr to a struct saving job related information
1106  *   @needNewSess   : flag to indicate if a new jpeg encoding session need
1107  *                    to be created. After creation, this flag will be toggled
1108  *
1109  * RETURN     : int32_t type of status
1110  *              NO_ERROR  -- success
1111  *              none-zero failure code
1112  *==========================================================================*/
encodeFWKData(qcamera_hal3_jpeg_data_t * jpeg_job_data,uint8_t & needNewSess)1113 int32_t QCamera3PostProcessor::encodeFWKData(qcamera_hal3_jpeg_data_t *jpeg_job_data,
1114         uint8_t &needNewSess)
1115 {
1116     LOGD("E");
1117     int32_t ret = NO_ERROR;
1118     mm_jpeg_job_t jpg_job;
1119     uint32_t jobId = 0;
1120     qcamera_fwk_input_pp_data_t *recvd_frame = NULL;
1121     metadata_buffer_t *metadata = NULL;
1122     jpeg_settings_t *jpeg_settings = NULL;
1123     QCamera3HardwareInterface* hal_obj = NULL;
1124     bool needJpegExifRotation = false;
1125 
1126     if (NULL == jpeg_job_data) {
1127         LOGE("Invalid jpeg job");
1128         return BAD_VALUE;
1129     }
1130 
1131     recvd_frame = jpeg_job_data->fwk_frame;
1132     if (NULL == recvd_frame) {
1133         LOGE("Invalid input buffer");
1134         return BAD_VALUE;
1135     }
1136 
1137     metadata = jpeg_job_data->metadata;
1138     if (NULL == metadata) {
1139         LOGE("Invalid metadata buffer");
1140         return BAD_VALUE;
1141     }
1142 
1143     jpeg_settings = jpeg_job_data->jpeg_settings;
1144     if (NULL == jpeg_settings) {
1145         LOGE("Invalid jpeg settings buffer");
1146         return BAD_VALUE;
1147     }
1148 
1149     if ((NULL != jpeg_job_data->src_frame) || (NULL != jpeg_job_data->src_reproc_frame)) {
1150         LOGE("Unsupported case either camera src_frame or src_reproc_frame is not NULL!");
1151         return BAD_VALUE;
1152     }
1153 
1154     hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
1155 
1156     if (mJpegClientHandle <= 0) {
1157         LOGE("Error: bug here, mJpegClientHandle is 0");
1158         return UNKNOWN_ERROR;
1159     }
1160 
1161     cam_dimension_t src_dim;
1162     memset(&src_dim, 0, sizeof(cam_dimension_t));
1163     src_dim.width = recvd_frame->reproc_config.input_stream_dim.width;
1164     src_dim.height = recvd_frame->reproc_config.input_stream_dim.height;
1165 
1166     cam_dimension_t dst_dim;
1167     memset(&dst_dim, 0, sizeof(cam_dimension_t));
1168     dst_dim.width = recvd_frame->reproc_config.output_stream_dim.width;
1169     dst_dim.height = recvd_frame->reproc_config.output_stream_dim.height;
1170 
1171     needJpegExifRotation = hal_obj->needJpegExifRotation();
1172 
1173     LOGH("Need new session?:%d", needNewSess);
1174     if (needNewSess) {
1175         //creating a new session, so we must destroy the old one
1176         if ( 0 < mJpegSessionId ) {
1177             ret = mJpegHandle.destroy_session(mJpegSessionId);
1178             if (ret != NO_ERROR) {
1179                 LOGE("Error destroying an old jpeg encoding session, id = %d",
1180                        mJpegSessionId);
1181                 return ret;
1182             }
1183             mJpegSessionId = 0;
1184         }
1185         // create jpeg encoding session
1186         mm_jpeg_encode_params_t encodeParam;
1187         memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t));
1188         encodeParam.main_dim.src_dim = src_dim;
1189         encodeParam.main_dim.dst_dim = dst_dim;
1190         encodeParam.thumb_dim.src_dim = src_dim;
1191         encodeParam.thumb_dim.dst_dim = jpeg_settings->thumbnail_size;
1192 
1193         if (needJpegExifRotation) {
1194             encodeParam.thumb_rotation = (uint32_t)jpeg_settings->jpeg_orientation;
1195         }
1196 
1197         getFWKJpegEncodeConfig(encodeParam, recvd_frame, jpeg_settings);
1198         LOGH("#src bufs:%d # tmb bufs:%d #dst_bufs:%d",
1199                      encodeParam.num_src_bufs,encodeParam.num_tmb_bufs,encodeParam.num_dst_bufs);
1200 
1201         ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId);
1202         if (ret != NO_ERROR) {
1203             LOGE("Error creating a new jpeg encoding session, ret = %d", ret);
1204             return ret;
1205         }
1206         needNewSess = FALSE;
1207     }
1208 
1209     // Fill in new job
1210     memset(&jpg_job, 0, sizeof(mm_jpeg_job_t));
1211     jpg_job.job_type = JPEG_JOB_TYPE_ENCODE;
1212     jpg_job.encode_job.session_id = mJpegSessionId;
1213     jpg_job.encode_job.src_index = 0;
1214     jpg_job.encode_job.dst_index = 0;
1215 
1216     cam_rect_t crop;
1217     memset(&crop, 0, sizeof(cam_rect_t));
1218     //TBD_later - Zoom event removed in stream
1219     //main_stream->getCropInfo(crop);
1220 
1221     // Set main dim job parameters and handle rotation
1222     if (!needJpegExifRotation && (jpeg_settings->jpeg_orientation == 90 ||
1223             jpeg_settings->jpeg_orientation == 270)) {
1224 
1225         jpg_job.encode_job.main_dim.src_dim.width = src_dim.height;
1226         jpg_job.encode_job.main_dim.src_dim.height = src_dim.width;
1227 
1228         jpg_job.encode_job.main_dim.dst_dim.width = dst_dim.height;
1229         jpg_job.encode_job.main_dim.dst_dim.height = dst_dim.width;
1230 
1231         jpg_job.encode_job.main_dim.crop.width = crop.height;
1232         jpg_job.encode_job.main_dim.crop.height = crop.width;
1233         jpg_job.encode_job.main_dim.crop.left = crop.top;
1234         jpg_job.encode_job.main_dim.crop.top = crop.left;
1235     } else {
1236         jpg_job.encode_job.main_dim.src_dim = src_dim;
1237         jpg_job.encode_job.main_dim.dst_dim = dst_dim;
1238         jpg_job.encode_job.main_dim.crop = crop;
1239     }
1240 
1241     QCamera3HardwareInterface* obj = (QCamera3HardwareInterface*)m_parent->mUserData;
1242     // get 3a sw version info
1243     cam_q3a_version_t sw_version;
1244     memset(&sw_version, 0, sizeof(sw_version));
1245     if (obj)
1246         obj->get3AVersion(sw_version);
1247 
1248     // get exif data
1249     QCamera3Exif *pJpegExifObj = getExifData(metadata, jpeg_settings);
1250     jpeg_job_data->pJpegExifObj = pJpegExifObj;
1251     if (pJpegExifObj != NULL) {
1252         jpg_job.encode_job.exif_info.exif_data = pJpegExifObj->getEntries();
1253         jpg_job.encode_job.exif_info.numOfEntries =
1254             pJpegExifObj->getNumOfEntries();
1255         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[0] =
1256             sw_version.major_version;
1257         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[1] =
1258             sw_version.minor_version;
1259         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[2] =
1260             sw_version.patch_version;
1261         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[3] =
1262             sw_version.new_feature_des;
1263     }
1264 
1265     // thumbnail dim
1266     LOGH("Thumbnail needed:%d", m_bThumbnailNeeded);
1267     if (m_bThumbnailNeeded == TRUE) {
1268         memset(&crop, 0, sizeof(cam_rect_t));
1269         jpg_job.encode_job.thumb_dim.dst_dim =
1270                 jpeg_settings->thumbnail_size;
1271 
1272         if (!needJpegExifRotation && (jpeg_settings->jpeg_orientation == 90 ||
1273                 jpeg_settings->jpeg_orientation == 270)) {
1274             //swap the thumbnail destination width and height if it has
1275             //already been rotated
1276             int temp = jpg_job.encode_job.thumb_dim.dst_dim.width;
1277             jpg_job.encode_job.thumb_dim.dst_dim.width =
1278                     jpg_job.encode_job.thumb_dim.dst_dim.height;
1279             jpg_job.encode_job.thumb_dim.dst_dim.height = temp;
1280         }
1281         jpg_job.encode_job.thumb_dim.src_dim = src_dim;
1282         jpg_job.encode_job.thumb_dim.crop = crop;
1283         jpg_job.encode_job.thumb_index = 0;
1284     }
1285 
1286     if (metadata != NULL) {
1287        //Fill in the metadata passed as parameter
1288        jpg_job.encode_job.p_metadata = metadata;
1289     } else {
1290        LOGW("Metadata is null");
1291     }
1292 
1293     jpg_job.encode_job.hal_version = CAM_HAL_V3;
1294 
1295     //Start jpeg encoding
1296     ret = mJpegHandle.start_job(&jpg_job, &jobId);
1297     if (ret == NO_ERROR) {
1298         // remember job info
1299         jpeg_job_data->jobId = jobId;
1300     }
1301 
1302     LOGD("X");
1303     return ret;
1304 }
1305 
1306 /*===========================================================================
1307  * FUNCTION   : encodeData
1308  *
1309  * DESCRIPTION: function to prepare encoding job information and send to
1310  *              mm-jpeg-interface to do the encoding job
1311  *
1312  * PARAMETERS :
1313  *   @jpeg_job_data : ptr to a struct saving job related information
1314  *   @needNewSess   : flag to indicate if a new jpeg encoding session need
1315  *                    to be created. After creation, this flag will be toggled
1316  *
1317  * RETURN     : int32_t type of status
1318  *              NO_ERROR  -- success
1319  *              none-zero failure code
1320  *==========================================================================*/
encodeData(qcamera_hal3_jpeg_data_t * jpeg_job_data,uint8_t & needNewSess)1321 int32_t QCamera3PostProcessor::encodeData(qcamera_hal3_jpeg_data_t *jpeg_job_data,
1322                           uint8_t &needNewSess)
1323 {
1324     ATRACE_CALL();
1325     LOGD("E");
1326     int32_t ret = NO_ERROR;
1327     mm_jpeg_job_t jpg_job;
1328     uint32_t jobId = 0;
1329     QCamera3Stream *main_stream = NULL;
1330     mm_camera_buf_def_t *main_frame = NULL;
1331     QCamera3Channel *srcChannel = NULL;
1332     mm_camera_super_buf_t *recvd_frame = NULL;
1333     metadata_buffer_t *metadata = NULL;
1334     jpeg_settings_t *jpeg_settings = NULL;
1335     QCamera3HardwareInterface* hal_obj = NULL;
1336     mm_jpeg_debug_exif_params_t *exif_debug_params = NULL;
1337     if (m_parent != NULL) {
1338        hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
1339     } else {
1340        LOGE("m_parent is NULL, Error");
1341        return BAD_VALUE;
1342     }
1343     bool needJpegExifRotation = false;
1344 
1345     recvd_frame = jpeg_job_data->src_frame;
1346     metadata = jpeg_job_data->metadata;
1347     jpeg_settings = jpeg_job_data->jpeg_settings;
1348 
1349     LOGD("encoding bufIndex: %u",
1350         jpeg_job_data->src_frame->bufs[0]->buf_idx);
1351 
1352     QCamera3Channel *pChannel = NULL;
1353     // first check picture channel
1354     if (m_parent->getMyHandle() == recvd_frame->ch_id) {
1355         pChannel = m_parent;
1356     }
1357     // check reprocess channel if not found
1358     if (pChannel == NULL) {
1359         if (m_pReprocChannel != NULL &&
1360             m_pReprocChannel->getMyHandle() == recvd_frame->ch_id) {
1361             pChannel = m_pReprocChannel;
1362         }
1363     }
1364 
1365     srcChannel = pChannel;
1366 
1367     if (srcChannel == NULL) {
1368         LOGE("No corresponding channel (ch_id = %d) exist, return here",
1369                recvd_frame->ch_id);
1370         return BAD_VALUE;
1371     }
1372 
1373     // find snapshot frame and thumnail frame
1374     //Note: In this version we will receive only snapshot frame.
1375     for (uint32_t i = 0; i < recvd_frame->num_bufs; i++) {
1376         QCamera3Stream *srcStream =
1377             srcChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id);
1378         if (srcStream != NULL) {
1379             switch (srcStream->getMyType()) {
1380             case CAM_STREAM_TYPE_SNAPSHOT:
1381             case CAM_STREAM_TYPE_OFFLINE_PROC:
1382                 main_stream = srcStream;
1383                 main_frame = recvd_frame->bufs[i];
1384                 break;
1385             default:
1386                 break;
1387             }
1388         }
1389     }
1390 
1391     if(NULL == main_frame){
1392        LOGE("Main frame is NULL");
1393        return BAD_VALUE;
1394     }
1395 
1396     QCamera3StreamMem *memObj = (QCamera3StreamMem *)main_frame->mem_info;
1397     if (NULL == memObj) {
1398         LOGE("Memeory Obj of main frame is NULL");
1399         return NO_MEMORY;
1400     }
1401 
1402     // clean and invalidate cache ops through mem obj of the frame
1403     memObj->cleanInvalidateCache(main_frame->buf_idx);
1404 
1405     if (mJpegClientHandle <= 0) {
1406         LOGE("Error: bug here, mJpegClientHandle is 0");
1407         return UNKNOWN_ERROR;
1408     }
1409     cam_dimension_t src_dim;
1410     memset(&src_dim, 0, sizeof(cam_dimension_t));
1411     main_stream->getFrameDimension(src_dim);
1412 
1413     cam_dimension_t dst_dim;
1414     memset(&dst_dim, 0, sizeof(cam_dimension_t));
1415     if (NO_ERROR != m_parent->getStreamSize(dst_dim)) {
1416         LOGE("Failed to get size of the JPEG stream");
1417         return UNKNOWN_ERROR;
1418     }
1419 
1420     needJpegExifRotation = hal_obj->needJpegExifRotation();
1421     LOGH("Need new session?:%d", needNewSess);
1422     if (needNewSess) {
1423         //creating a new session, so we must destroy the old one
1424         if ( 0 < mJpegSessionId ) {
1425             ret = mJpegHandle.destroy_session(mJpegSessionId);
1426             if (ret != NO_ERROR) {
1427                 LOGE("Error destroying an old jpeg encoding session, id = %d",
1428                        mJpegSessionId);
1429                 return ret;
1430             }
1431             mJpegSessionId = 0;
1432         }
1433         // create jpeg encoding session
1434         mm_jpeg_encode_params_t encodeParam;
1435         memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t));
1436         getJpegEncodeConfig(encodeParam, main_stream, jpeg_settings);
1437         LOGH("#src bufs:%d # tmb bufs:%d #dst_bufs:%d",
1438                      encodeParam.num_src_bufs,encodeParam.num_tmb_bufs,encodeParam.num_dst_bufs);
1439         if (!needJpegExifRotation &&
1440             (jpeg_settings->jpeg_orientation == 90 ||
1441             jpeg_settings->jpeg_orientation == 270)) {
1442            //swap src width and height, stride and scanline due to rotation
1443            encodeParam.main_dim.src_dim.width = src_dim.height;
1444            encodeParam.main_dim.src_dim.height = src_dim.width;
1445            encodeParam.thumb_dim.src_dim.width = src_dim.height;
1446            encodeParam.thumb_dim.src_dim.height = src_dim.width;
1447 
1448            int32_t temp = encodeParam.src_main_buf[0].offset.mp[0].stride;
1449            encodeParam.src_main_buf[0].offset.mp[0].stride =
1450               encodeParam.src_main_buf[0].offset.mp[0].scanline;
1451            encodeParam.src_main_buf[0].offset.mp[0].scanline = temp;
1452 
1453            temp = encodeParam.src_thumb_buf[0].offset.mp[0].stride;
1454            encodeParam.src_thumb_buf[0].offset.mp[0].stride =
1455               encodeParam.src_thumb_buf[0].offset.mp[0].scanline;
1456            encodeParam.src_thumb_buf[0].offset.mp[0].scanline = temp;
1457         } else {
1458            encodeParam.main_dim.src_dim  = src_dim;
1459            encodeParam.thumb_dim.src_dim = src_dim;
1460         }
1461         encodeParam.main_dim.dst_dim = dst_dim;
1462         encodeParam.thumb_dim.dst_dim = jpeg_settings->thumbnail_size;
1463 
1464         if (needJpegExifRotation) {
1465             encodeParam.thumb_rotation = (uint32_t)jpeg_settings->jpeg_orientation;
1466         }
1467 
1468         LOGI("Src Buffer cnt = %d, res = %dX%d len = %d rot = %d "
1469             "src_dim = %dX%d dst_dim = %dX%d",
1470             encodeParam.num_src_bufs,
1471             encodeParam.src_main_buf[0].offset.mp[0].stride,
1472             encodeParam.src_main_buf[0].offset.mp[0].scanline,
1473             encodeParam.src_main_buf[0].offset.frame_len,
1474             encodeParam.rotation,
1475             src_dim.width, src_dim.height,
1476             dst_dim.width, dst_dim.height);
1477         LOGI("Src THUMB buf_cnt = %d, res = %dX%d len = %d rot = %d "
1478             "src_dim = %dX%d, dst_dim = %dX%d",
1479             encodeParam.num_tmb_bufs,
1480             encodeParam.src_thumb_buf[0].offset.mp[0].stride,
1481             encodeParam.src_thumb_buf[0].offset.mp[0].scanline,
1482             encodeParam.src_thumb_buf[0].offset.frame_len,
1483             encodeParam.thumb_rotation,
1484             encodeParam.thumb_dim.src_dim.width,
1485             encodeParam.thumb_dim.src_dim.height,
1486             encodeParam.thumb_dim.dst_dim.width,
1487             encodeParam.thumb_dim.dst_dim.height);
1488         ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId);
1489         if (ret != NO_ERROR) {
1490             LOGE("Error creating a new jpeg encoding session, ret = %d", ret);
1491             return ret;
1492         }
1493         needNewSess = FALSE;
1494     }
1495 
1496     // Fill in new job
1497     memset(&jpg_job, 0, sizeof(mm_jpeg_job_t));
1498     jpg_job.job_type = JPEG_JOB_TYPE_ENCODE;
1499     jpg_job.encode_job.session_id = mJpegSessionId;
1500     jpg_job.encode_job.src_index = (int32_t)main_frame->buf_idx;
1501     jpg_job.encode_job.dst_index = 0;
1502 
1503     cam_rect_t crop;
1504     memset(&crop, 0, sizeof(cam_rect_t));
1505     //TBD_later - Zoom event removed in stream
1506     //main_stream->getCropInfo(crop);
1507 
1508     // Set main dim job parameters and handle rotation
1509     if (!needJpegExifRotation && (jpeg_settings->jpeg_orientation == 90 ||
1510             jpeg_settings->jpeg_orientation == 270)) {
1511 
1512         jpg_job.encode_job.main_dim.src_dim.width = src_dim.height;
1513         jpg_job.encode_job.main_dim.src_dim.height = src_dim.width;
1514 
1515         jpg_job.encode_job.main_dim.dst_dim.width = dst_dim.height;
1516         jpg_job.encode_job.main_dim.dst_dim.height = dst_dim.width;
1517 
1518         jpg_job.encode_job.main_dim.crop.width = crop.height;
1519         jpg_job.encode_job.main_dim.crop.height = crop.width;
1520         jpg_job.encode_job.main_dim.crop.left = crop.top;
1521         jpg_job.encode_job.main_dim.crop.top = crop.left;
1522     } else {
1523         jpg_job.encode_job.main_dim.src_dim = src_dim;
1524         jpg_job.encode_job.main_dim.dst_dim = dst_dim;
1525         jpg_job.encode_job.main_dim.crop = crop;
1526     }
1527 
1528     QCamera3HardwareInterface* obj = (QCamera3HardwareInterface*)m_parent->mUserData;
1529     // get 3a sw version info
1530     cam_q3a_version_t sw_version;
1531     memset(&sw_version, 0, sizeof(sw_version));
1532 
1533     if (obj)
1534         obj->get3AVersion(sw_version);
1535 
1536     // get exif data
1537     QCamera3Exif *pJpegExifObj = getExifData(metadata, jpeg_settings);
1538     jpeg_job_data->pJpegExifObj = pJpegExifObj;
1539     if (pJpegExifObj != NULL) {
1540         jpg_job.encode_job.exif_info.exif_data = pJpegExifObj->getEntries();
1541         jpg_job.encode_job.exif_info.numOfEntries =
1542             pJpegExifObj->getNumOfEntries();
1543         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[0] =
1544             sw_version.major_version;
1545         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[1] =
1546             sw_version.minor_version;
1547         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[2] =
1548             sw_version.patch_version;
1549         jpg_job.encode_job.exif_info.debug_data.sw_3a_version[3] =
1550             sw_version.new_feature_des;
1551     }
1552 
1553     // thumbnail dim
1554     LOGH("Thumbnail needed:%d", m_bThumbnailNeeded);
1555     if (m_bThumbnailNeeded == TRUE) {
1556         memset(&crop, 0, sizeof(cam_rect_t));
1557         jpg_job.encode_job.thumb_dim.dst_dim =
1558                 jpeg_settings->thumbnail_size;
1559 
1560       if (!needJpegExifRotation &&
1561           (jpeg_settings->jpeg_orientation  == 90 ||
1562            jpeg_settings->jpeg_orientation == 270)) {
1563             //swap the thumbnail destination width and height if it has
1564             //already been rotated
1565             int temp = jpg_job.encode_job.thumb_dim.dst_dim.width;
1566             jpg_job.encode_job.thumb_dim.dst_dim.width =
1567                     jpg_job.encode_job.thumb_dim.dst_dim.height;
1568             jpg_job.encode_job.thumb_dim.dst_dim.height = temp;
1569 
1570             jpg_job.encode_job.thumb_dim.src_dim.width = src_dim.height;
1571             jpg_job.encode_job.thumb_dim.src_dim.height = src_dim.width;
1572         } else {
1573            jpg_job.encode_job.thumb_dim.src_dim = src_dim;
1574         }
1575         jpg_job.encode_job.thumb_dim.crop = crop;
1576         jpg_job.encode_job.thumb_index = main_frame->buf_idx;
1577         LOGI("Thumbnail idx = %d src w/h (%dx%d), dst w/h (%dx%d)",
1578                 jpg_job.encode_job.thumb_index,
1579                 jpg_job.encode_job.thumb_dim.src_dim.width,
1580                 jpg_job.encode_job.thumb_dim.src_dim.height,
1581                 jpg_job.encode_job.thumb_dim.dst_dim.width,
1582                 jpg_job.encode_job.thumb_dim.dst_dim.height);
1583     }
1584     LOGI("Main image idx = %d src w/h (%dx%d), dst w/h (%dx%d)",
1585             jpg_job.encode_job.src_index,
1586             jpg_job.encode_job.main_dim.src_dim.width,
1587             jpg_job.encode_job.main_dim.src_dim.height,
1588             jpg_job.encode_job.main_dim.dst_dim.width,
1589             jpg_job.encode_job.main_dim.dst_dim.height);
1590 
1591     jpg_job.encode_job.cam_exif_params = hal_obj->get3AExifParams();
1592     exif_debug_params = jpg_job.encode_job.cam_exif_params.debug_params;
1593 
1594     // Allocate for a local copy of debug parameters
1595     jpg_job.encode_job.cam_exif_params.debug_params =
1596             (mm_jpeg_debug_exif_params_t *) malloc (sizeof(mm_jpeg_debug_exif_params_t));
1597     if (!jpg_job.encode_job.cam_exif_params.debug_params) {
1598         LOGE("Out of Memory. Allocation failed for 3A debug exif params");
1599         return NO_MEMORY;
1600     }
1601 
1602     jpg_job.encode_job.mobicat_mask = hal_obj->getMobicatMask();
1603 
1604     if (metadata != NULL) {
1605        //Fill in the metadata passed as parameter
1606        jpg_job.encode_job.p_metadata = metadata;
1607 
1608        jpg_job.encode_job.p_metadata->is_mobicat_aec_params_valid =
1609                 jpg_job.encode_job.cam_exif_params.cam_3a_params_valid;
1610 
1611        if (jpg_job.encode_job.cam_exif_params.cam_3a_params_valid) {
1612             jpg_job.encode_job.p_metadata->mobicat_aec_params =
1613                 jpg_job.encode_job.cam_exif_params.cam_3a_params;
1614        }
1615 
1616        if (exif_debug_params) {
1617             // Copy debug parameters locally.
1618            memcpy(jpg_job.encode_job.cam_exif_params.debug_params,
1619                    exif_debug_params, (sizeof(mm_jpeg_debug_exif_params_t)));
1620            /* Save a copy of 3A debug params */
1621             jpg_job.encode_job.p_metadata->is_statsdebug_ae_params_valid =
1622                     jpg_job.encode_job.cam_exif_params.debug_params->ae_debug_params_valid;
1623             jpg_job.encode_job.p_metadata->is_statsdebug_awb_params_valid =
1624                     jpg_job.encode_job.cam_exif_params.debug_params->awb_debug_params_valid;
1625             jpg_job.encode_job.p_metadata->is_statsdebug_af_params_valid =
1626                     jpg_job.encode_job.cam_exif_params.debug_params->af_debug_params_valid;
1627             jpg_job.encode_job.p_metadata->is_statsdebug_asd_params_valid =
1628                     jpg_job.encode_job.cam_exif_params.debug_params->asd_debug_params_valid;
1629             jpg_job.encode_job.p_metadata->is_statsdebug_stats_params_valid =
1630                     jpg_job.encode_job.cam_exif_params.debug_params->stats_debug_params_valid;
1631             jpg_job.encode_job.p_metadata->is_statsdebug_bestats_params_valid =
1632                     jpg_job.encode_job.cam_exif_params.debug_params->bestats_debug_params_valid;
1633             jpg_job.encode_job.p_metadata->is_statsdebug_bhist_params_valid =
1634                     jpg_job.encode_job.cam_exif_params.debug_params->bhist_debug_params_valid;
1635             jpg_job.encode_job.p_metadata->is_statsdebug_3a_tuning_params_valid =
1636                     jpg_job.encode_job.cam_exif_params.debug_params->q3a_tuning_debug_params_valid;
1637 
1638             if (jpg_job.encode_job.cam_exif_params.debug_params->ae_debug_params_valid) {
1639                 jpg_job.encode_job.p_metadata->statsdebug_ae_data =
1640                         jpg_job.encode_job.cam_exif_params.debug_params->ae_debug_params;
1641             }
1642             if (jpg_job.encode_job.cam_exif_params.debug_params->awb_debug_params_valid) {
1643                 jpg_job.encode_job.p_metadata->statsdebug_awb_data =
1644                         jpg_job.encode_job.cam_exif_params.debug_params->awb_debug_params;
1645             }
1646             if (jpg_job.encode_job.cam_exif_params.debug_params->af_debug_params_valid) {
1647                 jpg_job.encode_job.p_metadata->statsdebug_af_data =
1648                         jpg_job.encode_job.cam_exif_params.debug_params->af_debug_params;
1649             }
1650             if (jpg_job.encode_job.cam_exif_params.debug_params->asd_debug_params_valid) {
1651                 jpg_job.encode_job.p_metadata->statsdebug_asd_data =
1652                         jpg_job.encode_job.cam_exif_params.debug_params->asd_debug_params;
1653             }
1654             if (jpg_job.encode_job.cam_exif_params.debug_params->stats_debug_params_valid) {
1655                 jpg_job.encode_job.p_metadata->statsdebug_stats_buffer_data =
1656                         jpg_job.encode_job.cam_exif_params.debug_params->stats_debug_params;
1657             }
1658             if (jpg_job.encode_job.cam_exif_params.debug_params->bestats_debug_params_valid) {
1659                 jpg_job.encode_job.p_metadata->statsdebug_bestats_buffer_data =
1660                         jpg_job.encode_job.cam_exif_params.debug_params->bestats_debug_params;
1661             }
1662             if (jpg_job.encode_job.cam_exif_params.debug_params->bhist_debug_params_valid) {
1663                 jpg_job.encode_job.p_metadata->statsdebug_bhist_data =
1664                         jpg_job.encode_job.cam_exif_params.debug_params->bhist_debug_params;
1665             }
1666             if (jpg_job.encode_job.cam_exif_params.debug_params->q3a_tuning_debug_params_valid) {
1667                 jpg_job.encode_job.p_metadata->statsdebug_3a_tuning_data =
1668                         jpg_job.encode_job.cam_exif_params.debug_params->q3a_tuning_debug_params;
1669             }
1670         }
1671     } else {
1672        LOGW("Metadata is null");
1673     }
1674 
1675     jpg_job.encode_job.hal_version = CAM_HAL_V3;
1676 
1677     //Start jpeg encoding
1678     ret = mJpegHandle.start_job(&jpg_job, &jobId);
1679     if (jpg_job.encode_job.cam_exif_params.debug_params) {
1680         free(jpg_job.encode_job.cam_exif_params.debug_params);
1681     }
1682     if (ret == NO_ERROR) {
1683         // remember job info
1684         jpeg_job_data->jobId = jobId;
1685     }
1686 
1687     LOGD("X");
1688     return ret;
1689 }
1690 
1691 /*===========================================================================
1692  * FUNCTION   : dataProcessRoutine
1693  *
1694  * DESCRIPTION: data process routine that handles input data either from input
1695  *              Jpeg Queue to do jpeg encoding, or from input PP Queue to do
1696  *              reprocess.
1697  *
1698  * PARAMETERS :
1699  *   @data    : user data ptr (QCamera3PostProcessor)
1700  *
1701  * RETURN     : None
1702  *==========================================================================*/
dataProcessRoutine(void * data)1703 void *QCamera3PostProcessor::dataProcessRoutine(void *data)
1704 {
1705     int running = 1;
1706     int ret;
1707     uint8_t is_active = FALSE;
1708     uint8_t needNewSess = TRUE;
1709     mm_camera_super_buf_t *meta_buffer = NULL;
1710     LOGD("E");
1711     QCamera3PostProcessor *pme = (QCamera3PostProcessor *)data;
1712     QCameraCmdThread *cmdThread = &pme->m_dataProcTh;
1713     cmdThread->setName("cam_data_proc");
1714 
1715     do {
1716         do {
1717             ret = cam_sem_wait(&cmdThread->cmd_sem);
1718             if (ret != 0 && errno != EINVAL) {
1719                 LOGE("cam_sem_wait error (%s)",
1720                             strerror(errno));
1721                 return NULL;
1722             }
1723         } while (ret != 0);
1724 
1725         // we got notified about new cmd avail in cmd queue
1726         camera_cmd_type_t cmd = cmdThread->getCmd();
1727         switch (cmd) {
1728         case CAMERA_CMD_TYPE_START_DATA_PROC:
1729             LOGH("start data proc");
1730             is_active = TRUE;
1731             needNewSess = TRUE;
1732 
1733             pme->m_ongoingPPQ.init();
1734             pme->m_inputJpegQ.init();
1735             pme->m_inputPPQ.init();
1736             pme->m_inputFWKPPQ.init();
1737             pme->m_inputMetaQ.init();
1738             cam_sem_post(&cmdThread->sync_sem);
1739 
1740             break;
1741         case CAMERA_CMD_TYPE_STOP_DATA_PROC:
1742             {
1743                 LOGH("stop data proc");
1744                 is_active = FALSE;
1745 
1746                 // cancel all ongoing jpeg jobs
1747                 qcamera_hal3_jpeg_data_t *jpeg_job =
1748                     (qcamera_hal3_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
1749                 while (jpeg_job != NULL) {
1750                     pme->mJpegHandle.abort_job(jpeg_job->jobId);
1751 
1752                     pme->releaseJpegJobData(jpeg_job);
1753                     free(jpeg_job);
1754 
1755                     jpeg_job = (qcamera_hal3_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
1756                 }
1757 
1758                 // destroy jpeg encoding session
1759                 if ( 0 < pme->mJpegSessionId ) {
1760                     pme->mJpegHandle.destroy_session(pme->mJpegSessionId);
1761                     pme->mJpegSessionId = 0;
1762                 }
1763 
1764                 needNewSess = TRUE;
1765 
1766                 // flush ongoing postproc Queue
1767                 pme->m_ongoingPPQ.flush();
1768 
1769                 // flush input jpeg Queue
1770                 pme->m_inputJpegQ.flush();
1771 
1772                 // flush input Postproc Queue
1773                 pme->m_inputPPQ.flush();
1774 
1775                 // flush framework input Postproc Queue
1776                 pme->m_inputFWKPPQ.flush();
1777 
1778                 pme->m_inputMetaQ.flush();
1779 
1780                 // signal cmd is completed
1781                 cam_sem_post(&cmdThread->sync_sem);
1782             }
1783             break;
1784         case CAMERA_CMD_TYPE_DO_NEXT_JOB:
1785             {
1786                 LOGH("Do next job, active is %d", is_active);
1787                 /* needNewSess is set to TRUE as postproc is not re-STARTed
1788                  * anymore for every captureRequest */
1789                 needNewSess = TRUE;
1790                 if (is_active == TRUE) {
1791                     // check if there is any ongoing jpeg jobs
1792                     if (pme->m_ongoingJpegQ.isEmpty()) {
1793                         LOGD("ongoing jpeg queue is empty so doing the jpeg job");
1794                         // no ongoing jpeg job, we are fine to send jpeg encoding job
1795                         qcamera_hal3_jpeg_data_t *jpeg_job =
1796                             (qcamera_hal3_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
1797 
1798                         if (NULL != jpeg_job) {
1799                             // add into ongoing jpeg job Q
1800                             pme->m_ongoingJpegQ.enqueue((void *)jpeg_job);
1801 
1802                             if (jpeg_job->fwk_frame) {
1803                                 ret = pme->encodeFWKData(jpeg_job, needNewSess);
1804                             } else {
1805                                 ret = pme->encodeData(jpeg_job, needNewSess);
1806                             }
1807                             if (NO_ERROR != ret) {
1808                                 // dequeue the last one
1809                                 pme->m_ongoingJpegQ.dequeue(false);
1810 
1811                                 pme->releaseJpegJobData(jpeg_job);
1812                                 free(jpeg_job);
1813                             }
1814                         }
1815                     }
1816 
1817                     // check if there are any framework pp jobs
1818                     if (!pme->m_inputFWKPPQ.isEmpty()) {
1819                         qcamera_fwk_input_pp_data_t *fwk_frame =
1820                                 (qcamera_fwk_input_pp_data_t *) pme->m_inputFWKPPQ.dequeue();
1821                         if (NULL != fwk_frame) {
1822                             qcamera_hal3_pp_data_t *pp_job =
1823                                     (qcamera_hal3_pp_data_t *)malloc(sizeof(qcamera_hal3_pp_data_t));
1824                             jpeg_settings_t *jpeg_settings =
1825                                     (jpeg_settings_t *)pme->m_jpegSettingsQ.dequeue();
1826                             if (pp_job != NULL) {
1827                                 memset(pp_job, 0, sizeof(qcamera_hal3_pp_data_t));
1828                                 pp_job->jpeg_settings = jpeg_settings;
1829                                 if (pme->m_pReprocChannel != NULL) {
1830                                     if (NO_ERROR != pme->m_pReprocChannel->overrideFwkMetadata(fwk_frame)) {
1831                                         LOGE("Failed to extract output crop");
1832                                     }
1833                                     // add into ongoing PP job Q
1834                                     pp_job->fwk_src_frame = fwk_frame;
1835                                     pme->m_ongoingPPQ.enqueue((void *)pp_job);
1836                                     ret = pme->m_pReprocChannel->doReprocessOffline(fwk_frame, true);
1837                                     if (NO_ERROR != ret) {
1838                                         // remove from ongoing PP job Q
1839                                         pme->m_ongoingPPQ.dequeue(false);
1840                                     }
1841                                 } else {
1842                                     LOGE("Reprocess channel is NULL");
1843                                     ret = -1;
1844                                 }
1845                             } else {
1846                                 LOGE("no mem for qcamera_hal3_pp_data_t");
1847                                 ret = -1;
1848                             }
1849 
1850                             if (0 != ret) {
1851                                 // free pp_job
1852                                 if (pp_job != NULL) {
1853                                     free(pp_job);
1854                                 }
1855                                 // free frame
1856                                 if (fwk_frame != NULL) {
1857                                     free(fwk_frame);
1858                                 }
1859                             }
1860                         }
1861                     }
1862 
1863                     LOGH("dequeuing pp frame");
1864                     pthread_mutex_lock(&pme->mReprocJobLock);
1865                     if(!pme->m_inputPPQ.isEmpty() && !pme->m_inputMetaQ.isEmpty()) {
1866                         qcamera_hal3_pp_buffer_t *pp_buffer =
1867                             (qcamera_hal3_pp_buffer_t *)pme->m_inputPPQ.dequeue();
1868                         meta_buffer =
1869                             (mm_camera_super_buf_t *)pme->m_inputMetaQ.dequeue();
1870                         jpeg_settings_t *jpeg_settings =
1871                            (jpeg_settings_t *)pme->m_jpegSettingsQ.dequeue();
1872                         pthread_mutex_unlock(&pme->mReprocJobLock);
1873                         qcamera_hal3_pp_data_t *pp_job =
1874                             (qcamera_hal3_pp_data_t *)malloc(sizeof(qcamera_hal3_pp_data_t));
1875                         if (pp_job == NULL) {
1876                             LOGE("no mem for qcamera_hal3_pp_data_t");
1877                             ret = -1;
1878                         } else if (meta_buffer == NULL) {
1879                             LOGE("failed to dequeue from m_inputMetaQ");
1880                             ret = -1;
1881                         } else if (pp_buffer == NULL) {
1882                             LOGE("failed to dequeue from m_inputPPQ");
1883                             ret = -1;
1884                         } else if (pp_buffer != NULL){
1885                             memset(pp_job, 0, sizeof(qcamera_hal3_pp_data_t));
1886                             pp_job->src_frame = pp_buffer->input;
1887                             pp_job->src_metadata = meta_buffer;
1888                             if (meta_buffer->bufs[0] != NULL) {
1889                                 pp_job->metadata = (metadata_buffer_t *)
1890                                         meta_buffer->bufs[0]->buffer;
1891                             }
1892                             pp_job->jpeg_settings = jpeg_settings;
1893                             pme->m_ongoingPPQ.enqueue((void *)pp_job);
1894                             if (pme->m_pReprocChannel != NULL) {
1895                                 mm_camera_buf_def_t *meta_buffer_arg = NULL;
1896                                 meta_buffer_arg = meta_buffer->bufs[0];
1897                                 qcamera_fwk_input_pp_data_t fwk_frame;
1898                                 memset(&fwk_frame, 0, sizeof(qcamera_fwk_input_pp_data_t));
1899                                 fwk_frame.frameNumber = pp_buffer->frameNumber;
1900                                 ret = pme->m_pReprocChannel->overrideMetadata(
1901                                         pp_buffer, meta_buffer_arg,
1902                                         pp_job->jpeg_settings,
1903                                         fwk_frame);
1904                                 if (NO_ERROR == ret) {
1905                                     // add into ongoing PP job Q
1906                                     ret = pme->m_pReprocChannel->doReprocessOffline(
1907                                             &fwk_frame, true);
1908                                     if (NO_ERROR != ret) {
1909                                         // remove from ongoing PP job Q
1910                                         pme->m_ongoingPPQ.dequeue(false);
1911                                     }
1912                                 }
1913                             } else {
1914                                 LOGE("No reprocess. Calling processPPData directly");
1915                                 ret = pme->processPPData(pp_buffer->input);
1916                             }
1917                         }
1918 
1919                         if (0 != ret) {
1920                             // free pp_job
1921                             if (pp_job != NULL) {
1922                                 free(pp_job);
1923                             }
1924                             // free frame
1925                             if (pp_buffer != NULL) {
1926                                 if (pp_buffer->input) {
1927                                     pme->releaseSuperBuf(pp_buffer->input);
1928                                     free(pp_buffer->input);
1929                                 }
1930                                 free(pp_buffer);
1931                             }
1932                             //free metadata
1933                             if (NULL != meta_buffer) {
1934                                 pme->m_parent->metadataBufDone(meta_buffer);
1935                                 free(meta_buffer);
1936                             }
1937                         } else {
1938                             if (pp_buffer != NULL) {
1939                                 free(pp_buffer);
1940                             }
1941                         }
1942                     } else {
1943                         pthread_mutex_unlock(&pme->mReprocJobLock);
1944                     }
1945                 } else {
1946                     // not active, simply return buf and do no op
1947                     qcamera_hal3_jpeg_data_t *jpeg_job =
1948                         (qcamera_hal3_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
1949                     if (NULL != jpeg_job) {
1950                         free(jpeg_job);
1951                     }
1952 
1953                     qcamera_hal3_pp_buffer_t* pp_buf =
1954                             (qcamera_hal3_pp_buffer_t *)pme->m_inputPPQ.dequeue();
1955                     if (NULL != pp_buf) {
1956                         if (pp_buf->input) {
1957                             pme->releaseSuperBuf(pp_buf->input);
1958                             free(pp_buf->input);
1959                             pp_buf->input = NULL;
1960                         }
1961                         free(pp_buf);
1962                     }
1963                     mm_camera_super_buf_t *metadata = (mm_camera_super_buf_t *)pme->m_inputMetaQ.dequeue();
1964                     if (metadata != NULL) {
1965                         pme->m_parent->metadataBufDone(metadata);
1966                         free(metadata);
1967                     }
1968                     qcamera_fwk_input_pp_data_t *fwk_frame =
1969                             (qcamera_fwk_input_pp_data_t *) pme->m_inputFWKPPQ.dequeue();
1970                     if (NULL != fwk_frame) {
1971                         free(fwk_frame);
1972                     }
1973                 }
1974             }
1975             break;
1976         case CAMERA_CMD_TYPE_EXIT:
1977             running = 0;
1978             break;
1979         default:
1980             break;
1981         }
1982     } while (running);
1983     LOGD("X");
1984     return NULL;
1985 }
1986 
1987 /* EXIF related helper methods */
1988 
1989 /*===========================================================================
1990  * FUNCTION   : getRational
1991  *
1992  * DESCRIPTION: compose rational struct
1993  *
1994  * PARAMETERS :
1995  *   @rat     : ptr to struct to store rational info
1996  *   @num     :num of the rational
1997  *   @denom   : denom of the rational
1998  *
1999  * RETURN     : int32_t type of status
2000  *              NO_ERROR  -- success
2001  *              none-zero failure code
2002  *==========================================================================*/
getRational(rat_t * rat,int num,int denom)2003 int32_t getRational(rat_t *rat, int num, int denom)
2004 {
2005     if ((0 > num) || (0 >= denom)) {
2006         LOGE("Negative values");
2007         return BAD_VALUE;
2008     }
2009     if (NULL == rat) {
2010         LOGE("NULL rat input");
2011         return BAD_VALUE;
2012     }
2013     rat->num = (uint32_t)num;
2014     rat->denom = (uint32_t)denom;
2015     return NO_ERROR;
2016 }
2017 
2018 /*===========================================================================
2019  * FUNCTION   : parseGPSCoordinate
2020  *
2021  * DESCRIPTION: parse GPS coordinate string
2022  *
2023  * PARAMETERS :
2024  *   @coord_str : [input] coordinate string
2025  *   @coord     : [output]  ptr to struct to store coordinate
2026  *
2027  * RETURN     : int32_t type of status
2028  *              NO_ERROR  -- success
2029  *              none-zero failure code
2030  *==========================================================================*/
parseGPSCoordinate(const char * coord_str,rat_t * coord)2031 int parseGPSCoordinate(const char *coord_str, rat_t* coord)
2032 {
2033     if(coord == NULL) {
2034         LOGE("error, invalid argument coord == NULL");
2035         return BAD_VALUE;
2036     }
2037     double degF = atof(coord_str);
2038     if (degF < 0) {
2039         degF = -degF;
2040     }
2041     double minF = (degF - (int) degF) * 60;
2042     double secF = (minF - (int) minF) * 60;
2043 
2044     getRational(&coord[0], (int)degF, 1);
2045     getRational(&coord[1], (int)minF, 1);
2046     getRational(&coord[2], (int)(secF * 10000), 10000);
2047     return NO_ERROR;
2048 }
2049 
2050 /*===========================================================================
2051  * FUNCTION   : getExifDateTime
2052  *
2053  * DESCRIPTION: query exif date time
2054  *
2055  * PARAMETERS :
2056  *   @dateTime   : string to store exif date time
2057  *   @subsecTime : string to store exif subsec time
2058  *
2059  * RETURN     : int32_t type of status
2060  *              NO_ERROR  -- success
2061  *              none-zero failure code
2062  *==========================================================================*/
getExifDateTime(String8 & dateTime,String8 & subsecTime)2063 int32_t getExifDateTime(String8 &dateTime, String8 &subsecTime)
2064 {
2065     int32_t ret = NO_ERROR;
2066 
2067     //get time and date from system
2068     struct timeval tv;
2069     struct tm timeinfo_data;
2070 
2071     int res = gettimeofday(&tv, NULL);
2072     if (0 == res) {
2073         struct tm *timeinfo = localtime_r(&tv.tv_sec, &timeinfo_data);
2074         if (NULL != timeinfo) {
2075             //Write datetime according to EXIF Spec
2076             //"YYYY:MM:DD HH:MM:SS" (20 chars including \0)
2077             dateTime = String8::format("%04d:%02d:%02d %02d:%02d:%02d",
2078                     timeinfo->tm_year + 1900, timeinfo->tm_mon + 1,
2079                     timeinfo->tm_mday, timeinfo->tm_hour,
2080                     timeinfo->tm_min, timeinfo->tm_sec);
2081             //Write subsec according to EXIF Sepc
2082             subsecTime = String8::format("%06ld", tv.tv_usec);
2083         } else {
2084             LOGE("localtime_r() error");
2085             ret = UNKNOWN_ERROR;
2086         }
2087     } else if (-1 == res) {
2088         LOGE("gettimeofday() error: %s", strerror(errno));
2089         ret = UNKNOWN_ERROR;
2090     } else {
2091         LOGE("gettimeofday() unexpected return code: %d", res);
2092         ret = UNKNOWN_ERROR;
2093     }
2094 
2095     return ret;
2096 }
2097 
2098 /*===========================================================================
2099  * FUNCTION   : getExifFocalLength
2100  *
2101  * DESCRIPTION: get exif focal length
2102  *
2103  * PARAMETERS :
2104  *   @focalLength : ptr to rational struct to store focal length
2105  *   @value       : focal length value
2106  *
2107  * RETURN     : int32_t type of status
2108  *              NO_ERROR  -- success
2109  *              none-zero failure code
2110  *==========================================================================*/
getExifFocalLength(rat_t * focalLength,float value)2111 int32_t getExifFocalLength(rat_t *focalLength, float value)
2112 {
2113     int focalLengthValue =
2114         (int)(value * FOCAL_LENGTH_DECIMAL_PRECISION);
2115     return getRational(focalLength, focalLengthValue, FOCAL_LENGTH_DECIMAL_PRECISION);
2116 }
2117 
2118 /*===========================================================================
2119   * FUNCTION   : getExifExpTimeInfo
2120   *
2121   * DESCRIPTION: get exif exposure time information
2122   *
2123   * PARAMETERS :
2124   *   @expoTimeInfo     : rational exposure time value
2125   *   @value            : exposure time value
2126   * RETURN     : nt32_t type of status
2127   *              NO_ERROR  -- success
2128   *              none-zero failure code
2129   *==========================================================================*/
getExifExpTimeInfo(rat_t * expoTimeInfo,int64_t value)2130 int32_t getExifExpTimeInfo(rat_t *expoTimeInfo, int64_t value)
2131 {
2132 
2133     int64_t cal_exposureTime;
2134     if (value != 0)
2135         cal_exposureTime = value;
2136     else
2137         cal_exposureTime = 60;
2138 
2139     return getRational(expoTimeInfo, 1, (int)cal_exposureTime);
2140 }
2141 
2142 /*===========================================================================
2143  * FUNCTION   : getExifGpsProcessingMethod
2144  *
2145  * DESCRIPTION: get GPS processing method
2146  *
2147  * PARAMETERS :
2148  *   @gpsProcessingMethod : string to store GPS process method
2149  *   @count               : length of the string
2150  *   @value               : the value of the processing method
2151  *
2152  * RETURN     : int32_t type of status
2153  *              NO_ERROR  -- success
2154  *              none-zero failure code
2155  *==========================================================================*/
getExifGpsProcessingMethod(char * gpsProcessingMethod,uint32_t & count,char * value)2156 int32_t getExifGpsProcessingMethod(char *gpsProcessingMethod,
2157         uint32_t &count, char* value)
2158 {
2159     if(value != NULL) {
2160         memcpy(gpsProcessingMethod, ExifAsciiPrefix, EXIF_ASCII_PREFIX_SIZE);
2161         count = EXIF_ASCII_PREFIX_SIZE;
2162         strlcpy(gpsProcessingMethod + EXIF_ASCII_PREFIX_SIZE,
2163                 value,
2164                 GPS_PROCESSING_METHOD_SIZE);
2165         count += (uint32_t)strlen(value);
2166         gpsProcessingMethod[count++] = '\0'; // increase 1 for the last NULL char
2167         return NO_ERROR;
2168     } else {
2169         return BAD_VALUE;
2170     }
2171 }
2172 
2173 /*===========================================================================
2174  * FUNCTION   : getExifLatitude
2175  *
2176  * DESCRIPTION: get exif latitude
2177  *
2178  * PARAMETERS :
2179  *   @latitude : ptr to rational struct to store latitude info
2180  *   @latRef   : character to indicate latitude reference
2181  *   @value    : value of the latitude
2182  *
2183  * RETURN     : int32_t type of status
2184  *              NO_ERROR  -- success
2185  *              none-zero failure code
2186  *==========================================================================*/
getExifLatitude(rat_t * latitude,char * latRef,double value)2187 int32_t getExifLatitude(rat_t *latitude, char *latRef, double value)
2188 {
2189     char str[30];
2190     snprintf(str, sizeof(str), "%f", value);
2191     if(str[0] != '\0') {
2192         parseGPSCoordinate(str, latitude);
2193 
2194         //set Latitude Ref
2195         float latitudeValue = strtof(str, 0);
2196         if(latitudeValue < 0.0f) {
2197             latRef[0] = 'S';
2198         } else {
2199             latRef[0] = 'N';
2200         }
2201         latRef[1] = '\0';
2202         return NO_ERROR;
2203     }else{
2204         return BAD_VALUE;
2205     }
2206 }
2207 
2208 /*===========================================================================
2209  * FUNCTION   : getExifLongitude
2210  *
2211  * DESCRIPTION: get exif longitude
2212  *
2213  * PARAMETERS :
2214  *   @longitude : ptr to rational struct to store longitude info
2215  *   @lonRef    : character to indicate longitude reference
2216  *   @value     : value of the longitude
2217  *
2218  * RETURN     : int32_t type of status
2219  *              NO_ERROR  -- success
2220  *              none-zero failure code
2221  *==========================================================================*/
getExifLongitude(rat_t * longitude,char * lonRef,double value)2222 int32_t getExifLongitude(rat_t *longitude, char *lonRef, double value)
2223 {
2224     char str[30];
2225     snprintf(str, sizeof(str), "%f", value);
2226     if(str[0] != '\0') {
2227         parseGPSCoordinate(str, longitude);
2228 
2229         //set Longitude Ref
2230         float longitudeValue = strtof(str, 0);
2231         if(longitudeValue < 0.0f) {
2232             lonRef[0] = 'W';
2233         } else {
2234             lonRef[0] = 'E';
2235         }
2236         lonRef[1] = '\0';
2237         return NO_ERROR;
2238     }else{
2239         return BAD_VALUE;
2240     }
2241 }
2242 
2243 /*===========================================================================
2244  * FUNCTION   : getExifAltitude
2245  *
2246  * DESCRIPTION: get exif altitude
2247  *
2248  * PARAMETERS :
2249  *   @altitude : ptr to rational struct to store altitude info
2250  *   @altRef   : character to indicate altitude reference
2251  *   @argValue : altitude value
2252  *
2253  * RETURN     : int32_t type of status
2254  *              NO_ERROR  -- success
2255  *              none-zero failure code
2256  *==========================================================================*/
getExifAltitude(rat_t * altitude,char * altRef,double argValue)2257 int32_t getExifAltitude(rat_t *altitude, char *altRef, double argValue)
2258 {
2259     char str[30];
2260     snprintf(str, sizeof(str), "%f", argValue);
2261     if (str[0] != '\0') {
2262         double value = atof(str);
2263         *altRef = 0;
2264         if(value < 0){
2265             *altRef = 1;
2266             value = -value;
2267         }
2268         return getRational(altitude, (int)(value * 1000), 1000);
2269     } else {
2270         return BAD_VALUE;
2271     }
2272 }
2273 
2274 /*===========================================================================
2275  * FUNCTION   : getExifGpsDateTimeStamp
2276  *
2277  * DESCRIPTION: get exif GPS date time stamp
2278  *
2279  * PARAMETERS :
2280  *   @gpsDateStamp : GPS date time stamp string
2281  *   @bufLen       : length of the string
2282  *   @gpsTimeStamp : ptr to rational struct to store time stamp info
2283  *   @value        : timestamp value
2284  *
2285  * RETURN     : int32_t type of status
2286  *              NO_ERROR  -- success
2287  *              none-zero failure code
2288  *==========================================================================*/
getExifGpsDateTimeStamp(char * gpsDateStamp,uint32_t bufLen,rat_t * gpsTimeStamp,int64_t value)2289 int32_t getExifGpsDateTimeStamp(char *gpsDateStamp, uint32_t bufLen,
2290         rat_t *gpsTimeStamp, int64_t value)
2291 {
2292     char str[30];
2293     snprintf(str, sizeof(str), "%lld", (long long int)value);
2294     if(str[0] != '\0') {
2295         time_t unixTime = (time_t)atol(str);
2296         struct tm *UTCTimestamp = gmtime(&unixTime);
2297         if (UTCTimestamp != NULL && gpsDateStamp != NULL
2298                 && gpsTimeStamp != NULL) {
2299             strftime(gpsDateStamp, bufLen, "%Y:%m:%d", UTCTimestamp);
2300 
2301             getRational(&gpsTimeStamp[0], UTCTimestamp->tm_hour, 1);
2302             getRational(&gpsTimeStamp[1], UTCTimestamp->tm_min, 1);
2303             getRational(&gpsTimeStamp[2], UTCTimestamp->tm_sec, 1);
2304             return NO_ERROR;
2305         } else {
2306             LOGE("Could not get the timestamp");
2307             return BAD_VALUE;
2308         }
2309     } else {
2310         return BAD_VALUE;
2311     }
2312 }
2313 
2314 /*===========================================================================
2315  * FUNCTION   : getExifExposureValue
2316  *
2317  * DESCRIPTION: get exif GPS date time stamp
2318  *
2319  * PARAMETERS :
2320  *   @exposure_val        : rational exposure value
2321  *   @exposure_comp       : exposure compensation
2322  *   @step                : exposure step
2323  *
2324  * RETURN     : int32_t type of status
2325  *              NO_ERROR  -- success
2326  *              none-zero failure code
2327  *==========================================================================*/
getExifExposureValue(srat_t * exposure_val,int32_t exposure_comp,cam_rational_type_t step)2328 int32_t getExifExposureValue(srat_t* exposure_val, int32_t exposure_comp,
2329         cam_rational_type_t step)
2330 {
2331     exposure_val->num = exposure_comp * step.numerator;
2332     exposure_val->denom = step.denominator;
2333     return 0;
2334 }
2335 
2336 /*===========================================================================
2337  * FUNCTION   : getExifData
2338  *
2339  * DESCRIPTION: get exif data to be passed into jpeg encoding
2340  *
2341  * PARAMETERS :
2342  * @metadata      : metadata of the encoding request
2343  * @jpeg_settings : jpeg_settings for encoding
2344  *
2345  * RETURN     : exif data from user setting and GPS
2346  *==========================================================================*/
getExifData(metadata_buffer_t * metadata,jpeg_settings_t * jpeg_settings)2347 QCamera3Exif *QCamera3PostProcessor::getExifData(metadata_buffer_t *metadata,
2348         jpeg_settings_t *jpeg_settings)
2349 {
2350     QCamera3Exif *exif = new QCamera3Exif();
2351     if (exif == NULL) {
2352         LOGE("No memory for QCamera3Exif");
2353         return NULL;
2354     }
2355     QCamera3HardwareInterface* hal_obj = NULL;
2356     if (m_parent != NULL) {
2357         hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
2358     } else {
2359         LOGE("m_parent is NULL, Error");
2360         return NULL;
2361     }
2362 
2363     int32_t rc = NO_ERROR;
2364     uint32_t count = 0;
2365 
2366     // add exif entries
2367     String8 dateTime;
2368     String8 subsecTime;
2369     rc = getExifDateTime(dateTime, subsecTime);
2370     if (rc == NO_ERROR) {
2371         exif->addEntry(EXIFTAGID_DATE_TIME, EXIF_ASCII,
2372                 (uint32_t)(dateTime.length() + 1), (void *)dateTime.string());
2373         exif->addEntry(EXIFTAGID_EXIF_DATE_TIME_ORIGINAL, EXIF_ASCII,
2374                 (uint32_t)(dateTime.length() + 1), (void *)dateTime.string());
2375         exif->addEntry(EXIFTAGID_EXIF_DATE_TIME_DIGITIZED, EXIF_ASCII,
2376                 (uint32_t)(dateTime.length() + 1), (void *)dateTime.string());
2377         exif->addEntry(EXIFTAGID_SUBSEC_TIME, EXIF_ASCII,
2378                 (uint32_t)(subsecTime.length() + 1), (void *)subsecTime.string());
2379         exif->addEntry(EXIFTAGID_SUBSEC_TIME_ORIGINAL, EXIF_ASCII,
2380                 (uint32_t)(subsecTime.length() + 1), (void *)subsecTime.string());
2381         exif->addEntry(EXIFTAGID_SUBSEC_TIME_DIGITIZED, EXIF_ASCII,
2382                 (uint32_t)(subsecTime.length() + 1), (void *)subsecTime.string());
2383     } else {
2384         LOGW("getExifDateTime failed");
2385     }
2386 
2387 
2388     if (metadata != NULL) {
2389         IF_META_AVAILABLE(float, focal_length, CAM_INTF_META_LENS_FOCAL_LENGTH, metadata) {
2390             rat_t focalLength;
2391             rc = getExifFocalLength(&focalLength, *focal_length);
2392             if (rc == NO_ERROR) {
2393                 exif->addEntry(EXIFTAGID_FOCAL_LENGTH,
2394                         EXIF_RATIONAL,
2395                         1,
2396                         (void *)&(focalLength));
2397             } else {
2398                 LOGW("getExifFocalLength failed");
2399             }
2400         }
2401 
2402         IF_META_AVAILABLE(int32_t, isoSpeed, CAM_INTF_META_SENSOR_SENSITIVITY, metadata) {
2403             int16_t fwk_isoSpeed = (int16_t) *isoSpeed;
2404             exif->addEntry(EXIFTAGID_ISO_SPEED_RATING, EXIF_SHORT, 1, (void *) &(fwk_isoSpeed));
2405         }
2406 
2407 
2408         IF_META_AVAILABLE(int64_t, sensor_exposure_time,
2409                 CAM_INTF_META_SENSOR_EXPOSURE_TIME, metadata) {
2410             rat_t sensorExpTime;
2411             rc = getExifExpTimeInfo(&sensorExpTime, *sensor_exposure_time);
2412             if (rc == NO_ERROR){
2413                 exif->addEntry(EXIFTAGID_EXPOSURE_TIME,
2414                         EXIF_RATIONAL,
2415                         1,
2416                         (void *)&(sensorExpTime));
2417             } else {
2418                 LOGW("getExifExpTimeInfo failed");
2419             }
2420         }
2421 
2422         char* jpeg_gps_processing_method = jpeg_settings->gps_processing_method;
2423         if (strlen(jpeg_gps_processing_method) > 0) {
2424             char gpsProcessingMethod[EXIF_ASCII_PREFIX_SIZE +
2425                     GPS_PROCESSING_METHOD_SIZE];
2426             count = 0;
2427             rc = getExifGpsProcessingMethod(gpsProcessingMethod,
2428                     count,
2429                     jpeg_gps_processing_method);
2430             if(rc == NO_ERROR) {
2431                 exif->addEntry(EXIFTAGID_GPS_PROCESSINGMETHOD,
2432                         EXIF_ASCII,
2433                         count,
2434                         (void *)gpsProcessingMethod);
2435             } else {
2436                 LOGW("getExifGpsProcessingMethod failed");
2437             }
2438         }
2439 
2440         if (jpeg_settings->gps_coordinates_valid) {
2441 
2442             //latitude
2443             rat_t latitude[3];
2444             char latRef[2];
2445             rc = getExifLatitude(latitude, latRef,
2446                     jpeg_settings->gps_coordinates[0]);
2447             if(rc == NO_ERROR) {
2448                 exif->addEntry(EXIFTAGID_GPS_LATITUDE,
2449                         EXIF_RATIONAL,
2450                         3,
2451                         (void *)latitude);
2452                 exif->addEntry(EXIFTAGID_GPS_LATITUDE_REF,
2453                         EXIF_ASCII,
2454                         2,
2455                         (void *)latRef);
2456             } else {
2457                 LOGW("getExifLatitude failed");
2458             }
2459 
2460             //longitude
2461             rat_t longitude[3];
2462             char lonRef[2];
2463             rc = getExifLongitude(longitude, lonRef,
2464                     jpeg_settings->gps_coordinates[1]);
2465             if(rc == NO_ERROR) {
2466                 exif->addEntry(EXIFTAGID_GPS_LONGITUDE,
2467                         EXIF_RATIONAL,
2468                         3,
2469                         (void *)longitude);
2470 
2471                 exif->addEntry(EXIFTAGID_GPS_LONGITUDE_REF,
2472                         EXIF_ASCII,
2473                         2,
2474                         (void *)lonRef);
2475             } else {
2476                 LOGW("getExifLongitude failed");
2477             }
2478 
2479             //altitude
2480             rat_t altitude;
2481             char altRef;
2482             rc = getExifAltitude(&altitude, &altRef,
2483                     jpeg_settings->gps_coordinates[2]);
2484             if(rc == NO_ERROR) {
2485                 exif->addEntry(EXIFTAGID_GPS_ALTITUDE,
2486                         EXIF_RATIONAL,
2487                         1,
2488                         (void *)&(altitude));
2489 
2490                 exif->addEntry(EXIFTAGID_GPS_ALTITUDE_REF,
2491                         EXIF_BYTE,
2492                         1,
2493                         (void *)&altRef);
2494             } else {
2495                 LOGW("getExifAltitude failed");
2496             }
2497         }
2498 
2499         if (jpeg_settings->gps_timestamp_valid) {
2500 
2501             char gpsDateStamp[20];
2502             rat_t gpsTimeStamp[3];
2503             rc = getExifGpsDateTimeStamp(gpsDateStamp, 20, gpsTimeStamp,
2504                     jpeg_settings->gps_timestamp);
2505             if(rc == NO_ERROR) {
2506                 exif->addEntry(EXIFTAGID_GPS_DATESTAMP, EXIF_ASCII,
2507                         (uint32_t)(strlen(gpsDateStamp) + 1),
2508                         (void *)gpsDateStamp);
2509 
2510                 exif->addEntry(EXIFTAGID_GPS_TIMESTAMP,
2511                         EXIF_RATIONAL,
2512                         3,
2513                         (void *)gpsTimeStamp);
2514             } else {
2515                 LOGW("getExifGpsDataTimeStamp failed");
2516             }
2517         }
2518 
2519         IF_META_AVAILABLE(int32_t, exposure_comp, CAM_INTF_PARM_EXPOSURE_COMPENSATION, metadata) {
2520             IF_META_AVAILABLE(cam_rational_type_t, comp_step, CAM_INTF_PARM_EV_STEP, metadata) {
2521                 srat_t exposure_val;
2522                 rc = getExifExposureValue(&exposure_val, *exposure_comp, *comp_step);
2523                 if(rc == NO_ERROR) {
2524                     exif->addEntry(EXIFTAGID_EXPOSURE_BIAS_VALUE,
2525                             EXIF_SRATIONAL,
2526                             1,
2527                             (void *)(&exposure_val));
2528                 } else {
2529                     LOGW("getExifExposureValue failed ");
2530                 }
2531             }
2532         }
2533     } else {
2534         LOGW("no metadata provided ");
2535     }
2536 
2537 #ifdef ENABLE_MODEL_INFO_EXIF
2538 
2539     char value[PROPERTY_VALUE_MAX];
2540     if (property_get("ro.product.manufacturer", value, "QCOM-AA") > 0) {
2541         exif->addEntry(EXIFTAGID_MAKE, EXIF_ASCII,
2542                 (uint32_t)(strlen(value) + 1), (void *)value);
2543     } else {
2544         LOGW("getExifMaker failed");
2545     }
2546 
2547     if (property_get("ro.product.model", value, "QCAM-AA") > 0) {
2548         exif->addEntry(EXIFTAGID_MODEL, EXIF_ASCII,
2549                 (uint32_t)(strlen(value) + 1), (void *)value);
2550     } else {
2551         LOGW("getExifModel failed");
2552     }
2553 
2554     if (property_get("ro.build.description", value, "QCAM-AA") > 0) {
2555         exif->addEntry(EXIFTAGID_SOFTWARE, EXIF_ASCII,
2556                 (uint32_t)(strlen(value) + 1), (void *)value);
2557     } else {
2558         LOGW("getExifSoftware failed");
2559     }
2560 
2561 #endif
2562 
2563     if (jpeg_settings->image_desc_valid) {
2564         if (exif->addEntry(EXIFTAGID_IMAGE_DESCRIPTION, EXIF_ASCII,
2565                 strlen(jpeg_settings->image_desc)+1,
2566                 (void *)jpeg_settings->image_desc)) {
2567             LOGW("Adding IMAGE_DESCRIPTION tag failed");
2568         }
2569     }
2570 
2571     if( hal_obj->needJpegExifRotation()) {
2572         int16_t orientation;
2573         switch (jpeg_settings->jpeg_orientation) {
2574             case 0:
2575                 orientation = 1;
2576                 break;
2577             case 90:
2578                 orientation = 6;
2579                 break;
2580             case 180:
2581                 orientation = 3;
2582                 break;
2583             case 270:
2584                 orientation = 8;
2585                 break;
2586             default:
2587                 orientation = 1;
2588                 break;
2589         }
2590         exif->addEntry(EXIFTAGID_ORIENTATION,
2591                        EXIF_SHORT,
2592                        1,
2593                        (void *)&orientation);
2594         exif->addEntry(EXIFTAGID_TN_ORIENTATION,
2595                        EXIF_SHORT,
2596                        1,
2597                        (void *)&orientation);
2598 
2599     }
2600 
2601     return exif;
2602 }
2603 
2604 /*===========================================================================
2605  * FUNCTION   : QCamera3Exif
2606  *
2607  * DESCRIPTION: constructor of QCamera3Exif
2608  *
2609  * PARAMETERS : None
2610  *
2611  * RETURN     : None
2612  *==========================================================================*/
QCamera3Exif()2613 QCamera3Exif::QCamera3Exif()
2614     : m_nNumEntries(0)
2615 {
2616     memset(m_Entries, 0, sizeof(m_Entries));
2617 }
2618 
2619 /*===========================================================================
2620  * FUNCTION   : ~QCamera3Exif
2621  *
2622  * DESCRIPTION: deconstructor of QCamera3Exif. Will release internal memory ptr.
2623  *
2624  * PARAMETERS : None
2625  *
2626  * RETURN     : None
2627  *==========================================================================*/
~QCamera3Exif()2628 QCamera3Exif::~QCamera3Exif()
2629 {
2630     for (uint32_t i = 0; i < m_nNumEntries; i++) {
2631         switch (m_Entries[i].tag_entry.type) {
2632             case EXIF_BYTE:
2633                 {
2634                     if (m_Entries[i].tag_entry.count > 1 &&
2635                             m_Entries[i].tag_entry.data._bytes != NULL) {
2636                         free(m_Entries[i].tag_entry.data._bytes);
2637                         m_Entries[i].tag_entry.data._bytes = NULL;
2638                     }
2639                 }
2640                 break;
2641             case EXIF_ASCII:
2642                 {
2643                     if (m_Entries[i].tag_entry.data._ascii != NULL) {
2644                         free(m_Entries[i].tag_entry.data._ascii);
2645                         m_Entries[i].tag_entry.data._ascii = NULL;
2646                     }
2647                 }
2648                 break;
2649             case EXIF_SHORT:
2650                 {
2651                     if (m_Entries[i].tag_entry.count > 1 &&
2652                             m_Entries[i].tag_entry.data._shorts != NULL) {
2653                         free(m_Entries[i].tag_entry.data._shorts);
2654                         m_Entries[i].tag_entry.data._shorts = NULL;
2655                     }
2656                 }
2657                 break;
2658             case EXIF_LONG:
2659                 {
2660                     if (m_Entries[i].tag_entry.count > 1 &&
2661                             m_Entries[i].tag_entry.data._longs != NULL) {
2662                         free(m_Entries[i].tag_entry.data._longs);
2663                         m_Entries[i].tag_entry.data._longs = NULL;
2664                     }
2665                 }
2666                 break;
2667             case EXIF_RATIONAL:
2668                 {
2669                     if (m_Entries[i].tag_entry.count > 1 &&
2670                             m_Entries[i].tag_entry.data._rats != NULL) {
2671                         free(m_Entries[i].tag_entry.data._rats);
2672                         m_Entries[i].tag_entry.data._rats = NULL;
2673                     }
2674                 }
2675                 break;
2676             case EXIF_UNDEFINED:
2677                 {
2678                     if (m_Entries[i].tag_entry.data._undefined != NULL) {
2679                         free(m_Entries[i].tag_entry.data._undefined);
2680                         m_Entries[i].tag_entry.data._undefined = NULL;
2681                     }
2682                 }
2683                 break;
2684             case EXIF_SLONG:
2685                 {
2686                     if (m_Entries[i].tag_entry.count > 1 &&
2687                             m_Entries[i].tag_entry.data._slongs != NULL) {
2688                         free(m_Entries[i].tag_entry.data._slongs);
2689                         m_Entries[i].tag_entry.data._slongs = NULL;
2690                     }
2691                 }
2692                 break;
2693             case EXIF_SRATIONAL:
2694                 {
2695                     if (m_Entries[i].tag_entry.count > 1 &&
2696                             m_Entries[i].tag_entry.data._srats != NULL) {
2697                         free(m_Entries[i].tag_entry.data._srats);
2698                         m_Entries[i].tag_entry.data._srats = NULL;
2699                     }
2700                 }
2701                 break;
2702             default:
2703                 LOGW("Error, Unknown type");
2704                 break;
2705         }
2706     }
2707 }
2708 
2709 /*===========================================================================
2710  * FUNCTION   : addEntry
2711  *
2712  * DESCRIPTION: function to add an entry to exif data
2713  *
2714  * PARAMETERS :
2715  *   @tagid   : exif tag ID
2716  *   @type    : data type
2717  *   @count   : number of data in uint of its type
2718  *   @data    : input data ptr
2719  *
2720  * RETURN     : int32_t type of status
2721  *              NO_ERROR  -- success
2722  *              none-zero failure code
2723  *==========================================================================*/
addEntry(exif_tag_id_t tagid,exif_tag_type_t type,uint32_t count,void * data)2724 int32_t QCamera3Exif::addEntry(exif_tag_id_t tagid,
2725                               exif_tag_type_t type,
2726                               uint32_t count,
2727                               void *data)
2728 {
2729     int32_t rc = NO_ERROR;
2730     if(m_nNumEntries >= MAX_HAL3_EXIF_TABLE_ENTRIES) {
2731         LOGE("Number of entries exceeded limit");
2732         return NO_MEMORY;
2733     }
2734 
2735     m_Entries[m_nNumEntries].tag_id = tagid;
2736     m_Entries[m_nNumEntries].tag_entry.type = type;
2737     m_Entries[m_nNumEntries].tag_entry.count = count;
2738     m_Entries[m_nNumEntries].tag_entry.copy = 1;
2739     switch (type) {
2740         case EXIF_BYTE:
2741             {
2742                 if (count > 1) {
2743                     uint8_t *values = (uint8_t *)malloc(count);
2744                     if (values == NULL) {
2745                         LOGE("No memory for byte array");
2746                         rc = NO_MEMORY;
2747                     } else {
2748                         memcpy(values, data, count);
2749                         m_Entries[m_nNumEntries].tag_entry.data._bytes = values;
2750                     }
2751                 } else {
2752                     m_Entries[m_nNumEntries].tag_entry.data._byte =
2753                         *(uint8_t *)data;
2754                 }
2755             }
2756             break;
2757         case EXIF_ASCII:
2758             {
2759                 char *str = NULL;
2760                 str = (char *)malloc(count + 1);
2761                 if (str == NULL) {
2762                     LOGE("No memory for ascii string");
2763                     rc = NO_MEMORY;
2764                 } else {
2765                     memset(str, 0, count + 1);
2766                     memcpy(str, data, count);
2767                     m_Entries[m_nNumEntries].tag_entry.data._ascii = str;
2768                 }
2769             }
2770             break;
2771         case EXIF_SHORT:
2772             {
2773                 uint16_t *exif_data = (uint16_t *)data;
2774                 if (count > 1) {
2775                     uint16_t *values =
2776                         (uint16_t *)malloc(count * sizeof(uint16_t));
2777                     if (values == NULL) {
2778                         LOGE("No memory for short array");
2779                         rc = NO_MEMORY;
2780                     } else {
2781                         memcpy(values, exif_data, count * sizeof(uint16_t));
2782                         m_Entries[m_nNumEntries].tag_entry.data._shorts = values;
2783                     }
2784                 } else {
2785                     m_Entries[m_nNumEntries].tag_entry.data._short =
2786                         *(uint16_t *)data;
2787                 }
2788             }
2789             break;
2790         case EXIF_LONG:
2791             {
2792                 uint32_t *exif_data = (uint32_t *)data;
2793                 if (count > 1) {
2794                     uint32_t *values =
2795                         (uint32_t *)malloc(count * sizeof(uint32_t));
2796                     if (values == NULL) {
2797                         LOGE("No memory for long array");
2798                         rc = NO_MEMORY;
2799                     } else {
2800                         memcpy(values, exif_data, count * sizeof(uint32_t));
2801                         m_Entries[m_nNumEntries].tag_entry.data._longs = values;
2802                     }
2803                 } else {
2804                     m_Entries[m_nNumEntries].tag_entry.data._long =
2805                         *(uint32_t *)data;
2806                 }
2807             }
2808             break;
2809         case EXIF_RATIONAL:
2810             {
2811                 rat_t *exif_data = (rat_t *)data;
2812                 if (count > 1) {
2813                     rat_t *values = (rat_t *)malloc(count * sizeof(rat_t));
2814                     if (values == NULL) {
2815                         LOGE("No memory for rational array");
2816                         rc = NO_MEMORY;
2817                     } else {
2818                         memcpy(values, exif_data, count * sizeof(rat_t));
2819                         m_Entries[m_nNumEntries].tag_entry.data._rats = values;
2820                     }
2821                 } else {
2822                     m_Entries[m_nNumEntries].tag_entry.data._rat =
2823                         *(rat_t *)data;
2824                 }
2825             }
2826             break;
2827         case EXIF_UNDEFINED:
2828             {
2829                 uint8_t *values = (uint8_t *)malloc(count);
2830                 if (values == NULL) {
2831                     LOGE("No memory for undefined array");
2832                     rc = NO_MEMORY;
2833                 } else {
2834                     memcpy(values, data, count);
2835                     m_Entries[m_nNumEntries].tag_entry.data._undefined = values;
2836                 }
2837             }
2838             break;
2839         case EXIF_SLONG:
2840             {
2841                 int32_t *exif_data = (int32_t *)data;
2842                 if (count > 1) {
2843                     int32_t *values =
2844                         (int32_t *)malloc(count * sizeof(int32_t));
2845                     if (values == NULL) {
2846                         LOGE("No memory for signed long array");
2847                         rc = NO_MEMORY;
2848                     } else {
2849                         memcpy(values, exif_data, count * sizeof(int32_t));
2850                         m_Entries[m_nNumEntries].tag_entry.data._slongs =values;
2851                     }
2852                 } else {
2853                     m_Entries[m_nNumEntries].tag_entry.data._slong =
2854                         *(int32_t *)data;
2855                 }
2856             }
2857             break;
2858         case EXIF_SRATIONAL:
2859             {
2860                 srat_t *exif_data = (srat_t *)data;
2861                 if (count > 1) {
2862                     srat_t *values = (srat_t *)malloc(count * sizeof(srat_t));
2863                     if (values == NULL) {
2864                         LOGE("No memory for sign rational array");
2865                         rc = NO_MEMORY;
2866                     } else {
2867                         memcpy(values, exif_data, count * sizeof(srat_t));
2868                         m_Entries[m_nNumEntries].tag_entry.data._srats = values;
2869                     }
2870                 } else {
2871                     m_Entries[m_nNumEntries].tag_entry.data._srat =
2872                         *(srat_t *)data;
2873                 }
2874             }
2875             break;
2876         default:
2877             LOGE("Error, Unknown type");
2878             break;
2879     }
2880 
2881     // Increase number of entries
2882     m_nNumEntries++;
2883     return rc;
2884 }
2885 
2886 }; // namespace qcamera
2887