| /* Copyright (c) 2012-2014, The Linux Foundataion. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of The Linux Foundation nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| */ |
| |
| #define LOG_TAG "QCamera3PostProc" |
| //#define LOG_NDEBUG 0 |
| |
| #include <stdlib.h> |
| #include <utils/Errors.h> |
| |
| #include "QCamera3PostProc.h" |
| #include "QCamera3HWI.h" |
| #include "QCamera3Channel.h" |
| #include "QCamera3Stream.h" |
| |
| namespace qcamera { |
| |
| /*=========================================================================== |
| * FUNCTION : QCamera3PostProcessor |
| * |
| * DESCRIPTION: constructor of QCamera3PostProcessor. |
| * |
| * PARAMETERS : |
| * @cam_ctrl : ptr to HWI object |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| QCamera3PostProcessor::QCamera3PostProcessor(QCamera3PicChannel* ch_ctrl) |
| : m_parent(ch_ctrl), |
| mJpegCB(NULL), |
| mJpegUserData(NULL), |
| mJpegClientHandle(0), |
| mJpegSessionId(0), |
| m_pJpegExifObj(NULL), |
| m_bThumbnailNeeded(TRUE), |
| m_pReprocChannel(NULL), |
| m_inputPPQ(releasePPInputData, this), |
| m_ongoingPPQ(releaseOngoingPPData, this), |
| m_inputJpegQ(releaseJpegData, this), |
| m_ongoingJpegQ(releaseJpegData, this), |
| m_inputRawQ(releasePPInputData, this), |
| m_inputMetaQ(releaseMetaData, this), |
| m_jpegSettingsQ(releaseJpegSetting, this) |
| { |
| memset(&mJpegHandle, 0, sizeof(mJpegHandle)); |
| pthread_mutex_init(&mReprocJobLock, NULL); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : ~QCamera3PostProcessor |
| * |
| * DESCRIPTION: deconstructor of QCamera3PostProcessor. |
| * |
| * PARAMETERS : None |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| QCamera3PostProcessor::~QCamera3PostProcessor() |
| { |
| if (m_pJpegExifObj != NULL) { |
| delete m_pJpegExifObj; |
| m_pJpegExifObj = NULL; |
| } |
| pthread_mutex_destroy(&mReprocJobLock); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : init |
| * |
| * DESCRIPTION: initialization of postprocessor |
| * |
| * PARAMETERS : |
| * @jpeg_cb : callback to handle jpeg event from mm-camera-interface |
| * @user_data : user data ptr for jpeg callback |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCamera3PostProcessor::init(QCamera3Memory* mMemory, |
| jpeg_encode_callback_t jpeg_cb, void *user_data) |
| { |
| mJpegCB = jpeg_cb; |
| mJpegUserData = user_data; |
| mJpegMem = mMemory; |
| mJpegClientHandle = jpeg_open(&mJpegHandle); |
| if(!mJpegClientHandle) { |
| ALOGE("%s : jpeg_open did not work", __func__); |
| return UNKNOWN_ERROR; |
| } |
| |
| m_dataProcTh.launch(dataProcessRoutine, this); |
| |
| return NO_ERROR; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : deinit |
| * |
| * DESCRIPTION: de-initialization of postprocessor |
| * |
| * PARAMETERS : None |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCamera3PostProcessor::deinit() |
| { |
| m_dataProcTh.exit(); |
| |
| if (m_pReprocChannel != NULL) { |
| m_pReprocChannel->stop(); |
| delete m_pReprocChannel; |
| m_pReprocChannel = NULL; |
| } |
| |
| if(mJpegClientHandle > 0) { |
| int rc = mJpegHandle.close(mJpegClientHandle); |
| ALOGD("%s: Jpeg closed, rc = %d, mJpegClientHandle = %x", |
| __func__, rc, mJpegClientHandle); |
| mJpegClientHandle = 0; |
| memset(&mJpegHandle, 0, sizeof(mJpegHandle)); |
| } |
| |
| mJpegMem = NULL; |
| |
| return NO_ERROR; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : start |
| * |
| * DESCRIPTION: start postprocessor. Data process thread and data notify thread |
| * will be launched. |
| * |
| * PARAMETERS : |
| * @pMemory : memory object representing buffers to store JPEG. |
| * @pInputChannel : Input channel obj ptr that possibly needs reprocess |
| * @metadata : metadata for the reprocessing |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| * |
| * NOTE : if any reprocess is needed, a reprocess channel/stream |
| * will be started. |
| *==========================================================================*/ |
| int32_t QCamera3PostProcessor::start(QCamera3Channel *pInputChannel, |
| metadata_buffer_t *metadata) |
| { |
| int32_t rc = NO_ERROR; |
| QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData; |
| |
| if (hal_obj->needReprocess()) { |
| |
| while (!m_inputMetaQ.isEmpty()) { |
| m_pReprocChannel->metadataBufDone((mm_camera_super_buf_t *)m_inputMetaQ.dequeue()); |
| } |
| if (m_pReprocChannel != NULL) { |
| m_pReprocChannel->stop(); |
| delete m_pReprocChannel; |
| m_pReprocChannel = NULL; |
| } |
| |
| // if reprocess is needed, start reprocess channel |
| QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData; |
| ALOGV("%s: Setting input channel as pInputChannel", __func__); |
| m_pReprocChannel = hal_obj->addOfflineReprocChannel(pInputChannel, m_parent, metadata); |
| if (m_pReprocChannel == NULL) { |
| ALOGE("%s: cannot add reprocess channel", __func__); |
| return UNKNOWN_ERROR; |
| } |
| |
| rc = m_pReprocChannel->start(); |
| if (rc != 0) { |
| ALOGE("%s: cannot start reprocess channel", __func__); |
| delete m_pReprocChannel; |
| m_pReprocChannel = NULL; |
| return rc; |
| } |
| } |
| m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, FALSE, FALSE); |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : stop |
| * |
| * DESCRIPTION: stop postprocessor. Data process and notify thread will be stopped. |
| * |
| * PARAMETERS : None |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| * |
| * NOTE : reprocess channel will be stopped and deleted if there is any |
| *==========================================================================*/ |
| int32_t QCamera3PostProcessor::stop() |
| { |
| m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE); |
| |
| if (m_pReprocChannel != NULL) { |
| m_pReprocChannel->stop(); |
| delete m_pReprocChannel; |
| m_pReprocChannel = NULL; |
| } |
| |
| return NO_ERROR; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : getJpegEncodeConfig |
| * |
| * DESCRIPTION: function to prepare encoding job information |
| * |
| * PARAMETERS : |
| * @encode_parm : param to be filled with encoding configuration |
| * #main_stream : stream object where the input buffer comes from |
| * @jpeg_settings : jpeg settings to be applied for encoding |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCamera3PostProcessor::getJpegEncodeConfig( |
| mm_jpeg_encode_params_t& encode_parm, |
| QCamera3Stream *main_stream, |
| jpeg_settings_t *jpeg_settings) |
| { |
| ALOGV("%s : E", __func__); |
| int32_t ret = NO_ERROR; |
| |
| encode_parm.jpeg_cb = mJpegCB; |
| encode_parm.userdata = mJpegUserData; |
| |
| if (jpeg_settings->thumbnail_size.width > 0 && |
| jpeg_settings->thumbnail_size.height > 0) |
| m_bThumbnailNeeded = TRUE; |
| else |
| m_bThumbnailNeeded = FALSE; |
| encode_parm.encode_thumbnail = m_bThumbnailNeeded; |
| |
| // get color format |
| cam_format_t img_fmt = CAM_FORMAT_YUV_420_NV12; //default value |
| main_stream->getFormat(img_fmt); |
| encode_parm.color_format = getColorfmtFromImgFmt(img_fmt); |
| |
| // get jpeg quality |
| encode_parm.quality = jpeg_settings->jpeg_quality; |
| |
| // get jpeg thumbnail quality |
| encode_parm.thumb_quality = jpeg_settings->jpeg_thumb_quality; |
| |
| cam_frame_len_offset_t main_offset; |
| memset(&main_offset, 0, sizeof(cam_frame_len_offset_t)); |
| main_stream->getFrameOffset(main_offset); |
| |
| // src buf config |
| //Pass input main image buffer info to encoder. |
| QCamera3Memory *pStreamMem = main_stream->getStreamBufs(); |
| if (pStreamMem == NULL) { |
| ALOGE("%s: cannot get stream bufs from main stream", __func__); |
| ret = BAD_VALUE; |
| goto on_error; |
| } |
| encode_parm.num_src_bufs = pStreamMem->getCnt(); |
| for (uint32_t i = 0; i < encode_parm.num_src_bufs; i++) { |
| if (pStreamMem != NULL) { |
| encode_parm.src_main_buf[i].index = i; |
| encode_parm.src_main_buf[i].buf_size = pStreamMem->getSize(i); |
| encode_parm.src_main_buf[i].buf_vaddr = (uint8_t *)pStreamMem->getPtr(i); |
| encode_parm.src_main_buf[i].fd = pStreamMem->getFd(i); |
| encode_parm.src_main_buf[i].format = MM_JPEG_FMT_YUV; |
| encode_parm.src_main_buf[i].offset = main_offset; |
| } |
| } |
| |
| //Pass input thumbnail buffer info to encoder. |
| //Note: In this version thumb_stream = main_stream |
| if (m_bThumbnailNeeded == TRUE) { |
| pStreamMem = main_stream->getStreamBufs(); |
| if (pStreamMem == NULL) { |
| ALOGE("%s: cannot get stream bufs from thumb stream", __func__); |
| ret = BAD_VALUE; |
| goto on_error; |
| } |
| cam_frame_len_offset_t thumb_offset; |
| memset(&thumb_offset, 0, sizeof(cam_frame_len_offset_t)); |
| main_stream->getFrameOffset(thumb_offset); |
| encode_parm.num_tmb_bufs = pStreamMem->getCnt(); |
| for (int i = 0; i < pStreamMem->getCnt(); i++) { |
| if (pStreamMem != NULL) { |
| encode_parm.src_thumb_buf[i].index = i; |
| encode_parm.src_thumb_buf[i].buf_size = pStreamMem->getSize(i); |
| encode_parm.src_thumb_buf[i].buf_vaddr = (uint8_t *)pStreamMem->getPtr(i); |
| encode_parm.src_thumb_buf[i].fd = pStreamMem->getFd(i); |
| encode_parm.src_thumb_buf[i].format = MM_JPEG_FMT_YUV; |
| encode_parm.src_thumb_buf[i].offset = thumb_offset; |
| } |
| } |
| } |
| |
| //Pass output jpeg buffer info to encoder. |
| //mJpegMem is allocated by framework. |
| encode_parm.num_dst_bufs = 1; |
| encode_parm.dest_buf[0].index = 0; |
| encode_parm.dest_buf[0].buf_size = mJpegMem->getSize( |
| jpeg_settings->out_buf_index); |
| encode_parm.dest_buf[0].buf_vaddr = (uint8_t *)mJpegMem->getPtr( |
| jpeg_settings->out_buf_index); |
| encode_parm.dest_buf[0].fd = mJpegMem->getFd( |
| jpeg_settings->out_buf_index); |
| encode_parm.dest_buf[0].format = MM_JPEG_FMT_YUV; |
| encode_parm.dest_buf[0].offset = main_offset; |
| |
| ALOGV("%s : X", __func__); |
| return NO_ERROR; |
| |
| on_error: |
| |
| ALOGV("%s : X with error %d", __func__, ret); |
| return ret; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : processData |
| * |
| * DESCRIPTION: enqueue data into dataProc thread |
| * |
| * PARAMETERS : |
| * @frame : process frame received from mm-camera-interface |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| * |
| * NOTE : depends on if offline reprocess is needed, received frame will |
| * be sent to either input queue of postprocess or jpeg encoding |
| *==========================================================================*/ |
| int32_t QCamera3PostProcessor::processData(mm_camera_super_buf_t *frame) |
| { |
| QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData; |
| if (hal_obj->needReprocess()) { |
| pthread_mutex_lock(&mReprocJobLock); |
| // enqueu to post proc input queue |
| m_inputPPQ.enqueue((void *)frame); |
| if (!(m_inputMetaQ.isEmpty())) { |
| ALOGV("%s: meta queue is not empty, do next job", __func__); |
| m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
| } |
| pthread_mutex_unlock(&mReprocJobLock); |
| } else { |
| ALOGD("%s: no need offline reprocess, sending to jpeg encoding", __func__); |
| qcamera_jpeg_data_t *jpeg_job = |
| (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t)); |
| if (jpeg_job == NULL) { |
| ALOGE("%s: No memory for jpeg job", __func__); |
| return NO_MEMORY; |
| } |
| |
| memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t)); |
| jpeg_job->src_frame = frame; |
| |
| // enqueu to jpeg input queue |
| m_inputJpegQ.enqueue((void *)jpeg_job); |
| m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
| } |
| |
| return NO_ERROR; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : processPPMetadata |
| * |
| * DESCRIPTION: enqueue data into dataProc thread |
| * |
| * PARAMETERS : |
| * @frame : process metadata frame received from pic channel |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| * |
| *==========================================================================*/ |
| int32_t QCamera3PostProcessor::processPPMetadata(metadata_buffer_t *reproc_meta) |
| { |
| pthread_mutex_lock(&mReprocJobLock); |
| // enqueue to metadata input queue |
| m_inputMetaQ.enqueue((void *)reproc_meta); |
| if (!(m_inputPPQ.isEmpty())) { |
| ALOGI("%s: pp queue is not empty, do next job", __func__); |
| m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
| } else { |
| ALOGI("%s: pp queue is empty, not calling do next job", __func__); |
| } |
| pthread_mutex_unlock(&mReprocJobLock); |
| return NO_ERROR; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : processJpegSettingData |
| * |
| * DESCRIPTION: enqueue jpegSetting into dataProc thread |
| * |
| * PARAMETERS : |
| * @jpeg_settings : jpeg settings data received from pic channel |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| * |
| *==========================================================================*/ |
| int32_t QCamera3PostProcessor::processJpegSettingData( |
| jpeg_settings_t *jpeg_settings) |
| { |
| if (!jpeg_settings) { |
| ALOGE("%s: invalid jpeg settings pointer", __func__); |
| return -EINVAL; |
| } |
| return m_jpegSettingsQ.enqueue((void *)jpeg_settings); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : processRawData |
| * |
| * DESCRIPTION: enqueue raw data into dataProc thread |
| * |
| * PARAMETERS : |
| * @frame : process frame received from mm-camera-interface |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCamera3PostProcessor::processRawData(mm_camera_super_buf_t *frame) |
| { |
| // enqueu to raw input queue |
| m_inputRawQ.enqueue((void *)frame); |
| m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
| return NO_ERROR; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : processPPData |
| * |
| * DESCRIPTION: process received frame after reprocess. |
| * |
| * PARAMETERS : |
| * @frame : received frame from reprocess channel. |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| * |
| * NOTE : The frame after reprocess need to send to jpeg encoding. |
| *==========================================================================*/ |
| int32_t QCamera3PostProcessor::processPPData(mm_camera_super_buf_t *frame) |
| { |
| qcamera_pp_data_t *job = (qcamera_pp_data_t *)m_ongoingPPQ.dequeue(); |
| jpeg_settings_t *jpeg_settings = (jpeg_settings_t *)m_jpegSettingsQ.dequeue(); |
| |
| if (job == NULL || job->src_frame == NULL) { |
| ALOGE("%s: Cannot find reprocess job", __func__); |
| return BAD_VALUE; |
| } |
| if (jpeg_settings == NULL) { |
| ALOGE("%s: Cannot find jpeg settings", __func__); |
| return BAD_VALUE; |
| } |
| |
| qcamera_jpeg_data_t *jpeg_job = |
| (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t)); |
| if (jpeg_job == NULL) { |
| ALOGE("%s: No memory for jpeg job", __func__); |
| return NO_MEMORY; |
| } |
| |
| memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t)); |
| jpeg_job->src_frame = frame; |
| jpeg_job->src_reproc_frame = job->src_frame; |
| jpeg_job->metadata = job->metadata; |
| jpeg_job->jpeg_settings = jpeg_settings; |
| |
| // free pp job buf |
| free(job); |
| |
| // enqueu reprocessed frame to jpeg input queue |
| m_inputJpegQ.enqueue((void *)jpeg_job); |
| |
| // wait up data proc thread |
| m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
| |
| return NO_ERROR; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : findJpegJobByJobId |
| * |
| * DESCRIPTION: find a jpeg job from ongoing Jpeg queue by its job ID |
| * |
| * PARAMETERS : |
| * @jobId : job Id of the job |
| * |
| * RETURN : ptr to a jpeg job struct. NULL if not found. |
| * |
| * NOTE : Currently only one job is sending to mm-jpeg-interface for jpeg |
| * encoding. Therefore simply dequeue from the ongoing Jpeg Queue |
| * will serve the purpose to find the jpeg job. |
| *==========================================================================*/ |
| qcamera_jpeg_data_t *QCamera3PostProcessor::findJpegJobByJobId(uint32_t jobId) |
| { |
| qcamera_jpeg_data_t * job = NULL; |
| if (jobId == 0) { |
| ALOGE("%s: not a valid jpeg jobId", __func__); |
| return NULL; |
| } |
| |
| // currely only one jpeg job ongoing, so simply dequeue the head |
| job = (qcamera_jpeg_data_t *)m_ongoingJpegQ.dequeue(); |
| return job; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : releasePPInputData |
| * |
| * DESCRIPTION: callback function to release post process input data node |
| * |
| * PARAMETERS : |
| * @data : ptr to post process input data |
| * @user_data : user data ptr (QCamera3Reprocessor) |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void QCamera3PostProcessor::releasePPInputData(void *data, void *user_data) |
| { |
| QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data; |
| if (NULL != pme) { |
| pme->releaseSuperBuf((mm_camera_super_buf_t *)data); |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : releaseMetaData |
| * |
| * DESCRIPTION: callback function to release meta data node |
| * |
| * PARAMETERS : |
| * @data : ptr to post process input data |
| * @user_data : user data ptr (QCamera3Reprocessor) |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void QCamera3PostProcessor::releaseMetaData(void *data, void * /*user_data*/) |
| { |
| metadata_buffer_t *metadata = (metadata_buffer_t *)data; |
| if (metadata != NULL) |
| free(metadata); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : releaseJpegSetting |
| * |
| * DESCRIPTION: callback function to release meta data node |
| * |
| * PARAMETERS : |
| * @data : ptr to post process input data |
| * @user_data : user data ptr (QCamera3Reprocessor) |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void QCamera3PostProcessor::releaseJpegSetting(void *data, void * /*user_data*/) |
| { |
| jpeg_settings_t *jpegSetting = (jpeg_settings_t *)data; |
| if (jpegSetting != NULL) |
| free(jpegSetting); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : releaseJpegData |
| * |
| * DESCRIPTION: callback function to release jpeg job node |
| * |
| * PARAMETERS : |
| * @data : ptr to ongoing jpeg job data |
| * @user_data : user data ptr (QCamera3Reprocessor) |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void QCamera3PostProcessor::releaseJpegData(void *data, void *user_data) |
| { |
| QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data; |
| if (NULL != pme) { |
| pme->releaseJpegJobData((qcamera_jpeg_data_t *)data); |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : releaseOngoingPPData |
| * |
| * DESCRIPTION: callback function to release ongoing postprocess job node |
| * |
| * PARAMETERS : |
| * @data : ptr to onging postprocess job |
| * @user_data : user data ptr (QCamera3Reprocessor) |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void QCamera3PostProcessor::releaseOngoingPPData(void *data, void *user_data) |
| { |
| QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data; |
| if (NULL != pme) { |
| qcamera_pp_data_t *pp_job = (qcamera_pp_data_t *)data; |
| if (NULL != pp_job->src_frame) { |
| pme->releaseSuperBuf(pp_job->src_frame); |
| free(pp_job->src_frame); |
| free(pp_job->metadata); |
| pp_job->src_frame = NULL; |
| pp_job->metadata = NULL; |
| } |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : releaseSuperBuf |
| * |
| * DESCRIPTION: function to release a superbuf frame by returning back to kernel |
| * |
| * PARAMETERS : |
| * @super_buf : ptr to the superbuf frame |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void QCamera3PostProcessor::releaseSuperBuf(mm_camera_super_buf_t *super_buf) |
| { |
| if (NULL != super_buf) { |
| if (m_parent != NULL) { |
| m_parent->bufDone(super_buf); |
| } |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : releaseJpegJobData |
| * |
| * DESCRIPTION: function to release internal resources in jpeg job struct |
| * |
| * PARAMETERS : |
| * @job : ptr to jpeg job struct |
| * |
| * RETURN : None |
| * |
| * NOTE : original source frame need to be queued back to kernel for |
| * future use. Output buf of jpeg job need to be released since |
| * it's allocated for each job. Exif object need to be deleted. |
| *==========================================================================*/ |
| void QCamera3PostProcessor::releaseJpegJobData(qcamera_jpeg_data_t *job) |
| { |
| ALOGV("%s: E", __func__); |
| if (NULL != job) { |
| if (NULL != job->src_reproc_frame) { |
| free(job->src_reproc_frame); |
| job->src_reproc_frame = NULL; |
| } |
| |
| if (NULL != job->src_frame) { |
| free(job->src_frame); |
| job->src_frame = NULL; |
| } |
| |
| if (NULL != job->metadata) { |
| free(job->metadata); |
| job->metadata = NULL; |
| } |
| |
| if (NULL != job->jpeg_settings) { |
| free(job->jpeg_settings); |
| job->jpeg_settings = NULL; |
| } |
| } |
| ALOGV("%s: X", __func__); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : getColorfmtFromImgFmt |
| * |
| * DESCRIPTION: function to return jpeg color format based on its image format |
| * |
| * PARAMETERS : |
| * @img_fmt : image format |
| * |
| * RETURN : jpeg color format that can be understandable by omx lib |
| *==========================================================================*/ |
| mm_jpeg_color_format QCamera3PostProcessor::getColorfmtFromImgFmt(cam_format_t img_fmt) |
| { |
| switch (img_fmt) { |
| case CAM_FORMAT_YUV_420_NV21: |
| return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2; |
| case CAM_FORMAT_YUV_420_NV21_ADRENO: |
| return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2; |
| case CAM_FORMAT_YUV_420_NV12: |
| return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2; |
| case CAM_FORMAT_YUV_420_YV12: |
| return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2; |
| case CAM_FORMAT_YUV_422_NV61: |
| return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1; |
| case CAM_FORMAT_YUV_422_NV16: |
| return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1; |
| default: |
| return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2; |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : getJpegImgTypeFromImgFmt |
| * |
| * DESCRIPTION: function to return jpeg encode image type based on its image format |
| * |
| * PARAMETERS : |
| * @img_fmt : image format |
| * |
| * RETURN : return jpeg source image format (YUV or Bitstream) |
| *==========================================================================*/ |
| mm_jpeg_format_t QCamera3PostProcessor::getJpegImgTypeFromImgFmt(cam_format_t img_fmt) |
| { |
| switch (img_fmt) { |
| case CAM_FORMAT_YUV_420_NV21: |
| case CAM_FORMAT_YUV_420_NV21_ADRENO: |
| case CAM_FORMAT_YUV_420_NV12: |
| case CAM_FORMAT_YUV_420_YV12: |
| case CAM_FORMAT_YUV_422_NV61: |
| case CAM_FORMAT_YUV_422_NV16: |
| return MM_JPEG_FMT_YUV; |
| default: |
| return MM_JPEG_FMT_YUV; |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : encodeData |
| * |
| * DESCRIPTION: function to prepare encoding job information and send to |
| * mm-jpeg-interface to do the encoding job |
| * |
| * PARAMETERS : |
| * @jpeg_job_data : ptr to a struct saving job related information |
| * @needNewSess : flag to indicate if a new jpeg encoding session need |
| * to be created. After creation, this flag will be toggled |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCamera3PostProcessor::encodeData(qcamera_jpeg_data_t *jpeg_job_data, |
| uint8_t &needNewSess) |
| { |
| ALOGV("%s : E", __func__); |
| int32_t ret = NO_ERROR; |
| mm_jpeg_job_t jpg_job; |
| uint32_t jobId = 0; |
| QCamera3Stream *main_stream = NULL; |
| mm_camera_buf_def_t *main_frame = NULL; |
| QCamera3Stream *thumb_stream = NULL; |
| mm_camera_buf_def_t *thumb_frame = NULL; |
| QCamera3Channel *srcChannel = NULL; |
| mm_camera_super_buf_t *recvd_frame = NULL; |
| metadata_buffer_t *metadata = NULL; |
| jpeg_settings_t *jpeg_settings = NULL; |
| QCamera3HardwareInterface* hal_obj = NULL; |
| |
| |
| hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData; |
| recvd_frame = jpeg_job_data->src_frame; |
| metadata = jpeg_job_data->metadata; |
| jpeg_settings = jpeg_job_data->jpeg_settings; |
| |
| QCamera3Channel *pChannel = NULL; |
| // first check picture channel |
| if (m_parent != NULL && |
| m_parent->getMyHandle() == recvd_frame->ch_id) { |
| pChannel = m_parent; |
| } |
| // check reprocess channel if not found |
| if (pChannel == NULL) { |
| if (m_pReprocChannel != NULL && |
| m_pReprocChannel->getMyHandle() == recvd_frame->ch_id) { |
| pChannel = m_pReprocChannel; |
| } |
| } |
| |
| srcChannel = pChannel; |
| |
| if (srcChannel == NULL) { |
| ALOGE("%s: No corresponding channel (ch_id = %d) exist, return here", |
| __func__, recvd_frame->ch_id); |
| return BAD_VALUE; |
| } |
| |
| // find snapshot frame and thumnail frame |
| //Note: In this version we will receive only snapshot frame. |
| for (int i = 0; i < recvd_frame->num_bufs; i++) { |
| QCamera3Stream *srcStream = |
| srcChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id); |
| if (srcStream != NULL) { |
| switch (srcStream->getMyType()) { |
| case CAM_STREAM_TYPE_SNAPSHOT: |
| case CAM_STREAM_TYPE_NON_ZSL_SNAPSHOT: |
| case CAM_STREAM_TYPE_OFFLINE_PROC: |
| main_stream = srcStream; |
| main_frame = recvd_frame->bufs[i]; |
| break; |
| case CAM_STREAM_TYPE_PREVIEW: |
| case CAM_STREAM_TYPE_POSTVIEW: |
| thumb_stream = srcStream; |
| thumb_frame = recvd_frame->bufs[i]; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| if(NULL == main_frame){ |
| ALOGE("%s : Main frame is NULL", __func__); |
| return BAD_VALUE; |
| } |
| |
| QCamera3Memory *memObj = (QCamera3Memory *)main_frame->mem_info; |
| if (NULL == memObj) { |
| ALOGE("%s : Memeory Obj of main frame is NULL", __func__); |
| return NO_MEMORY; |
| } |
| |
| // clean and invalidate cache ops through mem obj of the frame |
| memObj->cleanInvalidateCache(main_frame->buf_idx); |
| |
| if (thumb_frame != NULL) { |
| QCamera3Memory *thumb_memObj = (QCamera3Memory *)thumb_frame->mem_info; |
| if (NULL != thumb_memObj) { |
| // clean and invalidate cache ops through mem obj of the frame |
| thumb_memObj->cleanInvalidateCache(thumb_frame->buf_idx); |
| } |
| } |
| |
| if (mJpegClientHandle <= 0) { |
| ALOGE("%s: Error: bug here, mJpegClientHandle is 0", __func__); |
| return UNKNOWN_ERROR; |
| } |
| |
| ALOGD("%s: Need new session?:%d",__func__, needNewSess); |
| if (needNewSess) { |
| //creating a new session, so we must destroy the old one |
| if ( 0 < mJpegSessionId ) { |
| ret = mJpegHandle.destroy_session(mJpegSessionId); |
| if (ret != NO_ERROR) { |
| ALOGE("%s: Error destroying an old jpeg encoding session, id = %d", |
| __func__, mJpegSessionId); |
| return ret; |
| } |
| mJpegSessionId = 0; |
| } |
| // create jpeg encoding session |
| mm_jpeg_encode_params_t encodeParam; |
| memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t)); |
| |
| getJpegEncodeConfig(encodeParam, main_stream, jpeg_settings); |
| ALOGD("%s: #src bufs:%d # tmb bufs:%d #dst_bufs:%d", __func__, |
| encodeParam.num_src_bufs,encodeParam.num_tmb_bufs,encodeParam.num_dst_bufs); |
| ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId); |
| if (ret != NO_ERROR) { |
| ALOGE("%s: Error creating a new jpeg encoding session, ret = %d", __func__, ret); |
| return ret; |
| } |
| needNewSess = FALSE; |
| } |
| |
| // Fill in new job |
| memset(&jpg_job, 0, sizeof(mm_jpeg_job_t)); |
| jpg_job.job_type = JPEG_JOB_TYPE_ENCODE; |
| jpg_job.encode_job.session_id = mJpegSessionId; |
| jpg_job.encode_job.src_index = main_frame->buf_idx; |
| jpg_job.encode_job.dst_index = 0; |
| |
| cam_rect_t crop; |
| memset(&crop, 0, sizeof(cam_rect_t)); |
| //TBD_later - Zoom event removed in stream |
| //main_stream->getCropInfo(crop); |
| |
| cam_dimension_t src_dim; |
| memset(&src_dim, 0, sizeof(cam_dimension_t)); |
| main_stream->getFrameDimension(src_dim); |
| |
| cam_dimension_t dst_dim; |
| memset(&dst_dim, 0, sizeof(cam_dimension_t)); |
| srcChannel->getStreamByIndex(0)->getFrameDimension(dst_dim); |
| |
| // main dim |
| jpg_job.encode_job.main_dim.src_dim = src_dim; |
| jpg_job.encode_job.main_dim.dst_dim = dst_dim; |
| jpg_job.encode_job.main_dim.crop = crop; |
| |
| // get exif data |
| if (m_pJpegExifObj != NULL) { |
| delete m_pJpegExifObj; |
| m_pJpegExifObj = NULL; |
| } |
| m_pJpegExifObj = m_parent->getExifData(metadata, jpeg_settings); |
| if (m_pJpegExifObj != NULL) { |
| jpg_job.encode_job.exif_info.exif_data = m_pJpegExifObj->getEntries(); |
| jpg_job.encode_job.exif_info.numOfEntries = |
| m_pJpegExifObj->getNumOfEntries(); |
| } |
| // thumbnail dim |
| ALOGD("%s: Thumbnail needed:%d",__func__, m_bThumbnailNeeded); |
| if (m_bThumbnailNeeded == TRUE) { |
| if (thumb_stream == NULL) { |
| // need jpeg thumbnail, but no postview/preview stream exists |
| // we use the main stream/frame to encode thumbnail |
| thumb_stream = main_stream; |
| thumb_frame = main_frame; |
| } |
| memset(&crop, 0, sizeof(cam_rect_t)); |
| //TBD_later - Zoom event removed in stream |
| //thumb_stream->getCropInfo(crop); |
| jpg_job.encode_job.thumb_dim.dst_dim = |
| jpeg_settings->thumbnail_size; |
| |
| if (!hal_obj->needRotationReprocess()) { |
| memset(&src_dim, 0, sizeof(cam_dimension_t)); |
| thumb_stream->getFrameDimension(src_dim); |
| jpg_job.encode_job.rotation = |
| jpeg_settings->jpeg_orientation; |
| ALOGD("%s: jpeg rotation is set to %d", __func__, |
| jpg_job.encode_job.rotation); |
| } else if (jpeg_settings->jpeg_orientation == 90 || |
| jpeg_settings->jpeg_orientation == 270) { |
| //swap the thumbnail destination width and height if it has already been rotated |
| int temp = jpg_job.encode_job.thumb_dim.dst_dim.width; |
| jpg_job.encode_job.thumb_dim.dst_dim.width = |
| jpg_job.encode_job.thumb_dim.dst_dim.height; |
| jpg_job.encode_job.thumb_dim.dst_dim.height = temp; |
| } |
| jpg_job.encode_job.thumb_dim.src_dim = src_dim; |
| jpg_job.encode_job.thumb_dim.crop = crop; |
| jpg_job.encode_job.thumb_index = thumb_frame->buf_idx; |
| } |
| |
| if (metadata != NULL) { |
| //Fill in the metadata passed as parameter |
| jpg_job.encode_job.p_metadata_v3 = metadata; |
| } else { |
| ALOGE("%s: Metadata is null", __func__); |
| } |
| //Not required here |
| //jpg_job.encode_job.cam_exif_params = m_parent->mExifParams; |
| //Start jpeg encoding |
| ret = mJpegHandle.start_job(&jpg_job, &jobId); |
| if (ret == NO_ERROR) { |
| // remember job info |
| jpeg_job_data->jobId = jobId; |
| } |
| |
| ALOGV("%s : X", __func__); |
| return ret; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : dataProcessRoutine |
| * |
| * DESCRIPTION: data process routine that handles input data either from input |
| * Jpeg Queue to do jpeg encoding, or from input PP Queue to do |
| * reprocess. |
| * |
| * PARAMETERS : |
| * @data : user data ptr (QCamera3PostProcessor) |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void *QCamera3PostProcessor::dataProcessRoutine(void *data) |
| { |
| int running = 1; |
| int ret; |
| uint8_t is_active = FALSE; |
| uint8_t needNewSess = TRUE; |
| mm_camera_super_buf_t *pp_frame = NULL; |
| metadata_buffer_t *meta_buffer = NULL; |
| ALOGV("%s: E", __func__); |
| QCamera3PostProcessor *pme = (QCamera3PostProcessor *)data; |
| QCameraCmdThread *cmdThread = &pme->m_dataProcTh; |
| cmdThread->setName("cam_data_proc"); |
| |
| do { |
| do { |
| ret = cam_sem_wait(&cmdThread->cmd_sem); |
| if (ret != 0 && errno != EINVAL) { |
| ALOGE("%s: cam_sem_wait error (%s)", |
| __func__, strerror(errno)); |
| return NULL; |
| } |
| } while (ret != 0); |
| |
| // we got notified about new cmd avail in cmd queue |
| camera_cmd_type_t cmd = cmdThread->getCmd(); |
| switch (cmd) { |
| case CAMERA_CMD_TYPE_START_DATA_PROC: |
| ALOGD("%s: start data proc", __func__); |
| is_active = TRUE; |
| needNewSess = TRUE; |
| |
| pme->m_ongoingPPQ.init(); |
| pme->m_inputJpegQ.init(); |
| pme->m_inputPPQ.init(); |
| pme->m_inputRawQ.init(); |
| pme->m_inputMetaQ.init(); |
| pme->m_ongoingJpegQ.init(); |
| pme->m_jpegSettingsQ.init(); |
| |
| break; |
| case CAMERA_CMD_TYPE_STOP_DATA_PROC: |
| { |
| ALOGD("%s: stop data proc", __func__); |
| is_active = FALSE; |
| |
| // cancel all ongoing jpeg jobs |
| qcamera_jpeg_data_t *jpeg_job = |
| (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue(); |
| while (jpeg_job != NULL) { |
| pme->mJpegHandle.abort_job(jpeg_job->jobId); |
| |
| pme->releaseJpegJobData(jpeg_job); |
| free(jpeg_job); |
| |
| jpeg_job = (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue(); |
| } |
| |
| // destroy jpeg encoding session |
| if ( 0 < pme->mJpegSessionId ) { |
| pme->mJpegHandle.destroy_session(pme->mJpegSessionId); |
| pme->mJpegSessionId = 0; |
| } |
| |
| // free jpeg exif obj |
| if (pme->m_pJpegExifObj != NULL) { |
| delete pme->m_pJpegExifObj; |
| pme->m_pJpegExifObj = NULL; |
| } |
| needNewSess = TRUE; |
| |
| // flush ongoing postproc Queue |
| pme->m_ongoingPPQ.flush(); |
| |
| // flush input jpeg Queue |
| pme->m_inputJpegQ.flush(); |
| |
| // flush input Postproc Queue |
| pme->m_inputPPQ.flush(); |
| |
| // flush input raw Queue |
| pme->m_inputRawQ.flush(); |
| |
| pme->m_inputMetaQ.flush(); |
| |
| // signal cmd is completed |
| cam_sem_post(&cmdThread->sync_sem); |
| } |
| break; |
| case CAMERA_CMD_TYPE_DO_NEXT_JOB: |
| { |
| ALOGD("%s: Do next job, active is %d", __func__, is_active); |
| if (is_active == TRUE) { |
| // check if there is any ongoing jpeg jobs |
| if (pme->m_ongoingJpegQ.isEmpty()) { |
| ALOGI("%s: ongoing jpeg queue is empty so doing the jpeg job", __func__); |
| // no ongoing jpeg job, we are fine to send jpeg encoding job |
| qcamera_jpeg_data_t *jpeg_job = |
| (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue(); |
| |
| if (NULL != jpeg_job) { |
| // add into ongoing jpeg job Q |
| pme->m_ongoingJpegQ.enqueue((void *)jpeg_job); |
| ret = pme->encodeData(jpeg_job, needNewSess); |
| if (NO_ERROR != ret) { |
| // dequeue the last one |
| pme->m_ongoingJpegQ.dequeue(false); |
| |
| pme->releaseJpegJobData(jpeg_job); |
| free(jpeg_job); |
| } |
| } |
| } |
| ALOGD("%s: dequeuing pp frame", __func__); |
| pp_frame = |
| (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue(); |
| meta_buffer = |
| (metadata_buffer_t *)pme->m_inputMetaQ.dequeue(); |
| if (NULL != pp_frame && NULL != meta_buffer) { |
| qcamera_pp_data_t *pp_job = |
| (qcamera_pp_data_t *)malloc(sizeof(qcamera_pp_data_t)); |
| if (pp_job != NULL) { |
| memset(pp_job, 0, sizeof(qcamera_pp_data_t)); |
| if (pme->m_pReprocChannel != NULL) { |
| // add into ongoing PP job Q |
| pp_job->src_frame = pp_frame; |
| pp_job->metadata = meta_buffer; |
| pme->m_ongoingPPQ.enqueue((void *)pp_job); |
| ret = pme->m_pReprocChannel->doReprocessOffline(pp_frame, meta_buffer); |
| if (NO_ERROR != ret) { |
| // remove from ongoing PP job Q |
| pme->m_ongoingPPQ.dequeue(false); |
| } |
| } else { |
| ALOGE("%s: Reprocess channel is NULL", __func__); |
| ret = -1; |
| } |
| } else { |
| ALOGE("%s: no mem for qcamera_pp_data_t", __func__); |
| ret = -1; |
| } |
| |
| if (0 != ret) { |
| // free pp_job |
| if (pp_job != NULL) { |
| free(pp_job); |
| } |
| // free frame |
| if (pp_frame != NULL) { |
| pme->releaseSuperBuf(pp_frame); |
| free(pp_frame); |
| } |
| } |
| } |
| } else { |
| // not active, simply return buf and do no op |
| mm_camera_super_buf_t *super_buf; |
| qcamera_jpeg_data_t *jpeg_job = |
| (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue(); |
| if (NULL != jpeg_job) { |
| free(jpeg_job); |
| } |
| super_buf = (mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue(); |
| if (NULL != super_buf) { |
| pme->releaseSuperBuf(super_buf); |
| free(super_buf); |
| } |
| super_buf = (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue(); |
| if (NULL != super_buf) { |
| pme->releaseSuperBuf(super_buf); |
| free(super_buf); |
| } |
| super_buf = (mm_camera_super_buf_t *)pme->m_inputMetaQ.dequeue(); |
| if (NULL != super_buf) { |
| pme->releaseSuperBuf(super_buf); |
| free(super_buf); |
| } |
| } |
| } |
| break; |
| case CAMERA_CMD_TYPE_EXIT: |
| running = 0; |
| break; |
| default: |
| break; |
| } |
| } while (running); |
| ALOGV("%s: X", __func__); |
| return NULL; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : QCamera3Exif |
| * |
| * DESCRIPTION: constructor of QCamera3Exif |
| * |
| * PARAMETERS : None |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| QCamera3Exif::QCamera3Exif() |
| : m_nNumEntries(0) |
| { |
| memset(m_Entries, 0, sizeof(m_Entries)); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : ~QCamera3Exif |
| * |
| * DESCRIPTION: deconstructor of QCamera3Exif. Will release internal memory ptr. |
| * |
| * PARAMETERS : None |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| QCamera3Exif::~QCamera3Exif() |
| { |
| for (uint32_t i = 0; i < m_nNumEntries; i++) { |
| switch (m_Entries[i].tag_entry.type) { |
| case EXIF_BYTE: |
| { |
| if (m_Entries[i].tag_entry.count > 1 && |
| m_Entries[i].tag_entry.data._bytes != NULL) { |
| free(m_Entries[i].tag_entry.data._bytes); |
| m_Entries[i].tag_entry.data._bytes = NULL; |
| } |
| } |
| break; |
| case EXIF_ASCII: |
| { |
| if (m_Entries[i].tag_entry.data._ascii != NULL) { |
| free(m_Entries[i].tag_entry.data._ascii); |
| m_Entries[i].tag_entry.data._ascii = NULL; |
| } |
| } |
| break; |
| case EXIF_SHORT: |
| { |
| if (m_Entries[i].tag_entry.count > 1 && |
| m_Entries[i].tag_entry.data._shorts != NULL) { |
| free(m_Entries[i].tag_entry.data._shorts); |
| m_Entries[i].tag_entry.data._shorts = NULL; |
| } |
| } |
| break; |
| case EXIF_LONG: |
| { |
| if (m_Entries[i].tag_entry.count > 1 && |
| m_Entries[i].tag_entry.data._longs != NULL) { |
| free(m_Entries[i].tag_entry.data._longs); |
| m_Entries[i].tag_entry.data._longs = NULL; |
| } |
| } |
| break; |
| case EXIF_RATIONAL: |
| { |
| if (m_Entries[i].tag_entry.count > 1 && |
| m_Entries[i].tag_entry.data._rats != NULL) { |
| free(m_Entries[i].tag_entry.data._rats); |
| m_Entries[i].tag_entry.data._rats = NULL; |
| } |
| } |
| break; |
| case EXIF_UNDEFINED: |
| { |
| if (m_Entries[i].tag_entry.data._undefined != NULL) { |
| free(m_Entries[i].tag_entry.data._undefined); |
| m_Entries[i].tag_entry.data._undefined = NULL; |
| } |
| } |
| break; |
| case EXIF_SLONG: |
| { |
| if (m_Entries[i].tag_entry.count > 1 && |
| m_Entries[i].tag_entry.data._slongs != NULL) { |
| free(m_Entries[i].tag_entry.data._slongs); |
| m_Entries[i].tag_entry.data._slongs = NULL; |
| } |
| } |
| break; |
| case EXIF_SRATIONAL: |
| { |
| if (m_Entries[i].tag_entry.count > 1 && |
| m_Entries[i].tag_entry.data._srats != NULL) { |
| free(m_Entries[i].tag_entry.data._srats); |
| m_Entries[i].tag_entry.data._srats = NULL; |
| } |
| } |
| break; |
| default: |
| ALOGE("%s: Error, Unknown type",__func__); |
| break; |
| } |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : addEntry |
| * |
| * DESCRIPTION: function to add an entry to exif data |
| * |
| * PARAMETERS : |
| * @tagid : exif tag ID |
| * @type : data type |
| * @count : number of data in uint of its type |
| * @data : input data ptr |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCamera3Exif::addEntry(exif_tag_id_t tagid, |
| exif_tag_type_t type, |
| uint32_t count, |
| void *data) |
| { |
| int32_t rc = NO_ERROR; |
| if(m_nNumEntries >= MAX_EXIF_TABLE_ENTRIES) { |
| ALOGE("%s: Number of entries exceeded limit", __func__); |
| return NO_MEMORY; |
| } |
| |
| m_Entries[m_nNumEntries].tag_id = tagid; |
| m_Entries[m_nNumEntries].tag_entry.type = type; |
| m_Entries[m_nNumEntries].tag_entry.count = count; |
| m_Entries[m_nNumEntries].tag_entry.copy = 1; |
| switch (type) { |
| case EXIF_BYTE: |
| { |
| if (count > 1) { |
| uint8_t *values = (uint8_t *)malloc(count); |
| if (values == NULL) { |
| ALOGE("%s: No memory for byte array", __func__); |
| rc = NO_MEMORY; |
| } else { |
| memcpy(values, data, count); |
| m_Entries[m_nNumEntries].tag_entry.data._bytes = values; |
| } |
| } else { |
| m_Entries[m_nNumEntries].tag_entry.data._byte = |
| *(uint8_t *)data; |
| } |
| } |
| break; |
| case EXIF_ASCII: |
| { |
| char *str = NULL; |
| str = (char *)malloc(count + 1); |
| if (str == NULL) { |
| ALOGE("%s: No memory for ascii string", __func__); |
| rc = NO_MEMORY; |
| } else { |
| memset(str, 0, count + 1); |
| memcpy(str, data, count); |
| m_Entries[m_nNumEntries].tag_entry.data._ascii = str; |
| } |
| } |
| break; |
| case EXIF_SHORT: |
| { |
| if (count > 1) { |
| uint16_t *values = |
| (uint16_t *)malloc(count * sizeof(uint16_t)); |
| if (values == NULL) { |
| ALOGE("%s: No memory for short array", __func__); |
| rc = NO_MEMORY; |
| } else { |
| memcpy(values, data, count * sizeof(uint16_t)); |
| m_Entries[m_nNumEntries].tag_entry.data._shorts =values; |
| } |
| } else { |
| m_Entries[m_nNumEntries].tag_entry.data._short = |
| *(uint16_t *)data; |
| } |
| } |
| break; |
| case EXIF_LONG: |
| { |
| if (count > 1) { |
| uint32_t *values = |
| (uint32_t *)malloc(count * sizeof(uint32_t)); |
| if (values == NULL) { |
| ALOGE("%s: No memory for long array", __func__); |
| rc = NO_MEMORY; |
| } else { |
| memcpy(values, data, count * sizeof(uint32_t)); |
| m_Entries[m_nNumEntries].tag_entry.data._longs = values; |
| } |
| } else { |
| m_Entries[m_nNumEntries].tag_entry.data._long = |
| *(uint32_t *)data; |
| } |
| } |
| break; |
| case EXIF_RATIONAL: |
| { |
| if (count > 1) { |
| rat_t *values = (rat_t *)malloc(count * sizeof(rat_t)); |
| if (values == NULL) { |
| ALOGE("%s: No memory for rational array", __func__); |
| rc = NO_MEMORY; |
| } else { |
| memcpy(values, data, count * sizeof(rat_t)); |
| m_Entries[m_nNumEntries].tag_entry.data._rats = values; |
| } |
| } else { |
| m_Entries[m_nNumEntries].tag_entry.data._rat = |
| *(rat_t *)data; |
| } |
| } |
| break; |
| case EXIF_UNDEFINED: |
| { |
| uint8_t *values = (uint8_t *)malloc(count); |
| if (values == NULL) { |
| ALOGE("%s: No memory for undefined array", __func__); |
| rc = NO_MEMORY; |
| } else { |
| memcpy(values, data, count); |
| m_Entries[m_nNumEntries].tag_entry.data._undefined = values; |
| } |
| } |
| break; |
| case EXIF_SLONG: |
| { |
| if (count > 1) { |
| int32_t *values = |
| (int32_t *)malloc(count * sizeof(int32_t)); |
| if (values == NULL) { |
| ALOGE("%s: No memory for signed long array", __func__); |
| rc = NO_MEMORY; |
| } else { |
| memcpy(values, data, count * sizeof(int32_t)); |
| m_Entries[m_nNumEntries].tag_entry.data._slongs =values; |
| } |
| } else { |
| m_Entries[m_nNumEntries].tag_entry.data._slong = |
| *(int32_t *)data; |
| } |
| } |
| break; |
| case EXIF_SRATIONAL: |
| { |
| if (count > 1) { |
| srat_t *values = (srat_t *)malloc(count * sizeof(srat_t)); |
| if (values == NULL) { |
| ALOGE("%s: No memory for sign rational array",__func__); |
| rc = NO_MEMORY; |
| } else { |
| memcpy(values, data, count * sizeof(srat_t)); |
| m_Entries[m_nNumEntries].tag_entry.data._srats = values; |
| } |
| } else { |
| m_Entries[m_nNumEntries].tag_entry.data._srat = |
| *(srat_t *)data; |
| } |
| } |
| break; |
| default: |
| ALOGE("%s: Error, Unknown type",__func__); |
| break; |
| } |
| |
| // Increase number of entries |
| m_nNumEntries++; |
| return rc; |
| } |
| |
| }; // namespace qcamera |