1 /* Copyright (c) 2012-2013, The Linux Foundataion. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30 #define LOG_TAG "QCameraPostProc"
31
32 #include <stdlib.h>
33 #include <utils/Errors.h>
34
35 #include "QCamera2HWI.h"
36 #include "QCameraPostProc.h"
37
38 namespace qcamera {
39
40 /*===========================================================================
41 * FUNCTION : QCameraPostProcessor
42 *
43 * DESCRIPTION: constructor of QCameraPostProcessor.
44 *
45 * PARAMETERS :
46 * @cam_ctrl : ptr to HWI object
47 *
48 * RETURN : None
49 *==========================================================================*/
QCameraPostProcessor(QCamera2HardwareInterface * cam_ctrl)50 QCameraPostProcessor::QCameraPostProcessor(QCamera2HardwareInterface *cam_ctrl)
51 : m_parent(cam_ctrl),
52 mJpegCB(NULL),
53 mJpegUserData(NULL),
54 mJpegClientHandle(0),
55 mJpegSessionId(0),
56 m_pJpegOutputMem(NULL),
57 m_pJpegExifObj(NULL),
58 m_bThumbnailNeeded(TRUE),
59 m_pReprocChannel(NULL),
60 m_inputPPQ(releasePPInputData, this),
61 m_ongoingPPQ(releaseOngoingPPData, this),
62 m_inputJpegQ(releaseJpegData, this),
63 m_ongoingJpegQ(releaseJpegData, this),
64 m_inputRawQ(releasePPInputData, this)
65 {
66 memset(&mJpegHandle, 0, sizeof(mJpegHandle));
67 }
68
69 /*===========================================================================
70 * FUNCTION : ~QCameraPostProcessor
71 *
72 * DESCRIPTION: deconstructor of QCameraPostProcessor.
73 *
74 * PARAMETERS : None
75 *
76 * RETURN : None
77 *==========================================================================*/
~QCameraPostProcessor()78 QCameraPostProcessor::~QCameraPostProcessor()
79 {
80 if (m_pJpegOutputMem != NULL) {
81 m_pJpegOutputMem->deallocate();
82 delete m_pJpegOutputMem;
83 m_pJpegOutputMem = NULL;
84 }
85 if (m_pJpegExifObj != NULL) {
86 delete m_pJpegExifObj;
87 m_pJpegExifObj = NULL;
88 }
89 if (m_pReprocChannel != NULL) {
90 m_pReprocChannel->stop();
91 delete m_pReprocChannel;
92 m_pReprocChannel = NULL;
93 }
94 }
95
96 /*===========================================================================
97 * FUNCTION : init
98 *
99 * DESCRIPTION: initialization of postprocessor
100 *
101 * PARAMETERS :
102 * @jpeg_cb : callback to handle jpeg event from mm-camera-interface
103 * @user_data : user data ptr for jpeg callback
104 *
105 * RETURN : int32_t type of status
106 * NO_ERROR -- success
107 * none-zero failure code
108 *==========================================================================*/
init(jpeg_encode_callback_t jpeg_cb,void * user_data)109 int32_t QCameraPostProcessor::init(jpeg_encode_callback_t jpeg_cb, void *user_data)
110 {
111 mJpegCB = jpeg_cb;
112 mJpegUserData = user_data;
113
114 mJpegClientHandle = jpeg_open(&mJpegHandle);
115 if(!mJpegClientHandle) {
116 ALOGE("%s : jpeg_open did not work", __func__);
117 return UNKNOWN_ERROR;
118 }
119
120 m_dataProcTh.launch(dataProcessRoutine, this);
121
122 return NO_ERROR;
123 }
124
125 /*===========================================================================
126 * FUNCTION : deinit
127 *
128 * DESCRIPTION: de-initialization of postprocessor
129 *
130 * PARAMETERS : None
131 *
132 * RETURN : int32_t type of status
133 * NO_ERROR -- success
134 * none-zero failure code
135 *==========================================================================*/
deinit()136 int32_t QCameraPostProcessor::deinit()
137 {
138 m_dataProcTh.exit();
139
140 if(mJpegClientHandle > 0) {
141 int rc = mJpegHandle.close(mJpegClientHandle);
142 ALOGE("%s: Jpeg closed, rc = %d, mJpegClientHandle = %x",
143 __func__, rc, mJpegClientHandle);
144 mJpegClientHandle = 0;
145 memset(&mJpegHandle, 0, sizeof(mJpegHandle));
146 }
147
148 return NO_ERROR;
149 }
150
151 /*===========================================================================
152 * FUNCTION : start
153 *
154 * DESCRIPTION: start postprocessor. Data process thread and data notify thread
155 * will be launched.
156 *
157 * PARAMETERS :
158 * @pSrcChannel : source channel obj ptr that possibly needs reprocess
159 *
160 * RETURN : int32_t type of status
161 * NO_ERROR -- success
162 * none-zero failure code
163 *
164 * NOTE : if any reprocess is needed, a reprocess channel/stream
165 * will be started.
166 *==========================================================================*/
start(QCameraChannel * pSrcChannel)167 int32_t QCameraPostProcessor::start(QCameraChannel *pSrcChannel)
168 {
169 int32_t rc = NO_ERROR;
170 if (m_parent->needReprocess()) {
171 if (m_pReprocChannel != NULL) {
172 delete m_pReprocChannel;
173 m_pReprocChannel = NULL;
174 }
175 // if reprocess is needed, start reprocess channel
176 m_pReprocChannel = m_parent->addOnlineReprocChannel(pSrcChannel);
177 if (m_pReprocChannel == NULL) {
178 ALOGE("%s: cannot add reprocess channel", __func__);
179 return UNKNOWN_ERROR;
180 }
181
182 rc = m_pReprocChannel->start();
183 if (rc != 0) {
184 ALOGE("%s: cannot start reprocess channel", __func__);
185 delete m_pReprocChannel;
186 m_pReprocChannel = NULL;
187 return rc;
188 }
189 }
190
191 m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, FALSE, FALSE);
192 m_parent->m_cbNotifier.startSnapshots();
193
194 return rc;
195 }
196
197 /*===========================================================================
198 * FUNCTION : stop
199 *
200 * DESCRIPTION: stop postprocessor. Data process and notify thread will be stopped.
201 *
202 * PARAMETERS : None
203 *
204 * RETURN : int32_t type of status
205 * NO_ERROR -- success
206 * none-zero failure code
207 *
208 * NOTE : reprocess channel will be stopped and deleted if there is any
209 *==========================================================================*/
stop()210 int32_t QCameraPostProcessor::stop()
211 {
212 m_parent->m_cbNotifier.stopSnapshots();
213 // dataProc Thread need to process "stop" as sync call because abort jpeg job should be a sync call
214 m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE);
215
216 return NO_ERROR;
217 }
218
219 /*===========================================================================
220 * FUNCTION : getJpegEncodingConfig
221 *
222 * DESCRIPTION: function to prepare encoding job information
223 *
224 * PARAMETERS :
225 * @encode_parm : param to be filled with encoding configuration
226 *
227 * RETURN : int32_t type of status
228 * NO_ERROR -- success
229 * none-zero failure code
230 *==========================================================================*/
getJpegEncodingConfig(mm_jpeg_encode_params_t & encode_parm,QCameraStream * main_stream,QCameraStream * thumb_stream)231 int32_t QCameraPostProcessor::getJpegEncodingConfig(mm_jpeg_encode_params_t& encode_parm,
232 QCameraStream *main_stream,
233 QCameraStream *thumb_stream)
234 {
235 ALOGV("%s : E", __func__);
236 int32_t ret = NO_ERROR;
237 camera_memory_t *jpeg_mem = NULL;
238
239 encode_parm.jpeg_cb = mJpegCB;
240 encode_parm.userdata = mJpegUserData;
241
242 m_bThumbnailNeeded = TRUE; // need encode thumbnail by default
243 cam_dimension_t thumbnailSize;
244 memset(&thumbnailSize, 0, sizeof(cam_dimension_t));
245 m_parent->getThumbnailSize(thumbnailSize);
246 if (thumbnailSize.width == 0 || thumbnailSize.height == 0) {
247 // (0,0) means no thumbnail
248 m_bThumbnailNeeded = FALSE;
249 }
250 encode_parm.encode_thumbnail = m_bThumbnailNeeded;
251
252 // get color format
253 cam_format_t img_fmt = CAM_FORMAT_YUV_420_NV12;
254 main_stream->getFormat(img_fmt);
255 encode_parm.color_format = getColorfmtFromImgFmt(img_fmt);
256
257 // get jpeg quality
258 encode_parm.quality = m_parent->getJpegQuality();
259 if (encode_parm.quality <= 0) {
260 encode_parm.quality = 85;
261 }
262
263 // get exif data
264 if (m_pJpegExifObj != NULL) {
265 delete m_pJpegExifObj;
266 m_pJpegExifObj = NULL;
267 }
268 m_pJpegExifObj = m_parent->getExifData();
269 if (m_pJpegExifObj != NULL) {
270 encode_parm.exif_info.exif_data = m_pJpegExifObj->getEntries();
271 encode_parm.exif_info.numOfEntries = m_pJpegExifObj->getNumOfEntries();
272 }
273
274 cam_frame_len_offset_t main_offset;
275 memset(&main_offset, 0, sizeof(cam_frame_len_offset_t));
276 main_stream->getFrameOffset(main_offset);
277
278 // src buf config
279 QCameraMemory *pStreamMem = main_stream->getStreamBufs();
280 if (pStreamMem == NULL) {
281 ALOGE("%s: cannot get stream bufs from main stream", __func__);
282 ret = BAD_VALUE;
283 goto on_error;
284 }
285 encode_parm.num_src_bufs = pStreamMem->getCnt();
286 for (uint32_t i = 0; i < encode_parm.num_src_bufs; i++) {
287 camera_memory_t *stream_mem = pStreamMem->getMemory(i, false);
288 if (stream_mem != NULL) {
289 encode_parm.src_main_buf[i].index = i;
290 encode_parm.src_main_buf[i].buf_size = stream_mem->size;
291 encode_parm.src_main_buf[i].buf_vaddr = (uint8_t *)stream_mem->data;
292 encode_parm.src_main_buf[i].fd = pStreamMem->getFd(i);
293 encode_parm.src_main_buf[i].format = MM_JPEG_FMT_YUV;
294 encode_parm.src_main_buf[i].offset = main_offset;
295 }
296 }
297
298 if (m_bThumbnailNeeded == TRUE) {
299 if (thumb_stream == NULL) {
300 thumb_stream = main_stream;
301 }
302 pStreamMem = thumb_stream->getStreamBufs();
303 if (pStreamMem == NULL) {
304 ALOGE("%s: cannot get stream bufs from thumb stream", __func__);
305 ret = BAD_VALUE;
306 goto on_error;
307 }
308 cam_frame_len_offset_t thumb_offset;
309 memset(&thumb_offset, 0, sizeof(cam_frame_len_offset_t));
310 thumb_stream->getFrameOffset(thumb_offset);
311 encode_parm.num_tmb_bufs = pStreamMem->getCnt();
312 for (int i = 0; i < pStreamMem->getCnt(); i++) {
313 camera_memory_t *stream_mem = pStreamMem->getMemory(i, false);
314 if (stream_mem != NULL) {
315 encode_parm.src_thumb_buf[i].index = i;
316 encode_parm.src_thumb_buf[i].buf_size = stream_mem->size;
317 encode_parm.src_thumb_buf[i].buf_vaddr = (uint8_t *)stream_mem->data;
318 encode_parm.src_thumb_buf[i].fd = pStreamMem->getFd(i);
319 encode_parm.src_thumb_buf[i].format = MM_JPEG_FMT_YUV;
320 encode_parm.src_thumb_buf[i].offset = thumb_offset;
321 }
322 }
323 }
324
325 // allocate output buf for jpeg encoding
326 if (m_pJpegOutputMem != NULL) {
327 m_pJpegOutputMem->deallocate();
328 delete m_pJpegOutputMem;
329 m_pJpegOutputMem = NULL;
330 }
331 m_pJpegOutputMem = new QCameraStreamMemory(m_parent->mGetMemory,
332 QCAMERA_ION_USE_CACHE);
333 if (NULL == m_pJpegOutputMem) {
334 ret = NO_MEMORY;
335 ALOGE("%s : No memory for m_pJpegOutputMem", __func__);
336 goto on_error;
337 }
338 ret = m_pJpegOutputMem->allocate(1, main_offset.frame_len);
339 if(ret != OK) {
340 ret = NO_MEMORY;
341 ALOGE("%s : No memory for m_pJpegOutputMem", __func__);
342 goto on_error;
343 }
344 jpeg_mem = m_pJpegOutputMem->getMemory(0, false);
345 if (NULL == jpeg_mem) {
346 ret = NO_MEMORY;
347 ALOGE("%s : initHeapMem for jpeg, ret = NO_MEMORY", __func__);
348 goto on_error;
349 }
350 encode_parm.num_dst_bufs = 1;
351 encode_parm.dest_buf[0].index = 0;
352 encode_parm.dest_buf[0].buf_size = jpeg_mem->size;
353 encode_parm.dest_buf[0].buf_vaddr = (uint8_t *)jpeg_mem->data;
354 encode_parm.dest_buf[0].fd = m_pJpegOutputMem->getFd(0);
355 encode_parm.dest_buf[0].format = MM_JPEG_FMT_YUV;
356 encode_parm.dest_buf[0].offset = main_offset;
357
358 ALOGV("%s : X", __func__);
359 return NO_ERROR;
360
361 on_error:
362 if (m_pJpegOutputMem != NULL) {
363 m_pJpegOutputMem->deallocate();
364 delete m_pJpegOutputMem;
365 m_pJpegOutputMem = NULL;
366 }
367 if (m_pJpegExifObj != NULL) {
368 delete m_pJpegExifObj;
369 m_pJpegExifObj = NULL;
370 }
371 ALOGV("%s : X with error %d", __func__, ret);
372 return ret;
373 }
374
375 /*===========================================================================
376 * FUNCTION : sendEvtNotify
377 *
378 * DESCRIPTION: send event notify through notify callback registered by upper layer
379 *
380 * PARAMETERS :
381 * @msg_type: msg type of notify
382 * @ext1 : extension
383 * @ext2 : extension
384 *
385 * RETURN : int32_t type of status
386 * NO_ERROR -- success
387 * none-zero failure code
388 *==========================================================================*/
sendEvtNotify(int32_t msg_type,int32_t ext1,int32_t ext2)389 int32_t QCameraPostProcessor::sendEvtNotify(int32_t msg_type,
390 int32_t ext1,
391 int32_t ext2)
392 {
393 return m_parent->sendEvtNotify(msg_type, ext1, ext2);
394 }
395
396 /*===========================================================================
397 * FUNCTION : sendDataNotify
398 *
399 * DESCRIPTION: enqueue data into dataNotify thread
400 *
401 * PARAMETERS :
402 * @msg_type: data callback msg type
403 * @data : ptr to data memory struct
404 * @index : index to data buffer
405 * @metadata: ptr to meta data buffer if there is any
406 * @release_data : ptr to struct indicating if data need to be released
407 * after notify
408 *
409 * RETURN : int32_t type of status
410 * NO_ERROR -- success
411 * none-zero failure code
412 *==========================================================================*/
sendDataNotify(int32_t msg_type,camera_memory_t * data,uint8_t index,camera_frame_metadata_t * metadata,qcamera_release_data_t * release_data)413 int32_t QCameraPostProcessor::sendDataNotify(int32_t msg_type,
414 camera_memory_t *data,
415 uint8_t index,
416 camera_frame_metadata_t *metadata,
417 qcamera_release_data_t *release_data)
418 {
419 qcamera_data_argm_t *data_cb = (qcamera_data_argm_t *)malloc(sizeof(qcamera_data_argm_t));
420 if (NULL == data_cb) {
421 ALOGE("%s: no mem for acamera_data_argm_t", __func__);
422 return NO_MEMORY;
423 }
424 memset(data_cb, 0, sizeof(qcamera_data_argm_t));
425 data_cb->msg_type = msg_type;
426 data_cb->data = data;
427 data_cb->index = index;
428 data_cb->metadata = metadata;
429 if (release_data != NULL) {
430 data_cb->release_data = *release_data;
431 }
432
433 qcamera_callback_argm_t cbArg;
434 memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
435 cbArg.cb_type = QCAMERA_DATA_SNAPSHOT_CALLBACK;
436 cbArg.msg_type = msg_type;
437 cbArg.data = data;
438 cbArg.metadata = metadata;
439 cbArg.user_data = data_cb;
440 cbArg.cookie = this;
441 cbArg.release_cb = releaseNotifyData;
442 int rc = m_parent->m_cbNotifier.notifyCallback(cbArg);
443 if ( NO_ERROR != rc ) {
444 ALOGE("%s: Error enqueuing jpeg data into notify queue", __func__);
445 free(data_cb);
446 return UNKNOWN_ERROR;
447 }
448
449 return rc;
450 }
451
452 /*===========================================================================
453 * FUNCTION : processData
454 *
455 * DESCRIPTION: enqueue data into dataProc thread
456 *
457 * PARAMETERS :
458 * @frame : process frame received from mm-camera-interface
459 *
460 * RETURN : int32_t type of status
461 * NO_ERROR -- success
462 * none-zero failure code
463 *
464 * NOTE : depends on if offline reprocess is needed, received frame will
465 * be sent to either input queue of postprocess or jpeg encoding
466 *==========================================================================*/
processData(mm_camera_super_buf_t * frame)467 int32_t QCameraPostProcessor::processData(mm_camera_super_buf_t *frame)
468 {
469 if (m_parent->needReprocess()) {
470 ALOGD("%s: need reprocess", __func__);
471 // enqueu to post proc input queue
472 m_inputPPQ.enqueue((void *)frame);
473 } else if (m_parent->mParameters.isNV16PictureFormat()) {
474 processRawData(frame);
475 } else {
476 ALOGD("%s: no need offline reprocess, sending to jpeg encoding", __func__);
477 qcamera_jpeg_data_t *jpeg_job =
478 (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t));
479 if (jpeg_job == NULL) {
480 ALOGE("%s: No memory for jpeg job", __func__);
481 return NO_MEMORY;
482 }
483
484 memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t));
485 jpeg_job->src_frame = frame;
486
487 // enqueu to jpeg input queue
488 m_inputJpegQ.enqueue((void *)jpeg_job);
489 }
490 m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
491
492 return NO_ERROR;
493 }
494
495 /*===========================================================================
496 * FUNCTION : processRawData
497 *
498 * DESCRIPTION: enqueue raw data into dataProc thread
499 *
500 * PARAMETERS :
501 * @frame : process frame received from mm-camera-interface
502 *
503 * RETURN : int32_t type of status
504 * NO_ERROR -- success
505 * none-zero failure code
506 *==========================================================================*/
processRawData(mm_camera_super_buf_t * frame)507 int32_t QCameraPostProcessor::processRawData(mm_camera_super_buf_t *frame)
508 {
509 // enqueu to raw input queue
510 m_inputRawQ.enqueue((void *)frame);
511 m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
512 return NO_ERROR;
513 }
514
515 /*===========================================================================
516 * FUNCTION : processJpegEvt
517 *
518 * DESCRIPTION: process jpeg event from mm-jpeg-interface.
519 *
520 * PARAMETERS :
521 * @evt : payload of jpeg event, including information about jpeg encoding
522 * status, jpeg size and so on.
523 *
524 * RETURN : int32_t type of status
525 * NO_ERROR -- success
526 * none-zero failure code
527 *
528 * NOTE : This event will also trigger DataProc thread to move to next job
529 * processing (i.e., send a new jpeg encoding job to mm-jpeg-interface
530 * if there is any pending job in jpeg input queue)
531 *==========================================================================*/
processJpegEvt(qcamera_jpeg_evt_payload_t * evt)532 int32_t QCameraPostProcessor::processJpegEvt(qcamera_jpeg_evt_payload_t *evt)
533 {
534 int32_t rc = NO_ERROR;
535 camera_memory_t *jpeg_mem = NULL;
536
537 // find job by jobId
538 qcamera_jpeg_data_t *job = findJpegJobByJobId(evt->jobId);
539
540 if (job == NULL) {
541 ALOGE("%s: Cannot find jpeg job by jobId(%d)", __func__, evt->jobId);
542 rc = BAD_VALUE;
543 goto end;
544 }
545
546 ALOGD("[KPI Perf] %s : jpeg job %d", __func__, evt->jobId);
547
548 if (m_parent->mDataCb == NULL ||
549 m_parent->msgTypeEnabledWithLock(CAMERA_MSG_COMPRESSED_IMAGE) == 0 ) {
550 ALOGD("%s: No dataCB or CAMERA_MSG_COMPRESSED_IMAGE not enabled",
551 __func__);
552 rc = NO_ERROR;
553 goto end;
554 }
555
556 if(evt->status == JPEG_JOB_STATUS_ERROR) {
557 ALOGE("%s: Error event handled from jpeg, status = %d",
558 __func__, evt->status);
559 rc = FAILED_TRANSACTION;
560 goto end;
561 }
562
563 m_parent->dumpFrameToFile(evt->out_data.buf_vaddr,
564 evt->out_data.buf_filled_len,
565 evt->jobId,
566 QCAMERA_DUMP_FRM_JPEG);
567 ALOGD("%s: Dump jpeg_size=%d", __func__, evt->out_data.buf_filled_len);
568
569 // alloc jpeg memory to pass to upper layer
570 jpeg_mem = m_parent->mGetMemory(-1, evt->out_data.buf_filled_len, 1, m_parent->mCallbackCookie);
571 if (NULL == jpeg_mem) {
572 rc = NO_MEMORY;
573 ALOGE("%s : getMemory for jpeg, ret = NO_MEMORY", __func__);
574 goto end;
575 }
576 memcpy(jpeg_mem->data, evt->out_data.buf_vaddr, evt->out_data.buf_filled_len);
577
578 ALOGE("%s : Calling upperlayer callback to store JPEG image", __func__);
579 qcamera_release_data_t release_data;
580 memset(&release_data, 0, sizeof(qcamera_release_data_t));
581 release_data.data = jpeg_mem;
582 rc = sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE,
583 jpeg_mem,
584 0,
585 NULL,
586 &release_data);
587
588 end:
589 if (rc != NO_ERROR) {
590 // send error msg to upper layer
591 sendEvtNotify(CAMERA_MSG_ERROR,
592 UNKNOWN_ERROR,
593 0);
594
595 if (NULL != jpeg_mem) {
596 jpeg_mem->release(jpeg_mem);
597 jpeg_mem = NULL;
598 }
599 }
600
601 // release internal data for jpeg job
602 if (job != NULL) {
603 releaseJpegJobData(job);
604 free(job);
605 }
606
607 // wait up data proc thread to do next job,
608 // if previous request is blocked due to ongoing jpeg job
609 m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
610
611 return rc;
612 }
613
614 /*===========================================================================
615 * FUNCTION : processPPData
616 *
617 * DESCRIPTION: process received frame after reprocess.
618 *
619 * PARAMETERS :
620 * @frame : received frame from reprocess channel.
621 *
622 * RETURN : int32_t type of status
623 * NO_ERROR -- success
624 * none-zero failure code
625 *
626 * NOTE : The frame after reprocess need to send to jpeg encoding.
627 *==========================================================================*/
processPPData(mm_camera_super_buf_t * frame)628 int32_t QCameraPostProcessor::processPPData(mm_camera_super_buf_t *frame)
629 {
630 qcamera_pp_data_t *job = (qcamera_pp_data_t *)m_ongoingPPQ.dequeue();
631
632 if (job == NULL || job->src_frame == NULL) {
633 ALOGE("%s: Cannot find reprocess job", __func__);
634 return BAD_VALUE;
635 }
636
637 if (m_parent->mParameters.isNV16PictureFormat()) {
638 releaseSuperBuf(job->src_frame);
639 free(job->src_frame);
640 free(job);
641 return processRawData(frame);
642 }
643
644 qcamera_jpeg_data_t *jpeg_job =
645 (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t));
646 if (jpeg_job == NULL) {
647 ALOGE("%s: No memory for jpeg job", __func__);
648 return NO_MEMORY;
649 }
650
651 memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t));
652 jpeg_job->src_frame = frame;
653 jpeg_job->src_reproc_frame = job->src_frame;
654
655 // free pp job buf
656 free(job);
657
658 // enqueu reprocessed frame to jpeg input queue
659 m_inputJpegQ.enqueue((void *)jpeg_job);
660
661 // wait up data proc thread
662 m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
663
664 return NO_ERROR;
665 }
666
667 /*===========================================================================
668 * FUNCTION : findJpegJobByJobId
669 *
670 * DESCRIPTION: find a jpeg job from ongoing Jpeg queue by its job ID
671 *
672 * PARAMETERS :
673 * @jobId : job Id of the job
674 *
675 * RETURN : ptr to a jpeg job struct. NULL if not found.
676 *
677 * NOTE : Currently only one job is sending to mm-jpeg-interface for jpeg
678 * encoding. Therefore simply dequeue from the ongoing Jpeg Queue
679 * will serve the purpose to find the jpeg job.
680 *==========================================================================*/
findJpegJobByJobId(uint32_t jobId)681 qcamera_jpeg_data_t *QCameraPostProcessor::findJpegJobByJobId(uint32_t jobId)
682 {
683 qcamera_jpeg_data_t * job = NULL;
684 if (jobId == 0) {
685 ALOGE("%s: not a valid jpeg jobId", __func__);
686 return NULL;
687 }
688
689 // currely only one jpeg job ongoing, so simply dequeue the head
690 job = (qcamera_jpeg_data_t *)m_ongoingJpegQ.dequeue();
691 return job;
692 }
693
694 /*===========================================================================
695 * FUNCTION : releasePPInputData
696 *
697 * DESCRIPTION: callback function to release post process input data node
698 *
699 * PARAMETERS :
700 * @data : ptr to post process input data
701 * @user_data : user data ptr (QCameraReprocessor)
702 *
703 * RETURN : None
704 *==========================================================================*/
releasePPInputData(void * data,void * user_data)705 void QCameraPostProcessor::releasePPInputData(void *data, void *user_data)
706 {
707 QCameraPostProcessor *pme = (QCameraPostProcessor *)user_data;
708 if (NULL != pme) {
709 pme->releaseSuperBuf((mm_camera_super_buf_t *)data);
710 }
711 }
712
713 /*===========================================================================
714 * FUNCTION : releaseJpegData
715 *
716 * DESCRIPTION: callback function to release jpeg job node
717 *
718 * PARAMETERS :
719 * @data : ptr to ongoing jpeg job data
720 * @user_data : user data ptr (QCameraReprocessor)
721 *
722 * RETURN : None
723 *==========================================================================*/
releaseJpegData(void * data,void * user_data)724 void QCameraPostProcessor::releaseJpegData(void *data, void *user_data)
725 {
726 QCameraPostProcessor *pme = (QCameraPostProcessor *)user_data;
727 if (NULL != pme) {
728 pme->releaseJpegJobData((qcamera_jpeg_data_t *)data);
729 }
730 }
731
732 /*===========================================================================
733 * FUNCTION : releaseOngoingPPData
734 *
735 * DESCRIPTION: callback function to release ongoing postprocess job node
736 *
737 * PARAMETERS :
738 * @data : ptr to onging postprocess job
739 * @user_data : user data ptr (QCameraReprocessor)
740 *
741 * RETURN : None
742 *==========================================================================*/
releaseOngoingPPData(void * data,void * user_data)743 void QCameraPostProcessor::releaseOngoingPPData(void *data, void *user_data)
744 {
745 QCameraPostProcessor *pme = (QCameraPostProcessor *)user_data;
746 if (NULL != pme) {
747 qcamera_pp_data_t *pp_job = (qcamera_pp_data_t *)data;
748 if (NULL != pp_job->src_frame) {
749 pme->releaseSuperBuf(pp_job->src_frame);
750 free(pp_job->src_frame);
751 pp_job->src_frame = NULL;
752 }
753 }
754 }
755
756 /*===========================================================================
757 * FUNCTION : releaseNotifyData
758 *
759 * DESCRIPTION: function to release internal resources in notify data struct
760 *
761 * PARAMETERS :
762 * @user_data : ptr user data
763 * @cookie : callback cookie
764 *
765 * RETURN : None
766 *
767 * NOTE : deallocate jpeg heap memory if it's not NULL
768 *==========================================================================*/
releaseNotifyData(void * user_data,void * cookie)769 void QCameraPostProcessor::releaseNotifyData(void *user_data, void *cookie)
770 {
771 qcamera_data_argm_t *app_cb = ( qcamera_data_argm_t * ) user_data;
772 QCameraPostProcessor *postProc = ( QCameraPostProcessor * ) cookie;
773 if ( ( NULL != app_cb ) && ( NULL != postProc ) ) {
774 if (app_cb && NULL != app_cb->release_data.data) {
775 app_cb->release_data.data->release(app_cb->release_data.data);
776 app_cb->release_data.data = NULL;
777 }
778 if (app_cb && NULL != app_cb->release_data.frame) {
779 postProc->releaseSuperBuf(app_cb->release_data.frame);
780 free(app_cb->release_data.frame);
781 app_cb->release_data.frame = NULL;
782 }
783 free(app_cb);
784 }
785 }
786
787 /*===========================================================================
788 * FUNCTION : releaseSuperBuf
789 *
790 * DESCRIPTION: function to release a superbuf frame by returning back to kernel
791 *
792 * PARAMETERS :
793 * @super_buf : ptr to the superbuf frame
794 *
795 * RETURN : None
796 *==========================================================================*/
releaseSuperBuf(mm_camera_super_buf_t * super_buf)797 void QCameraPostProcessor::releaseSuperBuf(mm_camera_super_buf_t *super_buf)
798 {
799 QCameraChannel *pChannel = NULL;
800
801 if (NULL != super_buf) {
802 pChannel = m_parent->getChannelByHandle(super_buf->ch_id);
803
804 if ( NULL == pChannel ) {
805 if (m_pReprocChannel != NULL &&
806 m_pReprocChannel->getMyHandle() == super_buf->ch_id) {
807 pChannel = m_pReprocChannel;
808 }
809 }
810
811 if (pChannel != NULL) {
812 pChannel->bufDone(super_buf);
813 } else {
814 ALOGE(" %s : Channel id %d not found!!",
815 __func__,
816 super_buf->ch_id);
817 }
818 }
819 }
820
821 /*===========================================================================
822 * FUNCTION : releaseJpegJobData
823 *
824 * DESCRIPTION: function to release internal resources in jpeg job struct
825 *
826 * PARAMETERS :
827 * @job : ptr to jpeg job struct
828 *
829 * RETURN : None
830 *
831 * NOTE : original source frame need to be queued back to kernel for
832 * future use. Output buf of jpeg job need to be released since
833 * it's allocated for each job. Exif object need to be deleted.
834 *==========================================================================*/
releaseJpegJobData(qcamera_jpeg_data_t * job)835 void QCameraPostProcessor::releaseJpegJobData(qcamera_jpeg_data_t *job)
836 {
837 ALOGV("%s: E", __func__);
838 if (NULL != job) {
839 if (NULL != job->src_reproc_frame) {
840 releaseSuperBuf(job->src_reproc_frame);
841 free(job->src_reproc_frame);
842 job->src_reproc_frame = NULL;
843 }
844
845 if (NULL != job->src_frame) {
846 releaseSuperBuf(job->src_frame);
847 free(job->src_frame);
848 job->src_frame = NULL;
849 }
850 }
851 ALOGV("%s: X", __func__);
852 }
853
854 /*===========================================================================
855 * FUNCTION : getColorfmtFromImgFmt
856 *
857 * DESCRIPTION: function to return jpeg color format based on its image format
858 *
859 * PARAMETERS :
860 * @img_fmt : image format
861 *
862 * RETURN : jpeg color format that can be understandable by omx lib
863 *==========================================================================*/
getColorfmtFromImgFmt(cam_format_t img_fmt)864 mm_jpeg_color_format QCameraPostProcessor::getColorfmtFromImgFmt(cam_format_t img_fmt)
865 {
866 switch (img_fmt) {
867 case CAM_FORMAT_YUV_420_NV21:
868 return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
869 case CAM_FORMAT_YUV_420_NV21_ADRENO:
870 return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
871 case CAM_FORMAT_YUV_420_NV12:
872 return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2;
873 case CAM_FORMAT_YUV_420_YV12:
874 return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2;
875 case CAM_FORMAT_YUV_422_NV61:
876 return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1;
877 case CAM_FORMAT_YUV_422_NV16:
878 return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1;
879 default:
880 return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
881 }
882 }
883
884 /*===========================================================================
885 * FUNCTION : getJpegImgTypeFromImgFmt
886 *
887 * DESCRIPTION: function to return jpeg encode image type based on its image format
888 *
889 * PARAMETERS :
890 * @img_fmt : image format
891 *
892 * RETURN : return jpeg source image format (YUV or Bitstream)
893 *==========================================================================*/
getJpegImgTypeFromImgFmt(cam_format_t img_fmt)894 mm_jpeg_format_t QCameraPostProcessor::getJpegImgTypeFromImgFmt(cam_format_t img_fmt)
895 {
896 switch (img_fmt) {
897 case CAM_FORMAT_YUV_420_NV21:
898 case CAM_FORMAT_YUV_420_NV21_ADRENO:
899 case CAM_FORMAT_YUV_420_NV12:
900 case CAM_FORMAT_YUV_420_YV12:
901 case CAM_FORMAT_YUV_422_NV61:
902 case CAM_FORMAT_YUV_422_NV16:
903 return MM_JPEG_FMT_YUV;
904 default:
905 return MM_JPEG_FMT_YUV;
906 }
907 }
908
909 /*===========================================================================
910 * FUNCTION : encodeData
911 *
912 * DESCRIPTION: function to prepare encoding job information and send to
913 * mm-jpeg-interface to do the encoding job
914 *
915 * PARAMETERS :
916 * @jpeg_job_data : ptr to a struct saving job related information
917 * @needNewSess : flag to indicate if a new jpeg encoding session need
918 * to be created. After creation, this flag will be toggled
919 *
920 * RETURN : int32_t type of status
921 * NO_ERROR -- success
922 * none-zero failure code
923 *==========================================================================*/
encodeData(qcamera_jpeg_data_t * jpeg_job_data,uint8_t & needNewSess)924 int32_t QCameraPostProcessor::encodeData(qcamera_jpeg_data_t *jpeg_job_data,
925 uint8_t &needNewSess)
926 {
927 ALOGV("%s : E", __func__);
928 int32_t ret = NO_ERROR;
929 mm_jpeg_job_t jpg_job;
930 uint32_t jobId = 0;
931 QCameraStream *main_stream = NULL;
932 mm_camera_buf_def_t *main_frame = NULL;
933 QCameraStream *thumb_stream = NULL;
934 mm_camera_buf_def_t *thumb_frame = NULL;
935 mm_camera_super_buf_t *recvd_frame = jpeg_job_data->src_frame;
936
937 // find channel
938 QCameraChannel *pChannel = m_parent->getChannelByHandle(recvd_frame->ch_id);
939 // check reprocess channel if not found
940 if (pChannel == NULL) {
941 if (m_pReprocChannel != NULL &&
942 m_pReprocChannel->getMyHandle() == recvd_frame->ch_id) {
943 pChannel = m_pReprocChannel;
944 }
945 }
946 if (pChannel == NULL) {
947 ALOGE("%s: No corresponding channel (ch_id = %d) exist, return here",
948 __func__, recvd_frame->ch_id);
949 return BAD_VALUE;
950 }
951
952 // find snapshot frame and thumnail frame
953 for (int i = 0; i < recvd_frame->num_bufs; i++) {
954 QCameraStream *pStream =
955 pChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id);
956 if (pStream != NULL) {
957 if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
958 pStream->isTypeOf(CAM_STREAM_TYPE_NON_ZSL_SNAPSHOT) ||
959 pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
960 pStream->isOrignalTypeOf(CAM_STREAM_TYPE_NON_ZSL_SNAPSHOT)) {
961 main_stream = pStream;
962 main_frame = recvd_frame->bufs[i];
963 } else if (pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
964 pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) ||
965 pStream->isOrignalTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
966 pStream->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW)) {
967 thumb_stream = pStream;
968 thumb_frame = recvd_frame->bufs[i];
969 }
970 }
971 }
972
973 if(NULL == main_frame){
974 ALOGE("%s : Main frame is NULL", __func__);
975 return BAD_VALUE;
976 }
977
978 QCameraMemory *memObj = (QCameraMemory *)main_frame->mem_info;
979 if (NULL == memObj) {
980 ALOGE("%s : Memeory Obj of main frame is NULL", __func__);
981 return NO_MEMORY;
982 }
983
984 // dump snapshot frame if enabled
985 m_parent->dumpFrameToFile(main_frame->buffer, main_frame->frame_len,
986 main_frame->frame_idx, QCAMERA_DUMP_FRM_SNAPSHOT);
987
988 // send upperlayer callback for raw image
989 camera_memory_t *mem = memObj->getMemory(main_frame->buf_idx, false);
990 if (NULL != m_parent->mDataCb &&
991 m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE) > 0) {
992 qcamera_callback_argm_t cbArg;
993 memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
994 cbArg.cb_type = QCAMERA_DATA_CALLBACK;
995 cbArg.msg_type = CAMERA_MSG_RAW_IMAGE;
996 cbArg.data = mem;
997 cbArg.index = 1;
998 m_parent->m_cbNotifier.notifyCallback(cbArg);
999 }
1000 if (NULL != m_parent->mNotifyCb &&
1001 m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE_NOTIFY) > 0) {
1002 qcamera_callback_argm_t cbArg;
1003 memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
1004 cbArg.cb_type = QCAMERA_NOTIFY_CALLBACK;
1005 cbArg.msg_type = CAMERA_MSG_RAW_IMAGE_NOTIFY;
1006 cbArg.ext1 = 0;
1007 cbArg.ext2 = 0;
1008 m_parent->m_cbNotifier.notifyCallback(cbArg);
1009 }
1010
1011 if (thumb_frame != NULL) {
1012 // dump thumbnail frame if enabled
1013 m_parent->dumpFrameToFile(thumb_frame->buffer, thumb_frame->frame_len,
1014 thumb_frame->frame_idx, QCAMERA_DUMP_FRM_THUMBNAIL);
1015 }
1016
1017 if (mJpegClientHandle <= 0) {
1018 ALOGE("%s: Error: bug here, mJpegClientHandle is 0", __func__);
1019 return UNKNOWN_ERROR;
1020 }
1021
1022 if (needNewSess) {
1023 // create jpeg encoding session
1024 mm_jpeg_encode_params_t encodeParam;
1025 memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t));
1026 getJpegEncodingConfig(encodeParam, main_stream, thumb_stream);
1027 ALOGD("[KPI Perf] %s : call jpeg create_session", __func__);
1028 ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId);
1029 if (ret != NO_ERROR) {
1030 ALOGE("%s: error creating a new jpeg encoding session", __func__);
1031 return ret;
1032 }
1033 needNewSess = FALSE;
1034 }
1035
1036 // Fill in new job
1037 memset(&jpg_job, 0, sizeof(mm_jpeg_job_t));
1038 jpg_job.job_type = JPEG_JOB_TYPE_ENCODE;
1039 jpg_job.encode_job.session_id = mJpegSessionId;
1040 jpg_job.encode_job.src_index = main_frame->buf_idx;
1041 jpg_job.encode_job.dst_index = 0;
1042
1043 cam_rect_t crop;
1044 memset(&crop, 0, sizeof(cam_rect_t));
1045 main_stream->getCropInfo(crop);
1046
1047 cam_dimension_t src_dim;
1048 memset(&src_dim, 0, sizeof(cam_dimension_t));
1049 main_stream->getFrameDimension(src_dim);
1050
1051 // main dim
1052 jpg_job.encode_job.main_dim.src_dim = src_dim;
1053 jpg_job.encode_job.main_dim.dst_dim = src_dim;
1054 jpg_job.encode_job.main_dim.crop = crop;
1055
1056 // thumbnail dim
1057 if (m_bThumbnailNeeded == TRUE) {
1058 if (thumb_stream == NULL) {
1059 // need jpeg thumbnail, but no postview/preview stream exists
1060 // we use the main stream/frame to encode thumbnail
1061 thumb_stream = main_stream;
1062 thumb_frame = main_frame;
1063 }
1064 memset(&crop, 0, sizeof(cam_rect_t));
1065 thumb_stream->getCropInfo(crop);
1066 memset(&src_dim, 0, sizeof(cam_dimension_t));
1067 thumb_stream->getFrameDimension(src_dim);
1068 jpg_job.encode_job.thumb_dim.src_dim = src_dim;
1069 m_parent->getThumbnailSize(jpg_job.encode_job.thumb_dim.dst_dim);
1070 int rotation = m_parent->getJpegRotation();
1071 if (rotation == 90 || rotation ==270) {
1072 // swap dimension if rotation is 90 or 270
1073 int32_t temp = jpg_job.encode_job.thumb_dim.dst_dim.height;
1074 jpg_job.encode_job.thumb_dim.dst_dim.height =
1075 jpg_job.encode_job.thumb_dim.dst_dim.width;
1076 jpg_job.encode_job.thumb_dim.dst_dim.width = temp;
1077 }
1078 jpg_job.encode_job.thumb_dim.crop = crop;
1079 jpg_job.encode_job.thumb_index = thumb_frame->buf_idx;
1080 }
1081
1082 // set rotation only when no online rotation or offline pp rotation is done before
1083 if (!m_parent->needRotationReprocess()) {
1084 jpg_job.encode_job.rotation = m_parent->getJpegRotation();
1085 }
1086 ALOGV("%s: jpeg rotation is set to %d", __func__, jpg_job.encode_job.rotation);
1087
1088 // find meta data frame
1089 mm_camera_buf_def_t *meta_frame = NULL;
1090 for (int i = 0; i < jpeg_job_data->src_frame->num_bufs; i++) {
1091 // look through input superbuf
1092 if (jpeg_job_data->src_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) {
1093 meta_frame = jpeg_job_data->src_frame->bufs[i];
1094 break;
1095 }
1096 }
1097 if (meta_frame == NULL && jpeg_job_data->src_reproc_frame != NULL) {
1098 // look through reprocess source superbuf
1099 for (int i = 0; i < jpeg_job_data->src_reproc_frame->num_bufs; i++) {
1100 if (jpeg_job_data->src_reproc_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) {
1101 meta_frame = jpeg_job_data->src_reproc_frame->bufs[i];
1102 break;
1103 }
1104 }
1105 }
1106 if (meta_frame != NULL) {
1107 // fill in meta data frame ptr
1108 jpg_job.encode_job.p_metadata_v1 = (cam_metadata_info_t *)meta_frame->buffer;
1109 }
1110
1111 ALOGD("[KPI Perf] %s : call jpeg start_job", __func__);
1112 ret = mJpegHandle.start_job(&jpg_job, &jobId);
1113 if (ret == NO_ERROR) {
1114 // remember job info
1115 jpeg_job_data->jobId = jobId;
1116 }
1117
1118 return ret;
1119 }
1120
1121 /*===========================================================================
1122 * FUNCTION : processRawImageImpl
1123 *
1124 * DESCRIPTION: function to send raw image to upper layer
1125 *
1126 * PARAMETERS :
1127 * @recvd_frame : frame to be encoded
1128 *
1129 * RETURN : int32_t type of status
1130 * NO_ERROR -- success
1131 * none-zero failure code
1132 *==========================================================================*/
processRawImageImpl(mm_camera_super_buf_t * recvd_frame)1133 int32_t QCameraPostProcessor::processRawImageImpl(mm_camera_super_buf_t *recvd_frame)
1134 {
1135 int32_t rc = NO_ERROR;
1136
1137 mm_camera_buf_def_t *frame = NULL;
1138 for ( int i= 0 ; i < recvd_frame->num_bufs ; i++ ) {
1139 if ( recvd_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_SNAPSHOT ||
1140 recvd_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_NON_ZSL_SNAPSHOT ||
1141 recvd_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_RAW ) {
1142 frame = recvd_frame->bufs[i];
1143 break;
1144 }
1145 }
1146 if ( NULL == frame ) {
1147 ALOGE("%s: No valid raw buffer", __func__);
1148 return BAD_VALUE;
1149 }
1150
1151 QCameraMemory *rawMemObj = (QCameraMemory *)frame->mem_info;
1152 camera_memory_t *raw_mem = NULL;
1153
1154 if (rawMemObj != NULL) {
1155 raw_mem = rawMemObj->getMemory(frame->buf_idx, false);
1156 }
1157
1158 if (NULL != rawMemObj && NULL != raw_mem) {
1159 // dump frame into file
1160 m_parent->dumpFrameToFile(frame->buffer, frame->frame_len,
1161 frame->frame_idx, QCAMERA_DUMP_FRM_RAW);
1162
1163 // send data callback / notify for RAW_IMAGE
1164 if (NULL != m_parent->mDataCb &&
1165 m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE) > 0) {
1166 qcamera_callback_argm_t cbArg;
1167 memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
1168 cbArg.cb_type = QCAMERA_DATA_CALLBACK;
1169 cbArg.msg_type = CAMERA_MSG_RAW_IMAGE;
1170 cbArg.data = raw_mem;
1171 cbArg.index = 0;
1172 m_parent->m_cbNotifier.notifyCallback(cbArg);
1173 }
1174 if (NULL != m_parent->mNotifyCb &&
1175 m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE_NOTIFY) > 0) {
1176 qcamera_callback_argm_t cbArg;
1177 memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
1178 cbArg.cb_type = QCAMERA_NOTIFY_CALLBACK;
1179 cbArg.msg_type = CAMERA_MSG_RAW_IMAGE_NOTIFY;
1180 cbArg.ext1 = 0;
1181 cbArg.ext2 = 0;
1182 m_parent->m_cbNotifier.notifyCallback(cbArg);
1183 }
1184
1185 if ((m_parent->mDataCb != NULL) &&
1186 m_parent->msgTypeEnabledWithLock(CAMERA_MSG_COMPRESSED_IMAGE) > 0) {
1187 qcamera_release_data_t release_data;
1188 memset(&release_data, 0, sizeof(qcamera_release_data_t));
1189 release_data.frame = recvd_frame;
1190 sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE,
1191 raw_mem,
1192 0,
1193 NULL,
1194 &release_data);
1195 }
1196 } else {
1197 ALOGE("%s: Cannot get raw mem", __func__);
1198 rc = UNKNOWN_ERROR;
1199 }
1200
1201 return rc;
1202 }
1203
1204 /*===========================================================================
1205 * FUNCTION : dataProcessRoutine
1206 *
1207 * DESCRIPTION: data process routine that handles input data either from input
1208 * Jpeg Queue to do jpeg encoding, or from input PP Queue to do
1209 * reprocess.
1210 *
1211 * PARAMETERS :
1212 * @data : user data ptr (QCameraPostProcessor)
1213 *
1214 * RETURN : None
1215 *==========================================================================*/
dataProcessRoutine(void * data)1216 void *QCameraPostProcessor::dataProcessRoutine(void *data)
1217 {
1218 int running = 1;
1219 int ret;
1220 uint8_t is_active = FALSE;
1221 uint8_t needNewSess = TRUE;
1222 QCameraPostProcessor *pme = (QCameraPostProcessor *)data;
1223 QCameraCmdThread *cmdThread = &pme->m_dataProcTh;
1224
1225 ALOGD("%s: E", __func__);
1226 do {
1227 do {
1228 ret = cam_sem_wait(&cmdThread->cmd_sem);
1229 if (ret != 0 && errno != EINVAL) {
1230 ALOGE("%s: cam_sem_wait error (%s)",
1231 __func__, strerror(errno));
1232 return NULL;
1233 }
1234 } while (ret != 0);
1235
1236 // we got notified about new cmd avail in cmd queue
1237 camera_cmd_type_t cmd = cmdThread->getCmd();
1238 switch (cmd) {
1239 case CAMERA_CMD_TYPE_START_DATA_PROC:
1240 ALOGD("%s: start data proc", __func__);
1241 is_active = TRUE;
1242 needNewSess = TRUE;
1243 break;
1244 case CAMERA_CMD_TYPE_STOP_DATA_PROC:
1245 {
1246 ALOGD("%s: stop data proc", __func__);
1247 is_active = FALSE;
1248
1249 // cancel all ongoing jpeg jobs
1250 qcamera_jpeg_data_t *jpeg_job =
1251 (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
1252 while (jpeg_job != NULL) {
1253 pme->mJpegHandle.abort_job(jpeg_job->jobId);
1254
1255 pme->releaseJpegJobData(jpeg_job);
1256 free(jpeg_job);
1257
1258 jpeg_job = (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
1259 }
1260
1261 // destroy jpeg encoding session
1262 if ( 0 < pme->mJpegSessionId ) {
1263 pme->mJpegHandle.destroy_session(pme->mJpegSessionId);
1264 pme->mJpegSessionId = 0;
1265 }
1266
1267 // free jpeg out buf and exif obj
1268 if (pme->m_pJpegOutputMem != NULL) {
1269 pme->m_pJpegOutputMem->deallocate();
1270 delete pme->m_pJpegOutputMem;
1271 pme->m_pJpegOutputMem = NULL;
1272 }
1273 if (pme->m_pJpegExifObj != NULL) {
1274 delete pme->m_pJpegExifObj;
1275 pme->m_pJpegExifObj = NULL;
1276 }
1277 needNewSess = TRUE;
1278
1279 // stop reproc channel if exists
1280 if (pme->m_pReprocChannel != NULL) {
1281 pme->m_pReprocChannel->stop();
1282 delete pme->m_pReprocChannel;
1283 pme->m_pReprocChannel = NULL;
1284 }
1285
1286 // flush ongoing postproc Queue
1287 pme->m_ongoingPPQ.flush();
1288
1289 // flush input jpeg Queue
1290 pme->m_inputJpegQ.flush();
1291
1292 // flush input Postproc Queue
1293 pme->m_inputPPQ.flush();
1294
1295 // flush input raw Queue
1296 pme->m_inputRawQ.flush();
1297
1298 // signal cmd is completed
1299 cam_sem_post(&cmdThread->sync_sem);
1300 }
1301 break;
1302 case CAMERA_CMD_TYPE_DO_NEXT_JOB:
1303 {
1304 ALOGD("%s: Do next job, active is %d", __func__, is_active);
1305 if (is_active == TRUE) {
1306 // check if there is any ongoing jpeg jobs
1307 if (pme->m_ongoingJpegQ.isEmpty()) {
1308 // no ongoing jpeg job, we are fine to send jpeg encoding job
1309 qcamera_jpeg_data_t *jpeg_job =
1310 (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
1311
1312 if (NULL != jpeg_job) {
1313 //play shutter sound
1314 pme->m_parent->playShutter();
1315
1316 // add into ongoing jpeg job Q
1317 pme->m_ongoingJpegQ.enqueue((void *)jpeg_job);
1318 ret = pme->encodeData(jpeg_job, needNewSess);
1319 if (NO_ERROR != ret) {
1320 // dequeue the last one
1321 pme->m_ongoingJpegQ.dequeue(false);
1322
1323 pme->releaseJpegJobData(jpeg_job);
1324 free(jpeg_job);
1325 pme->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
1326 }
1327 }
1328 }
1329
1330 // process raw data if any
1331 mm_camera_super_buf_t *super_buf =
1332 (mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue();
1333
1334 if (NULL != super_buf) {
1335 //play shutter sound
1336 pme->m_parent->playShutter();
1337 ret = pme->processRawImageImpl(super_buf);
1338 if (NO_ERROR != ret) {
1339 pme->releaseSuperBuf(super_buf);
1340 free(super_buf);
1341 pme->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
1342 }
1343 }
1344
1345 mm_camera_super_buf_t *pp_frame =
1346 (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue();
1347 if (NULL != pp_frame) {
1348 qcamera_pp_data_t *pp_job =
1349 (qcamera_pp_data_t *)malloc(sizeof(qcamera_pp_data_t));
1350 if (pp_job != NULL) {
1351 memset(pp_job, 0, sizeof(qcamera_pp_data_t));
1352 if (pme->m_pReprocChannel != NULL) {
1353 // add into ongoing PP job Q
1354 pp_job->src_frame = pp_frame;
1355 pme->m_ongoingPPQ.enqueue((void *)pp_job);
1356 ret = pme->m_pReprocChannel->doReprocess(pp_frame);
1357 if (NO_ERROR != ret) {
1358 // remove from ongoing PP job Q
1359 pme->m_ongoingPPQ.dequeue(false);
1360 }
1361 } else {
1362 ALOGE("%s: Reprocess channel is NULL", __func__);
1363 ret = -1;
1364 }
1365 } else {
1366 ALOGE("%s: no mem for qcamera_pp_data_t", __func__);
1367 ret = -1;
1368 }
1369
1370 if (0 != ret) {
1371 // free pp_job
1372 if (pp_job != NULL) {
1373 free(pp_job);
1374 }
1375 // free frame
1376 if (pp_frame != NULL) {
1377 pme->releaseSuperBuf(pp_frame);
1378 free(pp_frame);
1379 }
1380 // send error notify
1381 pme->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
1382 }
1383 }
1384 } else {
1385 // not active, simply return buf and do no op
1386 qcamera_jpeg_data_t *jpeg_data =
1387 (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
1388 if (NULL != jpeg_data) {
1389 pme->releaseJpegJobData(jpeg_data);
1390 free(jpeg_data);
1391 }
1392 mm_camera_super_buf_t *super_buf =
1393 (mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue();
1394 if (NULL != super_buf) {
1395 pme->releaseSuperBuf(super_buf);
1396 free(super_buf);
1397 }
1398 super_buf = (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue();
1399 if (NULL != super_buf) {
1400 pme->releaseSuperBuf(super_buf);
1401 free(super_buf);
1402 }
1403 }
1404 }
1405 break;
1406 case CAMERA_CMD_TYPE_EXIT:
1407 running = 0;
1408 break;
1409 default:
1410 break;
1411 }
1412 } while (running);
1413 ALOGD("%s: X", __func__);
1414 return NULL;
1415 }
1416
1417 /*===========================================================================
1418 * FUNCTION : getJpegPaddingReq
1419 *
1420 * DESCRIPTION: function to add an entry to exif data
1421 *
1422 * PARAMETERS :
1423 * @padding_info : jpeg specific padding requirement
1424 *
1425 * RETURN : int32_t type of status
1426 * NO_ERROR -- success
1427 * none-zero failure code
1428 *==========================================================================*/
getJpegPaddingReq(cam_padding_info_t & padding_info)1429 int32_t QCameraPostProcessor::getJpegPaddingReq(cam_padding_info_t &padding_info)
1430 {
1431 // TODO: hardcode for now, needs to query from mm-jpeg-interface
1432 padding_info.width_padding = CAM_PAD_NONE;
1433 padding_info.height_padding = CAM_PAD_TO_16;
1434 padding_info.plane_padding = CAM_PAD_TO_WORD;
1435 return NO_ERROR;
1436 }
1437
1438 /*===========================================================================
1439 * FUNCTION : QCameraExif
1440 *
1441 * DESCRIPTION: constructor of QCameraExif
1442 *
1443 * PARAMETERS : None
1444 *
1445 * RETURN : None
1446 *==========================================================================*/
QCameraExif()1447 QCameraExif::QCameraExif()
1448 : m_nNumEntries(0)
1449 {
1450 memset(m_Entries, 0, sizeof(m_Entries));
1451 }
1452
1453 /*===========================================================================
1454 * FUNCTION : ~QCameraExif
1455 *
1456 * DESCRIPTION: deconstructor of QCameraExif. Will release internal memory ptr.
1457 *
1458 * PARAMETERS : None
1459 *
1460 * RETURN : None
1461 *==========================================================================*/
~QCameraExif()1462 QCameraExif::~QCameraExif()
1463 {
1464 for (uint32_t i = 0; i < m_nNumEntries; i++) {
1465 switch (m_Entries[i].tag_entry.type) {
1466 case EXIF_BYTE:
1467 {
1468 if (m_Entries[i].tag_entry.count > 1 &&
1469 m_Entries[i].tag_entry.data._bytes != NULL) {
1470 free(m_Entries[i].tag_entry.data._bytes);
1471 m_Entries[i].tag_entry.data._bytes = NULL;
1472 }
1473 }
1474 break;
1475 case EXIF_ASCII:
1476 {
1477 if (m_Entries[i].tag_entry.data._ascii != NULL) {
1478 free(m_Entries[i].tag_entry.data._ascii);
1479 m_Entries[i].tag_entry.data._ascii = NULL;
1480 }
1481 }
1482 break;
1483 case EXIF_SHORT:
1484 {
1485 if (m_Entries[i].tag_entry.count > 1 &&
1486 m_Entries[i].tag_entry.data._shorts != NULL) {
1487 free(m_Entries[i].tag_entry.data._shorts);
1488 m_Entries[i].tag_entry.data._shorts = NULL;
1489 }
1490 }
1491 break;
1492 case EXIF_LONG:
1493 {
1494 if (m_Entries[i].tag_entry.count > 1 &&
1495 m_Entries[i].tag_entry.data._longs != NULL) {
1496 free(m_Entries[i].tag_entry.data._longs);
1497 m_Entries[i].tag_entry.data._longs = NULL;
1498 }
1499 }
1500 break;
1501 case EXIF_RATIONAL:
1502 {
1503 if (m_Entries[i].tag_entry.count > 1 &&
1504 m_Entries[i].tag_entry.data._rats != NULL) {
1505 free(m_Entries[i].tag_entry.data._rats);
1506 m_Entries[i].tag_entry.data._rats = NULL;
1507 }
1508 }
1509 break;
1510 case EXIF_UNDEFINED:
1511 {
1512 if (m_Entries[i].tag_entry.data._undefined != NULL) {
1513 free(m_Entries[i].tag_entry.data._undefined);
1514 m_Entries[i].tag_entry.data._undefined = NULL;
1515 }
1516 }
1517 break;
1518 case EXIF_SLONG:
1519 {
1520 if (m_Entries[i].tag_entry.count > 1 &&
1521 m_Entries[i].tag_entry.data._slongs != NULL) {
1522 free(m_Entries[i].tag_entry.data._slongs);
1523 m_Entries[i].tag_entry.data._slongs = NULL;
1524 }
1525 }
1526 break;
1527 case EXIF_SRATIONAL:
1528 {
1529 if (m_Entries[i].tag_entry.count > 1 &&
1530 m_Entries[i].tag_entry.data._srats != NULL) {
1531 free(m_Entries[i].tag_entry.data._srats);
1532 m_Entries[i].tag_entry.data._srats = NULL;
1533 }
1534 }
1535 break;
1536 }
1537 }
1538 }
1539
1540 /*===========================================================================
1541 * FUNCTION : addEntry
1542 *
1543 * DESCRIPTION: function to add an entry to exif data
1544 *
1545 * PARAMETERS :
1546 * @tagid : exif tag ID
1547 * @type : data type
1548 * @count : number of data in uint of its type
1549 * @data : input data ptr
1550 *
1551 * RETURN : int32_t type of status
1552 * NO_ERROR -- success
1553 * none-zero failure code
1554 *==========================================================================*/
addEntry(exif_tag_id_t tagid,exif_tag_type_t type,uint32_t count,void * data)1555 int32_t QCameraExif::addEntry(exif_tag_id_t tagid,
1556 exif_tag_type_t type,
1557 uint32_t count,
1558 void *data)
1559 {
1560 int32_t rc = NO_ERROR;
1561 if(m_nNumEntries >= MAX_EXIF_TABLE_ENTRIES) {
1562 ALOGE("%s: Number of entries exceeded limit", __func__);
1563 return NO_MEMORY;
1564 }
1565
1566 m_Entries[m_nNumEntries].tag_id = tagid;
1567 m_Entries[m_nNumEntries].tag_entry.type = type;
1568 m_Entries[m_nNumEntries].tag_entry.count = count;
1569 m_Entries[m_nNumEntries].tag_entry.copy = 1;
1570 switch (type) {
1571 case EXIF_BYTE:
1572 {
1573 if (count > 1) {
1574 uint8_t *values = (uint8_t *)malloc(count);
1575 if (values == NULL) {
1576 ALOGE("%s: No memory for byte array", __func__);
1577 rc = NO_MEMORY;
1578 } else {
1579 memcpy(values, data, count);
1580 m_Entries[m_nNumEntries].tag_entry.data._bytes = values;
1581 }
1582 } else {
1583 m_Entries[m_nNumEntries].tag_entry.data._byte = *(uint8_t *)data;
1584 }
1585 }
1586 break;
1587 case EXIF_ASCII:
1588 {
1589 char *str = NULL;
1590 str = (char *)malloc(count + 1);
1591 if (str == NULL) {
1592 ALOGE("%s: No memory for ascii string", __func__);
1593 rc = NO_MEMORY;
1594 } else {
1595 memset(str, 0, count + 1);
1596 memcpy(str, data, count);
1597 m_Entries[m_nNumEntries].tag_entry.data._ascii = str;
1598 }
1599 }
1600 break;
1601 case EXIF_SHORT:
1602 {
1603 if (count > 1) {
1604 uint16_t *values = (uint16_t *)malloc(count * sizeof(uint16_t));
1605 if (values == NULL) {
1606 ALOGE("%s: No memory for short array", __func__);
1607 rc = NO_MEMORY;
1608 } else {
1609 memcpy(values, data, count * sizeof(uint16_t));
1610 m_Entries[m_nNumEntries].tag_entry.data._shorts = values;
1611 }
1612 } else {
1613 m_Entries[m_nNumEntries].tag_entry.data._short = *(uint16_t *)data;
1614 }
1615 }
1616 break;
1617 case EXIF_LONG:
1618 {
1619 if (count > 1) {
1620 uint32_t *values = (uint32_t *)malloc(count * sizeof(uint32_t));
1621 if (values == NULL) {
1622 ALOGE("%s: No memory for long array", __func__);
1623 rc = NO_MEMORY;
1624 } else {
1625 memcpy(values, data, count * sizeof(uint32_t));
1626 m_Entries[m_nNumEntries].tag_entry.data._longs = values;
1627 }
1628 } else {
1629 m_Entries[m_nNumEntries].tag_entry.data._long = *(uint32_t *)data;
1630 }
1631 }
1632 break;
1633 case EXIF_RATIONAL:
1634 {
1635 if (count > 1) {
1636 rat_t *values = (rat_t *)malloc(count * sizeof(rat_t));
1637 if (values == NULL) {
1638 ALOGE("%s: No memory for rational array", __func__);
1639 rc = NO_MEMORY;
1640 } else {
1641 memcpy(values, data, count * sizeof(rat_t));
1642 m_Entries[m_nNumEntries].tag_entry.data._rats = values;
1643 }
1644 } else {
1645 m_Entries[m_nNumEntries].tag_entry.data._rat = *(rat_t *)data;
1646 }
1647 }
1648 break;
1649 case EXIF_UNDEFINED:
1650 {
1651 uint8_t *values = (uint8_t *)malloc(count);
1652 if (values == NULL) {
1653 ALOGE("%s: No memory for undefined array", __func__);
1654 rc = NO_MEMORY;
1655 } else {
1656 memcpy(values, data, count);
1657 m_Entries[m_nNumEntries].tag_entry.data._undefined = values;
1658 }
1659 }
1660 break;
1661 case EXIF_SLONG:
1662 {
1663 if (count > 1) {
1664 int32_t *values = (int32_t *)malloc(count * sizeof(int32_t));
1665 if (values == NULL) {
1666 ALOGE("%s: No memory for signed long array", __func__);
1667 rc = NO_MEMORY;
1668 } else {
1669 memcpy(values, data, count * sizeof(int32_t));
1670 m_Entries[m_nNumEntries].tag_entry.data._slongs = values;
1671 }
1672 } else {
1673 m_Entries[m_nNumEntries].tag_entry.data._slong = *(int32_t *)data;
1674 }
1675 }
1676 break;
1677 case EXIF_SRATIONAL:
1678 {
1679 if (count > 1) {
1680 srat_t *values = (srat_t *)malloc(count * sizeof(srat_t));
1681 if (values == NULL) {
1682 ALOGE("%s: No memory for signed rational array", __func__);
1683 rc = NO_MEMORY;
1684 } else {
1685 memcpy(values, data, count * sizeof(srat_t));
1686 m_Entries[m_nNumEntries].tag_entry.data._srats = values;
1687 }
1688 } else {
1689 m_Entries[m_nNumEntries].tag_entry.data._srat = *(srat_t *)data;
1690 }
1691 }
1692 break;
1693 }
1694
1695 // Increase number of entries
1696 m_nNumEntries++;
1697 return rc;
1698 }
1699
1700 }; // namespace qcamera
1701