4501 lines
171 KiB
C++
4501 lines
171 KiB
C++
|
/* Copyright (c) 2012-2018, The Linux Foundation. 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"
|
||
|
|
||
|
// To remove
|
||
|
#include <cutils/properties.h>
|
||
|
|
||
|
// System dependencies
|
||
|
#include <stdio.h>
|
||
|
|
||
|
// Camera dependencies
|
||
|
#include "QCamera3Channel.h"
|
||
|
#include "QCamera3HWI.h"
|
||
|
#include "QCamera3PostProc.h"
|
||
|
#include "QCamera3Stream.h"
|
||
|
#include "QCameraTrace.h"
|
||
|
#include "QCameraPprocManager.h"
|
||
|
#include "QCameraMem.h"
|
||
|
|
||
|
extern "C" {
|
||
|
#include "mm_camera_dbg.h"
|
||
|
}
|
||
|
|
||
|
#define ENABLE_MODEL_INFO_EXIF
|
||
|
|
||
|
namespace qcamera {
|
||
|
|
||
|
static const char ExifAsciiPrefix[] =
|
||
|
{ 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 }; // "ASCII\0\0\0"
|
||
|
|
||
|
__unused
|
||
|
static const char ExifUndefinedPrefix[] =
|
||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // "\0\0\0\0\0\0\0\0"
|
||
|
|
||
|
#define EXIF_ASCII_PREFIX_SIZE 8 //(sizeof(ExifAsciiPrefix))
|
||
|
#define FOCAL_LENGTH_DECIMAL_PRECISION 1000
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : QCamera3PostProcessor
|
||
|
*
|
||
|
* DESCRIPTION: constructor of QCamera3PostProcessor.
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @cam_ctrl : ptr to HWI object
|
||
|
*
|
||
|
* RETURN : None
|
||
|
*==========================================================================*/
|
||
|
QCamera3PostProcessor::QCamera3PostProcessor(QCamera3ProcessingChannel* ch_ctrl)
|
||
|
: m_parent(ch_ctrl),
|
||
|
mJpegCB(NULL),
|
||
|
mJpegUserData(NULL),
|
||
|
mJpegClientHandle(0),
|
||
|
mJpegSessionId(0),
|
||
|
m_bThumbnailNeeded(TRUE),
|
||
|
m_ppChannelCnt(1),
|
||
|
m_bMpoEnabled(FALSE),
|
||
|
m_inputPPQ(releasePPInputData, this),
|
||
|
m_inputFWKPPQ(NULL, this),
|
||
|
m_inputMultiReprocQ(NULL, this), // add release job data func here
|
||
|
m_ongoingPPQ(releaseOngoingPPData, this),
|
||
|
m_inputJpegQ(releaseJpegData, this),
|
||
|
m_ongoingJpegQ(releaseJpegData, this),
|
||
|
m_inputMetaQ(releaseMetadata, this),
|
||
|
m_jpegSettingsQ(NULL, this),
|
||
|
m_pHalPPManager(NULL),
|
||
|
mChannelStop(TRUE)
|
||
|
{
|
||
|
memset(&mJpegHandle, 0, sizeof(mJpegHandle));
|
||
|
memset(&mJpegMetadata, 0, sizeof(mJpegMetadata));
|
||
|
memset(m_pReprocChannel, 0, sizeof(m_pReprocChannel));
|
||
|
mReprocessNode.clear();
|
||
|
pthread_mutex_init(&mReprocJobLock, NULL);
|
||
|
pthread_mutex_init(&mHDRJobLock, NULL);
|
||
|
pthread_cond_init(&mProcChStopCond, NULL);
|
||
|
max_pic_size = {0,0};
|
||
|
mCancelpprocReqFrameList.clear();
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : ~QCamera3PostProcessor
|
||
|
*
|
||
|
* DESCRIPTION: deconstructor of QCamera3PostProcessor.
|
||
|
*
|
||
|
* PARAMETERS : None
|
||
|
*
|
||
|
* RETURN : None
|
||
|
*==========================================================================*/
|
||
|
QCamera3PostProcessor::~QCamera3PostProcessor()
|
||
|
{
|
||
|
for (int8_t i = 0; i < m_ppChannelCnt; i++) {
|
||
|
QCamera3Channel *pChannel = m_pReprocChannel[i];
|
||
|
if (pChannel != NULL ) {
|
||
|
pChannel->stop();
|
||
|
delete pChannel;
|
||
|
m_pReprocChannel[i] = NULL;
|
||
|
}
|
||
|
}
|
||
|
if (m_pHalPPManager != NULL) {
|
||
|
m_pHalPPManager->release();
|
||
|
m_pHalPPManager = NULL;
|
||
|
}
|
||
|
m_ppChannelCnt = 0;
|
||
|
|
||
|
pthread_mutex_destroy(&mReprocJobLock);
|
||
|
pthread_mutex_destroy(&mHDRJobLock);
|
||
|
pthread_cond_destroy(&mProcChStopCond);
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : init
|
||
|
*
|
||
|
* DESCRIPTION: initialization of postprocessor
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @memory : output buffer memory
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t QCamera3PostProcessor::init(QCamera3StreamMem *memory)
|
||
|
{
|
||
|
ATRACE_CAMSCOPE_CALL(CAMSCOPE_HAL3_PPROC_INIT);
|
||
|
mOutputMem = memory;
|
||
|
m_dataProcTh.launch(dataProcessRoutine, this);
|
||
|
QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
|
||
|
if (hal_obj->isDualCamera()) {
|
||
|
LOGH("Check and create HAL PP manager if not present");
|
||
|
createHalPPManager();
|
||
|
}
|
||
|
mFreeJpegSessions.clear();
|
||
|
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()
|
||
|
{
|
||
|
int rc = NO_ERROR;
|
||
|
m_dataProcTh.exit();
|
||
|
|
||
|
for (int8_t i = 0; i < m_ppChannelCnt; i++) {
|
||
|
QCamera3Channel *pChannel = m_pReprocChannel[i];
|
||
|
if (pChannel != NULL ) {
|
||
|
pChannel->stop();
|
||
|
delete pChannel;
|
||
|
m_pReprocChannel[i] = NULL;
|
||
|
}
|
||
|
}
|
||
|
if (m_pHalPPManager != NULL) {
|
||
|
LOGH("DeInit PP Manager");
|
||
|
m_pHalPPManager->deinit();
|
||
|
m_pHalPPManager = NULL;
|
||
|
}
|
||
|
m_ppChannelCnt = 0;
|
||
|
|
||
|
if(mJpegClientHandle > 0) {
|
||
|
rc = mJpegHandle.close(mJpegClientHandle);
|
||
|
LOGH("Jpeg closed, rc = %d, mJpegClientHandle = %x",
|
||
|
rc, mJpegClientHandle);
|
||
|
mJpegClientHandle = 0;
|
||
|
memset(&mJpegHandle, 0, sizeof(mJpegHandle));
|
||
|
}
|
||
|
|
||
|
mOutputMem = NULL;
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : initJpeg
|
||
|
*
|
||
|
* DESCRIPTION: initialization of jpeg through postprocessor
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @jpeg_cb : callback to handle jpeg event from mm-camera-interface
|
||
|
* @max_pic_dim : max picture dimensions
|
||
|
* @user_data : user data ptr for jpeg callback
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t QCamera3PostProcessor::initJpeg(jpeg_encode_callback_t jpeg_cb,
|
||
|
mpo_encode_callback_t mpo_cb,
|
||
|
cam_dimension_t* max_pic_dim,
|
||
|
void *user_data)
|
||
|
{
|
||
|
ATRACE_CAMSCOPE_CALL(CAMSCOPE_HAL3_PPROC_INIT_JPEG);
|
||
|
mJpegCB = jpeg_cb;
|
||
|
mMpoCB = mpo_cb;
|
||
|
mJpegUserData = user_data;
|
||
|
|
||
|
mMpoInputData.clear();
|
||
|
|
||
|
if ((0 > max_pic_dim->width) || (0 > max_pic_dim->height)) {
|
||
|
LOGE("Negative dimension %dx%d",
|
||
|
max_pic_dim->width, max_pic_dim->height);
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
// set max pic size
|
||
|
memset(&max_pic_size, 0, sizeof(mm_dimension));
|
||
|
max_pic_size.w = max_pic_dim->width;
|
||
|
max_pic_size.h = max_pic_dim->height;
|
||
|
|
||
|
// Pass OTP calibration data to JPEG
|
||
|
QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
|
||
|
mJpegMetadata.default_sensor_flip = FLIP_NONE;
|
||
|
mJpegMetadata.sensor_mount_angle = hal_obj->getSensorMountAngle();
|
||
|
memcpy(&mJpegMetadata.otp_calibration_data,
|
||
|
hal_obj->getRelatedCalibrationData(),
|
||
|
sizeof(cam_related_system_calibration_data_t));
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_INIT_JPEG, FALSE, TRUE);
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : start
|
||
|
*
|
||
|
* DESCRIPTION: start postprocessor. Data process thread and data notify thread
|
||
|
* will be launched.
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @config : reprocess configuration
|
||
|
*
|
||
|
* 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(const reprocess_config_t &config)
|
||
|
{
|
||
|
int32_t rc = NO_ERROR;
|
||
|
pthread_mutex_lock(&mHDRJobLock);
|
||
|
QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
|
||
|
if(mChannelStop == false)
|
||
|
pthread_cond_wait(&mProcChStopCond, &mHDRJobLock);
|
||
|
pthread_mutex_unlock(&mHDRJobLock);
|
||
|
if (config.reprocess_type != REPROCESS_TYPE_NONE) {
|
||
|
for (int8_t i = 0; i < m_ppChannelCnt; i++) {
|
||
|
QCamera3Channel *pChannel = m_pReprocChannel[i];
|
||
|
if (pChannel != NULL ) {
|
||
|
pChannel->stop();
|
||
|
delete pChannel;
|
||
|
m_pReprocChannel[i] = NULL;
|
||
|
}
|
||
|
}
|
||
|
m_ppChannelCnt = 0;
|
||
|
|
||
|
//if YUV support quadra remosaic and 2 yuv configured/requested one with quadra size and
|
||
|
//other with offline reprocessing. then need to differentiate for how many reprocess
|
||
|
//channel required for which YUV channel.
|
||
|
if((config.reprocess_type == REPROCESS_TYPE_YUV)
|
||
|
&& hal_obj->m_bQuadraCfaRequest
|
||
|
&& !m_parent->m_bQuadraChannel)
|
||
|
{
|
||
|
m_ppChannelCnt = 1; //setting 1 for non-quadra YUV at remosaic requested PCR from framework.
|
||
|
} else {
|
||
|
m_ppChannelCnt = hal_obj->getReprocChannelCnt();
|
||
|
}
|
||
|
|
||
|
LOGH("m_ppChannelCnt:%d", m_ppChannelCnt);
|
||
|
|
||
|
reprocess_config_t local_cfg = config;
|
||
|
for (int8_t i = 0; i < m_ppChannelCnt; i++) {
|
||
|
LOGD("src channel:%p, input channel:%p", local_cfg.src_channel, m_parent);
|
||
|
m_pReprocChannel[i] = hal_obj->addOfflineReprocChannel(local_cfg, m_parent, i);
|
||
|
if (m_pReprocChannel[i] == NULL) {
|
||
|
LOGE("cannot add reprocess channel, idx:%d", i);
|
||
|
return UNKNOWN_ERROR;
|
||
|
}
|
||
|
local_cfg.src_channel = (QCamera3Channel *)m_pReprocChannel[i];
|
||
|
}
|
||
|
|
||
|
/*start the reprocess channel only if buffers are already allocated, thus
|
||
|
only start it in an intermediate reprocess type, defer it for others*/
|
||
|
if ((config.reprocess_type == REPROCESS_TYPE_JPEG)
|
||
|
|| ((config.reprocess_type == REPROCESS_TYPE_YUV) && (m_parent->m_bQuadraChannel))) {
|
||
|
for (int8_t i = 0; i < m_ppChannelCnt; i++) {
|
||
|
rc = m_pReprocChannel[i]->start();
|
||
|
if (rc != 0) {
|
||
|
LOGE("cannot start reprocess channel, idx:%d", i);
|
||
|
delete m_pReprocChannel[i];
|
||
|
m_pReprocChannel[i] = NULL;
|
||
|
return rc;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (hal_obj->isDualCamera() &&
|
||
|
(hal_obj->getHalPPType() != CAM_HAL_PP_TYPE_NONE
|
||
|
&& hal_obj->getHalPPType() != CAM_HAL_PP_TYPE_SAT)) {
|
||
|
// HALPP type might have changed, ensure we have right pp block
|
||
|
rc = initHalPPManager();
|
||
|
if (rc != NO_ERROR) {
|
||
|
LOGE("Initializing PP manager failed");
|
||
|
return rc;
|
||
|
}
|
||
|
if (m_pHalPPManager != NULL) {
|
||
|
LOGH("HALPP is need, call QCameraHALPPManager::start() here");
|
||
|
rc = m_pHalPPManager->start();
|
||
|
if (rc != NO_ERROR) {
|
||
|
LOGE("start PP manager failed");
|
||
|
return rc;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, TRUE, FALSE);
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : flush
|
||
|
*
|
||
|
* DESCRIPTION: stop ongoing postprocess and jpeg jobs
|
||
|
*
|
||
|
* PARAMETERS : None
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*
|
||
|
*==========================================================================*/
|
||
|
int32_t QCamera3PostProcessor::flush()
|
||
|
{
|
||
|
int32_t rc = NO_ERROR;
|
||
|
qcamera_hal3_jpeg_data_t *jpeg_job =
|
||
|
(qcamera_hal3_jpeg_data_t *)m_ongoingJpegQ.dequeue();
|
||
|
while (jpeg_job != NULL) {
|
||
|
rc = mJpegHandle.abort_job(jpeg_job->jobId);
|
||
|
releaseJpegJobData(jpeg_job);
|
||
|
free(jpeg_job);
|
||
|
|
||
|
jpeg_job = (qcamera_hal3_jpeg_data_t *)m_ongoingJpegQ.dequeue();
|
||
|
}
|
||
|
rc = releaseOfflineBuffers(true);
|
||
|
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(bool isHDR)
|
||
|
{
|
||
|
if ((m_pHalPPManager != NULL)) {
|
||
|
m_pHalPPManager->stop();
|
||
|
}
|
||
|
|
||
|
if(isHDR == true)
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, FALSE, TRUE);
|
||
|
else
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE);
|
||
|
|
||
|
for (int8_t i = 0; i < m_ppChannelCnt; i++) {
|
||
|
QCamera3Channel *pChannel = m_pReprocChannel[i];
|
||
|
if (pChannel != NULL ) {
|
||
|
pChannel->stop();
|
||
|
delete pChannel;
|
||
|
m_pReprocChannel[i] = NULL;
|
||
|
}
|
||
|
}
|
||
|
m_ppChannelCnt = 0;
|
||
|
mCancelpprocReqFrameList.clear();
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getFWKJpegEncodeConfig
|
||
|
*
|
||
|
* DESCRIPTION: function to prepare encoding job information
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @encode_parm : param to be filled with encoding configuration
|
||
|
* @frame : framework input buffer
|
||
|
* @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::getFWKJpegEncodeConfig(
|
||
|
mm_jpeg_encode_params_t& encode_parm,
|
||
|
qcamera_fwk_input_pp_data_t *frame,
|
||
|
jpeg_settings_t *jpeg_settings)
|
||
|
{
|
||
|
LOGD("E");
|
||
|
int32_t ret = NO_ERROR;
|
||
|
|
||
|
if ((NULL == frame) || (NULL == jpeg_settings)) {
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
ssize_t bufSize = mOutputMem->getSize(jpeg_settings->out_buf_index);
|
||
|
if (BAD_INDEX == bufSize) {
|
||
|
LOGE("cannot retrieve buffer size for buffer %u",
|
||
|
jpeg_settings->out_buf_index);
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
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 = frame->reproc_config.stream_format;
|
||
|
encode_parm.color_format = getColorfmtFromImgFmt(img_fmt);
|
||
|
|
||
|
// get jpeg quality
|
||
|
encode_parm.quality = jpeg_settings->jpeg_quality;
|
||
|
if (encode_parm.quality <= 0) {
|
||
|
encode_parm.quality = 85;
|
||
|
}
|
||
|
|
||
|
// get jpeg thumbnail quality
|
||
|
encode_parm.thumb_quality = jpeg_settings->jpeg_thumb_quality;
|
||
|
|
||
|
cam_frame_len_offset_t main_offset =
|
||
|
frame->reproc_config.input_stream_plane_info.plane_info;
|
||
|
|
||
|
encode_parm.num_src_bufs = 1;
|
||
|
encode_parm.src_main_buf[0].index = 0;
|
||
|
encode_parm.src_main_buf[0].buf_size = frame->input_buffer.frame_len;
|
||
|
encode_parm.src_main_buf[0].buf_vaddr = (uint8_t *) frame->input_buffer.buffer;
|
||
|
encode_parm.src_main_buf[0].fd = frame->input_buffer.fd;
|
||
|
encode_parm.src_main_buf[0].format = MM_JPEG_FMT_YUV;
|
||
|
encode_parm.src_main_buf[0].offset = main_offset;
|
||
|
|
||
|
//Pass input thumbnail buffer info to encoder.
|
||
|
//Note: Use main buffer to encode thumbnail
|
||
|
if (m_bThumbnailNeeded == TRUE) {
|
||
|
encode_parm.num_tmb_bufs = 1;
|
||
|
encode_parm.src_thumb_buf[0] = encode_parm.src_main_buf[0];
|
||
|
}
|
||
|
|
||
|
//Pass output jpeg buffer info to encoder.
|
||
|
//mOutputMem is allocated by framework.
|
||
|
encode_parm.num_dst_bufs = 1;
|
||
|
encode_parm.dest_buf[0].index = 0;
|
||
|
encode_parm.dest_buf[0].buf_size = (size_t)bufSize;
|
||
|
encode_parm.dest_buf[0].buf_vaddr = (uint8_t *)mOutputMem->getPtr(
|
||
|
jpeg_settings->out_buf_index);
|
||
|
encode_parm.dest_buf[0].fd = mOutputMem->getFd(
|
||
|
jpeg_settings->out_buf_index);
|
||
|
encode_parm.dest_buf[0].format = MM_JPEG_FMT_YUV;
|
||
|
encode_parm.dest_buf[0].offset = main_offset;
|
||
|
|
||
|
LOGD("X");
|
||
|
return NO_ERROR;
|
||
|
|
||
|
LOGD("X with error %d", ret);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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,
|
||
|
mm_camera_buf_def_t *input_buf)
|
||
|
{
|
||
|
LOGD("E");
|
||
|
int32_t ret = NO_ERROR;
|
||
|
ssize_t bufSize = 0;
|
||
|
QCamera3StreamMem *outputMem = mOutputMem;
|
||
|
|
||
|
if(jpeg_settings->encode_type == MM_JPEG_TYPE_JPEG)
|
||
|
{
|
||
|
encode_parm.jpeg_cb = mJpegCB;
|
||
|
encode_parm.userdata = mJpegUserData;
|
||
|
} else {
|
||
|
// MPO usecase.
|
||
|
encode_parm.jpeg_cb = processJpegData;
|
||
|
encode_parm.userdata = this;
|
||
|
outputMem = &m_parent->getJpegMemory();
|
||
|
}
|
||
|
|
||
|
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
|
||
|
if(jpeg_settings->is_format_valid)
|
||
|
{
|
||
|
img_fmt = jpeg_settings->format;
|
||
|
} else {
|
||
|
if(main_stream->getFormat(img_fmt) < 0)
|
||
|
{
|
||
|
LOGE("Error: failed to get image format");
|
||
|
}
|
||
|
}
|
||
|
encode_parm.color_format = getColorfmtFromImgFmt(img_fmt);
|
||
|
|
||
|
// get jpeg quality
|
||
|
encode_parm.quality = jpeg_settings->jpeg_quality;
|
||
|
if (encode_parm.quality <= 0) {
|
||
|
encode_parm.quality = 85;
|
||
|
}
|
||
|
|
||
|
// 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));
|
||
|
if(jpeg_settings->is_offset_valid)
|
||
|
{
|
||
|
main_offset = jpeg_settings->offset;
|
||
|
} else {
|
||
|
main_stream->getFrameOffset(main_offset);
|
||
|
}
|
||
|
|
||
|
// src buf config
|
||
|
//Pass input main image buffer info to encoder.
|
||
|
QCamera3StreamMem *pStreamMem = main_stream->getStreamBufs();
|
||
|
if (pStreamMem == NULL) {
|
||
|
LOGE("cannot get stream bufs from main stream");
|
||
|
ret = BAD_VALUE;
|
||
|
goto on_error;
|
||
|
}
|
||
|
if(input_buf == NULL)
|
||
|
{
|
||
|
encode_parm.num_src_bufs = MIN(pStreamMem->getCnt(), MM_JPEG_MAX_BUF);
|
||
|
for (uint32_t i = 0; i < encode_parm.num_src_bufs; i++) {
|
||
|
if (pStreamMem != NULL) {
|
||
|
encode_parm.src_main_buf[i].index = i;
|
||
|
bufSize = pStreamMem->getSize(i);
|
||
|
if (BAD_INDEX == bufSize) {
|
||
|
LOGE("cannot retrieve buffer size for buffer %u", i);
|
||
|
ret = BAD_VALUE;
|
||
|
goto on_error;
|
||
|
}
|
||
|
encode_parm.src_main_buf[i].buf_size = (size_t)bufSize;
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
encode_parm.num_src_bufs = 1;
|
||
|
encode_parm.src_main_buf[0].index = 0;
|
||
|
encode_parm.src_main_buf[0].buf_size = input_buf->frame_len;
|
||
|
encode_parm.src_main_buf[0].buf_vaddr = (uint8_t *)input_buf->buffer;
|
||
|
encode_parm.src_main_buf[0].fd = input_buf->fd;
|
||
|
encode_parm.src_main_buf[0].format = MM_JPEG_FMT_YUV;
|
||
|
encode_parm.src_main_buf[0].offset = main_offset;
|
||
|
}
|
||
|
|
||
|
//Pass input thumbnail buffer info to encoder.
|
||
|
//Note: Use main buffer to encode thumbnail
|
||
|
if (m_bThumbnailNeeded == TRUE) {
|
||
|
pStreamMem = main_stream->getStreamBufs();
|
||
|
if (pStreamMem == NULL) {
|
||
|
LOGE("cannot get stream bufs from thumb stream");
|
||
|
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 = MIN(pStreamMem->getCnt(), MM_JPEG_MAX_BUF);
|
||
|
for (uint32_t i = 0; i < encode_parm.num_tmb_bufs; i++) {
|
||
|
if (pStreamMem != NULL) {
|
||
|
encode_parm.src_thumb_buf[i].index = i;
|
||
|
bufSize = pStreamMem->getSize(i);
|
||
|
if (BAD_INDEX == bufSize) {
|
||
|
LOGE("cannot retrieve buffer size for buffer %u", i);
|
||
|
ret = BAD_VALUE;
|
||
|
goto on_error;
|
||
|
}
|
||
|
encode_parm.src_thumb_buf[i].buf_size = (uint32_t)bufSize;
|
||
|
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.
|
||
|
bufSize = outputMem->getSize(jpeg_settings->out_buf_index);
|
||
|
if (BAD_INDEX == bufSize) {
|
||
|
LOGE("cannot retrieve buffer size for buffer %u",
|
||
|
jpeg_settings->out_buf_index);
|
||
|
ret = BAD_VALUE;
|
||
|
goto on_error;
|
||
|
}
|
||
|
|
||
|
encode_parm.num_dst_bufs = 1;
|
||
|
encode_parm.dest_buf[0].index = 0;
|
||
|
encode_parm.dest_buf[0].buf_size = (size_t)bufSize;
|
||
|
encode_parm.dest_buf[0].buf_vaddr = (uint8_t *)outputMem->getPtr(
|
||
|
jpeg_settings->out_buf_index);
|
||
|
encode_parm.dest_buf[0].fd = outputMem->getFd(
|
||
|
jpeg_settings->out_buf_index);
|
||
|
encode_parm.dest_buf[0].format = MM_JPEG_FMT_YUV;
|
||
|
encode_parm.dest_buf[0].offset = main_offset;
|
||
|
|
||
|
LOGD("X");
|
||
|
return NO_ERROR;
|
||
|
|
||
|
on_error:
|
||
|
LOGD("X with error %d", ret);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int32_t QCamera3PostProcessor::processData(mm_camera_super_buf_t *input) {
|
||
|
return processData(input, NULL, 0);
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : processData
|
||
|
*
|
||
|
* DESCRIPTION: enqueue data into dataProc thread
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @frame : process input frame
|
||
|
* @output : process output frame
|
||
|
*
|
||
|
* 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 *input,
|
||
|
buffer_handle_t *output, uint32_t frameNumber)
|
||
|
{
|
||
|
LOGD("E");
|
||
|
pthread_mutex_lock(&mReprocJobLock);
|
||
|
|
||
|
// enqueue to post proc input queue
|
||
|
qcamera_hal3_pp_buffer_t *pp_buffer = (qcamera_hal3_pp_buffer_t *)malloc(
|
||
|
sizeof(qcamera_hal3_pp_buffer_t));
|
||
|
if (NULL == pp_buffer) {
|
||
|
LOGE("out of memory");
|
||
|
return NO_MEMORY;
|
||
|
}
|
||
|
memset(pp_buffer, 0, sizeof(*pp_buffer));
|
||
|
pp_buffer->input = input;
|
||
|
pp_buffer->output = output;
|
||
|
pp_buffer->frameNumber = frameNumber;
|
||
|
if (!(m_inputMetaQ.isEmpty())) {
|
||
|
qcamera_hal3_meta_pp_buffer_t *meta_job = isMetaMatched(frameNumber);
|
||
|
if(meta_job != NULL) {
|
||
|
ReprocessBuffer reproc;
|
||
|
reproc.metaBuffer = meta_job;
|
||
|
reproc.reprocBuf = pp_buffer;
|
||
|
mReprocessNode.push_back(reproc);
|
||
|
LOGD("meta queue is not empty, do next job");
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
|
||
|
} else {
|
||
|
m_inputPPQ.enqueue((void *)pp_buffer);
|
||
|
}
|
||
|
} else {
|
||
|
LOGD("metadata queue is empty");
|
||
|
m_inputPPQ.enqueue((void *)pp_buffer);
|
||
|
}
|
||
|
pthread_mutex_unlock(&mReprocJobLock);
|
||
|
|
||
|
if(mCancelpprocReqFrameList.size())
|
||
|
{
|
||
|
List<uint32_t>::iterator cancel_frame = mCancelpprocReqFrameList.begin();
|
||
|
while((cancel_frame != mCancelpprocReqFrameList.end()) && ((*cancel_frame) != frameNumber))
|
||
|
{
|
||
|
cancel_frame = mCancelpprocReqFrameList.erase(cancel_frame);
|
||
|
}
|
||
|
|
||
|
if(cancel_frame != mCancelpprocReqFrameList.end() && ((*cancel_frame) == frameNumber))
|
||
|
{
|
||
|
cancelFramePProc(frameNumber);
|
||
|
mCancelpprocReqFrameList.erase(cancel_frame);
|
||
|
}
|
||
|
}
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : isMetaMatched
|
||
|
*
|
||
|
* DESCRIPTION: corresponding meta detection
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @frame : frame number
|
||
|
*
|
||
|
* RETURN :
|
||
|
* TRUE if Frame is present
|
||
|
* FALSE if Frame is not released.
|
||
|
*
|
||
|
*==========================================================================*/
|
||
|
qcamera_hal3_meta_pp_buffer_t* QCamera3PostProcessor::isMetaMatched(uint32_t resultFrameNumber)
|
||
|
{
|
||
|
qcamera_hal3_meta_pp_buffer_t *meta_job =
|
||
|
(qcamera_hal3_meta_pp_buffer_t *)
|
||
|
m_inputMetaQ.dequeue(matchMetaFrameNum, (void*)&resultFrameNumber);
|
||
|
if(meta_job != NULL) {
|
||
|
return meta_job;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : releaseReprocMetaBuffer
|
||
|
*
|
||
|
* DESCRIPTION: Release reprocessed Meta.
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @frame : meta frame number
|
||
|
*
|
||
|
* RETURN :
|
||
|
* TRUE if Meta is released.
|
||
|
* FALSE if Meta is not released.
|
||
|
*
|
||
|
*==========================================================================*/
|
||
|
bool QCamera3PostProcessor::releaseReprocMetaBuffer(uint32_t resultFrameNumber)
|
||
|
{
|
||
|
pthread_mutex_lock(&mReprocJobLock);
|
||
|
if (!(m_inputMetaQ.isEmpty())) {
|
||
|
mm_camera_super_buf_t *meta_buffer = NULL;
|
||
|
qcamera_hal3_meta_pp_buffer_t *meta_job =
|
||
|
(qcamera_hal3_meta_pp_buffer_t *)
|
||
|
m_inputMetaQ.dequeue(matchMetaFrameNum, (void*)&resultFrameNumber);
|
||
|
if(meta_job != NULL) {
|
||
|
meta_buffer = meta_job->metabuf;
|
||
|
m_parent->metadataBufDone(meta_buffer);
|
||
|
free(meta_job);
|
||
|
pthread_mutex_unlock(&mReprocJobLock);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
pthread_mutex_unlock(&mReprocJobLock);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool QCamera3PostProcessor::matchMetaFrameNum(void *data, void *, void *match_data)
|
||
|
{
|
||
|
qcamera_hal3_meta_pp_buffer_t *job = (qcamera_hal3_meta_pp_buffer_t *) data;
|
||
|
uint32_t frame_num = *((uint32_t *) match_data);
|
||
|
LOGD(" Matching MetaFrameNum :%d and %d", frame_num, job->metaFrameNumber);
|
||
|
return job->metaFrameNumber == frame_num;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool QCamera3PostProcessor::matchReprocessFrameNum(void *data, void *, void *match_data)
|
||
|
{
|
||
|
qcamera_hal3_pp_buffer_t *job = (qcamera_hal3_pp_buffer_t *) data;
|
||
|
uint32_t frame_num = *((uint32_t *) match_data);
|
||
|
LOGD(" Matching FrameNum :%d and %d",frame_num,job->frameNumber);
|
||
|
return job->frameNumber == frame_num;
|
||
|
}
|
||
|
|
||
|
bool QCamera3PostProcessor::matchJpegSetting(void *data, void *, void *match_data)
|
||
|
{
|
||
|
jpeg_settings_t* jpeg_setting = (jpeg_settings_t *) data;
|
||
|
uint32_t frame_num = *((uint32_t *) match_data);
|
||
|
LOGD(" Matching FrameNum :%d and %d",frame_num,jpeg_setting->frame_number);
|
||
|
return jpeg_setting->frame_number == frame_num;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : needsReprocess
|
||
|
*
|
||
|
* DESCRIPTION: Determine if reprocess is needed.
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @frame : process frame
|
||
|
*
|
||
|
* RETURN :
|
||
|
* TRUE if frame needs to be reprocessed
|
||
|
* FALSE is frame does not need to be reprocessed
|
||
|
*
|
||
|
*==========================================================================*/
|
||
|
bool QCamera3PostProcessor::needsReprocess(qcamera_fwk_input_pp_data_t *frame)
|
||
|
{
|
||
|
metadata_buffer_t* meta = (metadata_buffer_t *) frame->metadata_buffer.buffer;
|
||
|
bool edgeModeOn = FALSE;
|
||
|
bool noiseRedModeOn = FALSE;
|
||
|
bool reproNotDone = TRUE;
|
||
|
|
||
|
if (frame->reproc_config.reprocess_type == REPROCESS_TYPE_NONE) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// edge detection
|
||
|
IF_META_AVAILABLE(cam_edge_application_t, edgeMode,
|
||
|
CAM_INTF_META_EDGE_MODE, meta) {
|
||
|
edgeModeOn = (CAM_EDGE_MODE_OFF != edgeMode->edge_mode);
|
||
|
}
|
||
|
|
||
|
// noise reduction
|
||
|
IF_META_AVAILABLE(uint32_t, noiseRedMode,
|
||
|
CAM_INTF_META_NOISE_REDUCTION_MODE, meta) {
|
||
|
noiseRedModeOn = (CAM_NOISE_REDUCTION_MODE_OFF != *noiseRedMode);
|
||
|
}
|
||
|
|
||
|
IF_META_AVAILABLE(uint8_t, reprocess_flags,
|
||
|
CAM_INTF_META_REPROCESS_FLAGS, meta) {
|
||
|
reproNotDone = FALSE;
|
||
|
}
|
||
|
|
||
|
return (edgeModeOn || noiseRedModeOn || reproNotDone);
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : processData
|
||
|
*
|
||
|
* DESCRIPTION: enqueue data into dataProc thread
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @frame : process frame
|
||
|
*
|
||
|
* 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(qcamera_fwk_input_pp_data_t *frame)
|
||
|
{
|
||
|
if (needsReprocess(frame)) {
|
||
|
ATRACE_INT("Camera:Reprocess", 1);
|
||
|
LOGH("scheduling framework reprocess");
|
||
|
pthread_mutex_lock(&mReprocJobLock);
|
||
|
// enqueu to post proc input queue
|
||
|
m_inputFWKPPQ.enqueue((void *)frame);
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
|
||
|
pthread_mutex_unlock(&mReprocJobLock);
|
||
|
} else {
|
||
|
jpeg_settings_t *jpeg_settings = (jpeg_settings_t *)m_jpegSettingsQ.dequeue();
|
||
|
|
||
|
if (jpeg_settings == NULL) {
|
||
|
LOGE("Cannot find jpeg settings");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
LOGH("no need offline reprocess, sending to jpeg encoding");
|
||
|
qcamera_hal3_jpeg_data_t *jpeg_job =
|
||
|
(qcamera_hal3_jpeg_data_t *)malloc(sizeof(qcamera_hal3_jpeg_data_t));
|
||
|
if (jpeg_job == NULL) {
|
||
|
LOGE("No memory for jpeg job");
|
||
|
return NO_MEMORY;
|
||
|
}
|
||
|
|
||
|
memset(jpeg_job, 0, sizeof(qcamera_hal3_jpeg_data_t));
|
||
|
jpeg_job->fwk_frame = frame;
|
||
|
jpeg_job->jpeg_settings = jpeg_settings;
|
||
|
jpeg_job->metadata =
|
||
|
(metadata_buffer_t *) frame->metadata_buffer.buffer;
|
||
|
|
||
|
// 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 : cancelFramePProc
|
||
|
*
|
||
|
* DESCRIPTION: cancel FramePost Processing request.
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @frame : frame number for which postproc request need to be cancel.
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*
|
||
|
*==========================================================================*/
|
||
|
int32_t QCamera3PostProcessor::cancelFramePProc(uint32_t framenum)
|
||
|
{
|
||
|
int rc = NO_ERROR;
|
||
|
pthread_mutex_lock(&mReprocJobLock);
|
||
|
if(!m_inputPPQ.isEmpty()){
|
||
|
LOGH("pp request cancel for frame : %d", framenum);
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_CANCEL_PP_FRAME, FALSE, FALSE);
|
||
|
pthread_mutex_unlock(&mReprocJobLock);
|
||
|
} else {
|
||
|
LOGH("PP Frame queue is empty. cache cancel frame request %d", framenum);
|
||
|
mCancelpprocReqFrameList.push_back(framenum);
|
||
|
pthread_mutex_unlock(&mReprocJobLock);
|
||
|
}
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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(mm_camera_super_buf_t *reproc_meta,
|
||
|
uint32_t framenum, bool dropFrame)
|
||
|
{
|
||
|
LOGD("E");
|
||
|
pthread_mutex_lock(&mReprocJobLock);
|
||
|
|
||
|
qcamera_hal3_meta_pp_buffer_t *ppMetaBuf =
|
||
|
(qcamera_hal3_meta_pp_buffer_t *)malloc(sizeof(qcamera_hal3_meta_pp_buffer_t));
|
||
|
|
||
|
// enqueue to metadata input queue
|
||
|
if (ppMetaBuf) {
|
||
|
ppMetaBuf->metabuf = reproc_meta;
|
||
|
ppMetaBuf->metaFrameNumber = framenum;
|
||
|
ppMetaBuf->dropFrame = dropFrame;
|
||
|
}
|
||
|
/* Need to send notifyError before meta for Error Buffer */
|
||
|
if (!(m_inputPPQ.isEmpty())) {
|
||
|
qcamera_hal3_pp_buffer_t *reproc_job = isFrameMatched(framenum);
|
||
|
if(reproc_job != NULL) {
|
||
|
ReprocessBuffer reproc;
|
||
|
reproc.metaBuffer = ppMetaBuf;
|
||
|
reproc.reprocBuf = reproc_job;
|
||
|
mReprocessNode.push_back(reproc);
|
||
|
LOGD("pp queue is not empty, do next job");
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
|
||
|
} else {
|
||
|
m_inputMetaQ.enqueue((void *)ppMetaBuf);
|
||
|
}
|
||
|
} else {
|
||
|
m_inputMetaQ.enqueue((void *)ppMetaBuf);
|
||
|
LOGD("pp queue is empty, not calling do next job");
|
||
|
}
|
||
|
pthread_mutex_unlock(&mReprocJobLock);
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : isFrameMatched
|
||
|
*
|
||
|
* DESCRIPTION: corresponding meta detection
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @frame : frame number
|
||
|
*
|
||
|
* RETURN :
|
||
|
* TRUE if Frame is present
|
||
|
* FALSE if Frame is not released.
|
||
|
*
|
||
|
*==========================================================================*/
|
||
|
qcamera_hal3_pp_buffer_t* QCamera3PostProcessor::isFrameMatched(uint32_t resultFrameNumber)
|
||
|
{
|
||
|
qcamera_hal3_pp_buffer_t *reprocess_job =
|
||
|
(qcamera_hal3_pp_buffer_t *)
|
||
|
m_inputPPQ.dequeue(matchReprocessFrameNum, (void*)&resultFrameNumber);
|
||
|
if(reprocess_job != NULL)
|
||
|
return reprocess_job;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void QCamera3PostProcessor::eraseJpegSetting(uint32_t resultFrameNumber)
|
||
|
{
|
||
|
jpeg_settings_t* jpeg_setting =
|
||
|
(jpeg_settings_t *) m_jpegSettingsQ.dequeue(matchJpegSetting,(void*)&resultFrameNumber);
|
||
|
if(jpeg_setting != NULL) {
|
||
|
LOGH("Erasing Jpeg settings for frame number %d", resultFrameNumber);
|
||
|
free(jpeg_setting);
|
||
|
jpeg_setting = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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) {
|
||
|
LOGE("invalid jpeg settings pointer");
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
m_jpegSettingsQ.init();
|
||
|
int32_t rc = m_jpegSettingsQ.enqueue((void *)jpeg_settings);
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
List<qcamera_hal3_mpo_data_t> QCamera3PostProcessor::mMpoInputData;
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : processJpegData
|
||
|
*
|
||
|
* DESCRIPTION: handled Jpeg callback from encoder (BOKEH snapshot case).
|
||
|
* After receiving BOKEH, MAIN, DEPTH images composeMpo.
|
||
|
* handles releasing of snapshot buffer, reprocess frame.
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @status : Jpeg error or success status.
|
||
|
* @client_hdl : __unused.
|
||
|
* @jobId : Jpeg job id.
|
||
|
* @p_output : Jpeg output image buffer.
|
||
|
* @userdata : user handle for this callback.
|
||
|
*
|
||
|
* RETURN : none
|
||
|
*
|
||
|
*==========================================================================*/
|
||
|
void QCamera3PostProcessor::processJpegData(jpeg_job_status_t status,
|
||
|
uint32_t /*client_hdl*/,
|
||
|
uint32_t jobId,
|
||
|
mm_jpeg_output_t *p_output,
|
||
|
void *userdata)
|
||
|
{
|
||
|
QCamera3PostProcessor *obj = (QCamera3PostProcessor *)userdata;
|
||
|
if(obj)
|
||
|
{
|
||
|
qcamera_hal3_jpeg_data_t *job = obj->findJpegJobByJobId(jobId);
|
||
|
if((job == NULL) || (status == JPEG_JOB_STATUS_ERROR))
|
||
|
{
|
||
|
//Send Error buffer with status to MpoEvtHandle.
|
||
|
LOGE("ERROR: JPEG Encoding failed");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
qcamera_hal3_mpo_data_t mpo_input;
|
||
|
|
||
|
mpo_input.jpeg_job = job;
|
||
|
mpo_input.jpeg_image = *p_output;
|
||
|
mpo_input.user_data = obj->mJpegUserData; //setting pic channel as userdata
|
||
|
|
||
|
mMpoInputData.push_back(mpo_input);
|
||
|
|
||
|
if(mMpoInputData.size() < MM_JPEG_MAX_MPO_IMAGES)
|
||
|
{
|
||
|
LOGH("need %d more jpeg images to compose mpo",
|
||
|
MM_JPEG_MAX_MPO_IMAGES - mMpoInputData.size());
|
||
|
obj->doNextJob();
|
||
|
return;
|
||
|
} else{
|
||
|
LOGI("Received %d images to compose MPO", mMpoInputData.size());
|
||
|
}
|
||
|
|
||
|
//getting the mpo output buffer from the main pic channel.
|
||
|
QCamera3PicChannel *pic_channel = NULL;
|
||
|
for(auto it = mMpoInputData.begin(); it != mMpoInputData.end(); it++)
|
||
|
{
|
||
|
qcamera_hal3_jpeg_data_t *job = it->jpeg_job;
|
||
|
if(job->jpeg_settings->image_type == CAM_HAL3_JPEG_TYPE_MAIN)
|
||
|
{
|
||
|
pic_channel = (QCamera3PicChannel *)it->user_data;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(pic_channel == NULL)
|
||
|
{
|
||
|
LOGE("unexpected case: no pic channel to get mpo output buffer");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
mm_jpeg_output_t mpo_output;
|
||
|
memset (&mpo_output, 0, sizeof(mm_jpeg_output_t));
|
||
|
pic_channel->getMpoOutputBuffer(&mpo_output);
|
||
|
|
||
|
//main image should be bokeh output.
|
||
|
//first aux will be main pic channel output.
|
||
|
//second aux will be aux pic channel output.
|
||
|
qcamera_hal3_mpo_compose_info_t mpo_info;
|
||
|
memset (&mpo_info, 0, sizeof(qcamera_hal3_mpo_compose_info_t));
|
||
|
for (auto it = mMpoInputData.begin(); it != mMpoInputData.end(); it++)
|
||
|
{
|
||
|
qcamera_hal3_jpeg_data_t *job = it->jpeg_job;
|
||
|
if(job->jpeg_settings->image_type == CAM_HAL3_JPEG_TYPE_BOKEH)
|
||
|
{
|
||
|
LOGH("Received bokeh processed image");
|
||
|
mpo_info.main_image = (it->jpeg_image);
|
||
|
}
|
||
|
else if(job->jpeg_settings->image_type == CAM_HAL3_JPEG_TYPE_MAIN) {
|
||
|
LOGH("Received main image");
|
||
|
mpo_info.aux_images[0] = (it->jpeg_image);
|
||
|
}
|
||
|
else if (job->jpeg_settings->image_type == CAM_HAL3_JPEG_TYPE_DEPTH) {
|
||
|
LOGH("Received aux image");
|
||
|
mpo_info.aux_images[1] = (it->jpeg_image);
|
||
|
}
|
||
|
cam_frame_len_offset_t offset;
|
||
|
memset(&offset, 0, sizeof(cam_frame_len_offset_t));
|
||
|
mm_camera_buf_def_t *jpeg_dump_buffer = NULL;
|
||
|
//Dumping images.
|
||
|
cam_dimension_t dim;
|
||
|
dim.width = pic_channel->mCamera3Stream->width;
|
||
|
dim.height = pic_channel->mCamera3Stream->height;
|
||
|
jpeg_dump_buffer = (mm_camera_buf_def_t *)malloc(sizeof(mm_camera_buf_def_t));
|
||
|
if(!jpeg_dump_buffer) {
|
||
|
LOGE("Could not allocate jpeg dump buffer");
|
||
|
} else {
|
||
|
jpeg_dump_buffer->buffer = it->jpeg_image.buf_vaddr;
|
||
|
jpeg_dump_buffer->frame_len = it->jpeg_image.buf_filled_len;
|
||
|
jpeg_dump_buffer->frame_idx =
|
||
|
pic_channel->mJpegMemory.getFrameNumber(job->jpeg_settings->out_buf_index);
|
||
|
pic_channel->dumpYUV(jpeg_dump_buffer, dim, offset, QCAMERA_DUMP_FRM_OUTPUT_JPEG);
|
||
|
free(jpeg_dump_buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mpo_info.num_of_aux_image = MM_JPEG_MAX_MPO_IMAGES - 1;
|
||
|
mpo_info.output = mpo_output;
|
||
|
mpo_info.output.buf_filled_len = 0;
|
||
|
|
||
|
//relaease snapshot buffer before sending mpo callback.
|
||
|
for(auto it = mMpoInputData.begin(); it != mMpoInputData.end(); it++)
|
||
|
{
|
||
|
qcamera_hal3_jpeg_data_t *job = it->jpeg_job;
|
||
|
QCamera3PicChannel * obj = (QCamera3PicChannel *)it->user_data;
|
||
|
if(job->jpeg_settings->image_type == CAM_HAL3_JPEG_TYPE_MAIN
|
||
|
|| job->jpeg_settings->image_type == CAM_HAL3_JPEG_TYPE_DEPTH)
|
||
|
{
|
||
|
obj->releaseSnapshotBuffer(job->src_reproc_frame);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//compose MPO.
|
||
|
//sends MPO event callback to pic channel;
|
||
|
obj->composeMpo(mpo_info, pic_channel);
|
||
|
|
||
|
//release JPEG JOB.
|
||
|
auto it = mMpoInputData.begin();
|
||
|
do {
|
||
|
if(it == mMpoInputData.end())
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
qcamera_hal3_jpeg_data_t *job = it->jpeg_job;
|
||
|
QCamera3PicChannel * obj = (QCamera3PicChannel *)it->user_data;
|
||
|
int bufIdx = job->jpeg_settings->out_buf_index;
|
||
|
int frameNumber = obj->mJpegMemory.getFrameNumber(bufIdx);
|
||
|
if((job->fwk_src_buffer != NULL) || (job->fwk_frame != NULL))
|
||
|
{
|
||
|
obj->releaseOfflineMemory(frameNumber);
|
||
|
} else {
|
||
|
//release offline buffers for MAIN and DEPTH (AUX channel).
|
||
|
if(job->jpeg_settings->image_type != CAM_HAL3_JPEG_TYPE_BOKEH)
|
||
|
{
|
||
|
obj->m_postprocessor.releaseOfflineBuffers(false);
|
||
|
}
|
||
|
}
|
||
|
obj->freeBufferForJpeg(bufIdx);
|
||
|
obj->m_postprocessor.releaseJpegJobData(job);
|
||
|
free(job->jpeg_settings);
|
||
|
free(job);
|
||
|
mMpoInputData.erase(it);
|
||
|
it = mMpoInputData.begin();
|
||
|
}while(it != mMpoInputData.end());
|
||
|
} else {
|
||
|
LOGE("Error: Received NULL JPEG userdata");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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,
|
||
|
const metadata_buffer_t *p_metadata)
|
||
|
{
|
||
|
qcamera_hal3_pp_data_t *job = (qcamera_hal3_pp_data_t *)m_ongoingPPQ.dequeue();
|
||
|
qcamera_hal3_pp_data_t *pending_job;
|
||
|
QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
|
||
|
bool needHalPP = hal_obj->needHALPP();
|
||
|
LOGH("needHalPP:%d", needHalPP);
|
||
|
ATRACE_INT("Camera:Reprocess", 0);
|
||
|
if (job == NULL || ((NULL == job->src_frame) && (NULL == job->fwk_src_frame))) {
|
||
|
LOGE("Cannot find reprocess job");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
LOGD("jpeg settings is :%p and %d",job->jpeg_settings, m_ongoingPPQ.getCurrentSize());
|
||
|
if (job->jpeg_settings == NULL && !m_parent->m_bQuadraChannel)
|
||
|
{
|
||
|
//If needHALPP is true, checking for ouput jpeg settings != NULL
|
||
|
if(!hal_obj->needHALPP() || (job->ppOutput_jpeg_settings == NULL)) {
|
||
|
LOGE("Cannot find jpeg settings");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool hdr_snapshot = FALSE;
|
||
|
if((job->jpeg_settings != NULL && job->jpeg_settings->hdr_snapshot == 1)) {
|
||
|
hdr_snapshot = TRUE;
|
||
|
}
|
||
|
|
||
|
bool multiframe_snapshot = FALSE;
|
||
|
if((job->jpeg_settings != NULL && job->jpeg_settings->multiframe_snapshot == 1)) {
|
||
|
multiframe_snapshot = TRUE;
|
||
|
}
|
||
|
|
||
|
while((hdr_snapshot == TRUE || multiframe_snapshot == TRUE) && (!m_ongoingPPQ.isEmpty()) ) {
|
||
|
LOGD(" Checking if empty");
|
||
|
pending_job = (qcamera_hal3_pp_data_t *)m_ongoingPPQ.dequeue();
|
||
|
if ((pending_job != NULL)) {
|
||
|
LOGD("free reprocessed buffer");
|
||
|
m_parent->freeBufferForFrame(pending_job->src_frame);
|
||
|
m_parent->metadataBufDone(pending_job->src_metadata);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((m_pHalPPManager != NULL) && needHalPP &&
|
||
|
(hal_obj->getHalPPType() != CAM_HAL_PP_TYPE_NONE)) {
|
||
|
qcamera_hal_pp_data_t *hal_pp_job =
|
||
|
(qcamera_hal_pp_data_t*) malloc(sizeof(qcamera_hal_pp_data_t));
|
||
|
if (hal_pp_job == NULL) {
|
||
|
LOGE("No memory for qcamera_hal_pp_data_t data");
|
||
|
return NO_MEMORY;
|
||
|
}
|
||
|
memset(hal_pp_job, 0, sizeof(qcamera_hal_pp_data_t));
|
||
|
|
||
|
|
||
|
// find snapshot frame
|
||
|
QCamera3Channel * srcChannel = getChannelByHandle(frame->ch_id);
|
||
|
if (srcChannel == NULL) {
|
||
|
LOGE("No corresponding channel (ch_id = %d) exist, return here",
|
||
|
frame->ch_id);
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
QCamera3Stream *pSnapStream = NULL;
|
||
|
for (uint32_t i = 0; i < frame->num_bufs; i++) {
|
||
|
QCamera3Stream *pStream =
|
||
|
srcChannel->getStreamByHandle(frame->bufs[i]->stream_id);
|
||
|
if ((pStream != NULL) &&
|
||
|
(pStream->getMyType() == CAM_STREAM_TYPE_SNAPSHOT ||
|
||
|
pStream->getMyType() == CAM_STREAM_TYPE_OFFLINE_PROC)) {
|
||
|
pSnapStream = pStream;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//get snapshot offset info
|
||
|
cam_frame_len_offset_t snap_offset, meta_offset;
|
||
|
memset(&snap_offset, 0, sizeof(cam_frame_len_offset_t));
|
||
|
memset(&meta_offset, 0, sizeof(cam_frame_len_offset_t));
|
||
|
if (pSnapStream != NULL) {
|
||
|
pSnapStream->getFrameOffset(snap_offset);
|
||
|
}
|
||
|
|
||
|
// find meta frame
|
||
|
srcChannel = getChannelByHandle(job->src_frame->ch_id);
|
||
|
if (srcChannel == NULL) {
|
||
|
LOGE("No corresponding channel (ch_id = %d) exist, return here",
|
||
|
job->src_frame->ch_id);
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
QCamera3Stream *pMetaStream = NULL;
|
||
|
for (uint32_t i = 0; i < job->src_frame->num_bufs; i++) {
|
||
|
QCamera3Stream *pStream =
|
||
|
srcChannel->getStreamByHandle(frame->bufs[i]->stream_id);
|
||
|
if ((pStream != NULL) &&
|
||
|
(pStream->getMyType() == CAM_STREAM_TYPE_SNAPSHOT ||
|
||
|
pStream->getMyType() == CAM_STREAM_TYPE_OFFLINE_PROC)) {
|
||
|
pMetaStream = pStream;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (pMetaStream != NULL) {
|
||
|
pMetaStream->getFrameOffset(meta_offset);
|
||
|
}
|
||
|
|
||
|
hal_pp_job->frame = frame;
|
||
|
hal_pp_job->snap_offset = snap_offset;
|
||
|
hal_pp_job->meta_offset = meta_offset;
|
||
|
hal_pp_job->frameIndex = frame->bufs[0]->frame_idx;
|
||
|
hal_pp_job->src_reproc_frame = job ? job->src_frame : NULL;
|
||
|
hal_pp_job->metadata = job ? job->metadata : NULL;
|
||
|
hal_pp_job->jpeg_settings = job ? job->jpeg_settings : NULL;
|
||
|
hal_pp_job->output_jpeg_settings = job ? job->ppOutput_jpeg_settings : NULL;
|
||
|
hal_pp_job->src_metadata = job ? job->src_metadata : NULL;
|
||
|
hal_pp_job->pUserData = this;
|
||
|
//adding blur information for BOKEH process.
|
||
|
if(hal_pp_job->metadata != NULL)
|
||
|
{
|
||
|
QCamera3HardwareInterface * hal_obj = (QCamera3HardwareInterface *)m_parent->mUserData;
|
||
|
uint32_t blurlevel = hal_obj->getBlurLevel();
|
||
|
cam_rtb_blur_info_t blurInfo;
|
||
|
blurInfo.blur_level = blurlevel;
|
||
|
blurInfo.blur_max_value = MAX_BLUR;
|
||
|
blurInfo.blur_min_value = MIN_BLUR;
|
||
|
ADD_SET_PARAM_ENTRY_TO_BATCH(hal_pp_job->metadata,
|
||
|
CAM_INTF_PARAM_BOKEH_BLUR_LEVEL, blurInfo);
|
||
|
}
|
||
|
LOGH("Feeding input to Manager");
|
||
|
m_pHalPPManager->feedInput(hal_pp_job);
|
||
|
free(job);
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
if (job->jpeg_settings != NULL && job->jpeg_settings->zsl_snapshot) {
|
||
|
m_parent->freeBufferForFrame(job->src_frame);
|
||
|
job->src_frame = NULL;
|
||
|
}
|
||
|
|
||
|
if ((job->pp_ch_idx+1) < m_ppChannelCnt) {
|
||
|
job->pp_ch_idx++;
|
||
|
LOGH("next pp index:%d.", job->pp_ch_idx);
|
||
|
|
||
|
if (job->fwk_src_frame != NULL) {
|
||
|
LOGD("reprocess for fwk input frame.");
|
||
|
if (p_metadata != NULL) {
|
||
|
memcpy(job->fwk_src_frame->metadata_buffer.buffer, p_metadata,
|
||
|
sizeof(metadata_buffer_t));
|
||
|
}
|
||
|
} else if (job->src_frame != NULL) {
|
||
|
LOGD("reprocess for non-fwk input frame.");
|
||
|
if (p_metadata != NULL && job->metadata != NULL) {
|
||
|
memcpy(job->metadata, p_metadata, sizeof(metadata_buffer_t));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// the src frame here should be from output of previous reprocess channel
|
||
|
job->reprocessed_src_frame = frame;
|
||
|
m_inputMultiReprocQ.enqueue(job);
|
||
|
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
qcamera_hal3_jpeg_data_t *jpeg_job =
|
||
|
(qcamera_hal3_jpeg_data_t *)malloc(sizeof(qcamera_hal3_jpeg_data_t));
|
||
|
if (jpeg_job == NULL) {
|
||
|
LOGE("No memory for jpeg job");
|
||
|
return NO_MEMORY;
|
||
|
}
|
||
|
|
||
|
memset(jpeg_job, 0, sizeof(qcamera_hal3_jpeg_data_t));
|
||
|
jpeg_job->src_frame = frame;
|
||
|
if(frame != job->src_frame)
|
||
|
jpeg_job->src_reproc_frame = job->src_frame;
|
||
|
if (NULL == job->fwk_src_frame) {
|
||
|
jpeg_job->metadata = job->metadata;
|
||
|
} else {
|
||
|
jpeg_job->metadata =
|
||
|
(metadata_buffer_t *) job->fwk_src_frame->metadata_buffer.buffer;
|
||
|
jpeg_job->fwk_src_buffer = job->fwk_src_frame;
|
||
|
}
|
||
|
if (p_metadata != NULL) {
|
||
|
// update metadata content with input buffer
|
||
|
memcpy(jpeg_job->metadata, p_metadata, sizeof(metadata_buffer_t));
|
||
|
}
|
||
|
jpeg_job->src_metadata = job->src_metadata;
|
||
|
jpeg_job->jpeg_settings = job->jpeg_settings;
|
||
|
|
||
|
if (job->reprocessed_src_frame != NULL) {
|
||
|
LOGD("release output buffers of previous reprocess channel");
|
||
|
for (int8_t i = 0; i < m_ppChannelCnt; i++) {
|
||
|
if (m_pReprocChannel[i] != NULL &&
|
||
|
m_pReprocChannel[i]->getMyHandle() == job->reprocessed_src_frame->ch_id) {
|
||
|
int32_t rc = m_pReprocChannel[i]->bufDone(job->reprocessed_src_frame);
|
||
|
if (NO_ERROR != rc) {
|
||
|
LOGE("bufDone error: %d", rc);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
free(job->reprocessed_src_frame);
|
||
|
job->reprocessed_src_frame = NULL;
|
||
|
}
|
||
|
|
||
|
// 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 : dequeuePPJob
|
||
|
*
|
||
|
* DESCRIPTION: find a postprocessing job from ongoing pp queue by frame number
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @frameNumber : frame number for the pp job
|
||
|
*
|
||
|
* RETURN : ptr to a pp job struct. NULL if not found.
|
||
|
*==========================================================================*/
|
||
|
qcamera_hal3_pp_data_t *QCamera3PostProcessor::dequeuePPJob(uint32_t frameNumber) {
|
||
|
qcamera_hal3_pp_data_t *pp_job = NULL;
|
||
|
pp_job = (qcamera_hal3_pp_data_t *)m_ongoingPPQ.dequeue();
|
||
|
|
||
|
if (pp_job == NULL) {
|
||
|
LOGE("Fatal: ongoing PP queue is empty");
|
||
|
return NULL;
|
||
|
}
|
||
|
if (pp_job->fwk_src_frame &&
|
||
|
(pp_job->fwk_src_frame->frameNumber != frameNumber)) {
|
||
|
LOGE("head of pp queue doesn't match requested frame number");
|
||
|
}
|
||
|
return pp_job;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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_hal3_jpeg_data_t *QCamera3PostProcessor::findJpegJobByJobId(uint32_t jobId)
|
||
|
{
|
||
|
qcamera_hal3_jpeg_data_t * job = NULL;
|
||
|
if (jobId == 0) {
|
||
|
LOGE("not a valid jpeg jobId");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
|
||
|
if(!hal_obj->isDualCamera())
|
||
|
{
|
||
|
mFreeJpegSessions.push_back(mJpegSessionId);
|
||
|
mJpegSessionId = 0;
|
||
|
}
|
||
|
// currely only one jpeg job ongoing, so simply dequeue the head
|
||
|
job = (qcamera_hal3_jpeg_data_t *)m_ongoingJpegQ.dequeue();
|
||
|
return job;
|
||
|
}
|
||
|
|
||
|
int QCamera3PostProcessor::releaseFreeJpegSessions()
|
||
|
{
|
||
|
int ret = NO_ERROR;
|
||
|
auto it = mFreeJpegSessions.begin();
|
||
|
while(it != mFreeJpegSessions.end())
|
||
|
{
|
||
|
ret = mJpegHandle.destroy_session(*it);
|
||
|
if(ret != NO_ERROR)
|
||
|
{
|
||
|
LOGE("failed to destroy jpeg session %d, non-fatal", *it);
|
||
|
}
|
||
|
it = mFreeJpegSessions.erase(it);
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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) {
|
||
|
qcamera_hal3_pp_buffer_t *buf = (qcamera_hal3_pp_buffer_t *)data;
|
||
|
if (NULL != buf) {
|
||
|
if (buf->input) {
|
||
|
pme->releaseSuperBuf(buf->input);
|
||
|
free(buf->input);
|
||
|
buf->input = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : timeoutFrame
|
||
|
*
|
||
|
* DESCRIPTION: Function to handle timeouts in reprocess
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @frameNumber : reprocess frame number that timed out
|
||
|
*
|
||
|
* RETURN : NO_ERROR or valid error number
|
||
|
*==========================================================================*/
|
||
|
int32_t QCamera3PostProcessor::timeoutFrame(uint32_t frameNumber)
|
||
|
{
|
||
|
int32_t rc = NO_ERROR;
|
||
|
|
||
|
if(NULL != m_pReprocChannel[0]) {
|
||
|
rc = m_pReprocChannel[0]->timeoutFrame(frameNumber);
|
||
|
}
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : releaseMetaData
|
||
|
*
|
||
|
* DESCRIPTION: callback function to release metadata camera buffer
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @data : ptr to post process input data
|
||
|
* @user_data : user data ptr (QCamera3Reprocessor)
|
||
|
*
|
||
|
* RETURN : None
|
||
|
*==========================================================================*/
|
||
|
void QCamera3PostProcessor::releaseMetadata(void *data, void *user_data)
|
||
|
{
|
||
|
QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data;
|
||
|
if (NULL != pme) {
|
||
|
qcamera_hal3_meta_pp_buffer_t *buf = (qcamera_hal3_meta_pp_buffer_t *)data;
|
||
|
pme->m_parent->metadataBufDone((mm_camera_super_buf_t *)buf->metabuf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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_hal3_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_hal3_pp_data_t *pp_data = (qcamera_hal3_pp_data_t *)data;
|
||
|
|
||
|
if (pp_data && pp_data->src_frame)
|
||
|
pme->releaseSuperBuf(pp_data->src_frame);
|
||
|
|
||
|
pme->releasePPJobData(pp_data);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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 : releaseOfflineBuffers
|
||
|
*
|
||
|
* DESCRIPTION: function to release/unmap offline buffers if any
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @allBuffers : flag that asks to release all buffers or only one
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t QCamera3PostProcessor::releaseOfflineBuffers(bool allBuffers)
|
||
|
{
|
||
|
int32_t rc = NO_ERROR;
|
||
|
|
||
|
for (int8_t i = 0; i < m_ppChannelCnt; i++) {
|
||
|
QCamera3ReprocessChannel *pChannel = m_pReprocChannel[i];
|
||
|
if (pChannel != NULL ) {
|
||
|
rc |= pChannel->unmapOfflineBuffers(allBuffers);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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_hal3_jpeg_data_t *job)
|
||
|
{
|
||
|
ATRACE_CAMSCOPE_CALL(CAMSCOPE_HAL3_PPROC_REL_JPEG_JOB_DATA);
|
||
|
int32_t rc = NO_ERROR;
|
||
|
LOGD("E");
|
||
|
if (NULL != job) {
|
||
|
if (NULL != job->src_reproc_frame) {
|
||
|
free(job->src_reproc_frame);
|
||
|
job->src_reproc_frame = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != job->src_frame) {
|
||
|
if(!job->halPPAllocatedBuf)
|
||
|
{
|
||
|
// find the correct reprocess channel for the super buffer
|
||
|
for (int8_t i = 0; i < m_ppChannelCnt; i++) {
|
||
|
if (m_pReprocChannel[i] != NULL &&
|
||
|
m_pReprocChannel[i]->getMyHandle() == job->src_frame->ch_id) {
|
||
|
rc = m_pReprocChannel[i]->bufDone(job->src_frame);
|
||
|
if (NO_ERROR != rc) {
|
||
|
LOGE("bufDone error: %d", rc);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if (job->hal_pp_bufs) {
|
||
|
free(job->hal_pp_bufs);
|
||
|
job->hal_pp_bufs = NULL;
|
||
|
}
|
||
|
if (job->snapshot_heap) {
|
||
|
job->snapshot_heap->deallocate();
|
||
|
delete job->snapshot_heap;
|
||
|
job->snapshot_heap = NULL;
|
||
|
}
|
||
|
if (job->metadata_heap) {
|
||
|
job->metadata_heap->deallocate();
|
||
|
delete job->metadata_heap;
|
||
|
job->metadata_heap = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
free(job->src_frame);
|
||
|
job->src_frame = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != job->fwk_src_buffer) {
|
||
|
free(job->fwk_src_buffer);
|
||
|
job->fwk_src_buffer = NULL;
|
||
|
} else if (NULL != job->src_metadata) {
|
||
|
m_parent->metadataBufDone(job->src_metadata);
|
||
|
free(job->src_metadata);
|
||
|
job->src_metadata = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != job->fwk_frame) {
|
||
|
free(job->fwk_frame);
|
||
|
job->fwk_frame = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != job->pJpegExifObj) {
|
||
|
delete job->pJpegExifObj;
|
||
|
job->pJpegExifObj = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != job->jpeg_settings) {
|
||
|
free(job->jpeg_settings);
|
||
|
job->jpeg_settings = NULL;
|
||
|
}
|
||
|
}
|
||
|
/* Additional trigger to process any pending jobs in the input queue */
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
|
||
|
LOGD("X");
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : releasePPJobData
|
||
|
*
|
||
|
* DESCRIPTION: function to release internal resources in p pjob struct
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @job : ptr to pp job struct
|
||
|
*
|
||
|
* RETURN : None
|
||
|
*
|
||
|
* NOTE : Original source metadata buffer needs to be released and
|
||
|
* queued back to kernel for future use. src_frame, src_metadata,
|
||
|
* and fwk_src_frame structures need to be freed.
|
||
|
*==========================================================================*/
|
||
|
void QCamera3PostProcessor::releasePPJobData(qcamera_hal3_pp_data_t *pp_job)
|
||
|
{
|
||
|
ATRACE_CAMSCOPE_CALL(CAMSCOPE_HAL3_PPROC_REL_PP_JOB_DATA);
|
||
|
LOGD("E");
|
||
|
if (NULL != pp_job) {
|
||
|
if (NULL != pp_job->src_frame) {
|
||
|
free(pp_job->src_frame);
|
||
|
if (NULL != pp_job->src_metadata) {
|
||
|
m_parent->metadataBufDone(pp_job->src_metadata);
|
||
|
free(pp_job->src_metadata);
|
||
|
}
|
||
|
pp_job->src_frame = NULL;
|
||
|
pp_job->metadata = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != pp_job->fwk_src_frame) {
|
||
|
free(pp_job->fwk_src_frame);
|
||
|
pp_job->fwk_src_frame = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Additional trigger to process any pending jobs in the input queue */
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
|
||
|
LOGD("X");
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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:
|
||
|
case CAM_FORMAT_YUV_420_NV21_VENUS:
|
||
|
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:
|
||
|
case CAM_FORMAT_YUV_420_NV12_VENUS:
|
||
|
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;
|
||
|
case CAM_FORMAT_Y_ONLY:
|
||
|
return MM_JPEG_COLOR_FORMAT_MONOCHROME;
|
||
|
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_NV12_VENUS:
|
||
|
case CAM_FORMAT_YUV_420_NV21_VENUS:
|
||
|
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 : encodeFWKData
|
||
|
*
|
||
|
* 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::encodeFWKData(qcamera_hal3_jpeg_data_t *jpeg_job_data,
|
||
|
uint8_t &needNewSess)
|
||
|
{
|
||
|
LOGD("E");
|
||
|
int32_t ret = NO_ERROR;
|
||
|
mm_jpeg_job_t jpg_job;
|
||
|
uint32_t jobId = 0;
|
||
|
qcamera_fwk_input_pp_data_t *recvd_frame = NULL;
|
||
|
metadata_buffer_t *metadata = NULL;
|
||
|
jpeg_settings_t *jpeg_settings = NULL;
|
||
|
QCamera3HardwareInterface* hal_obj = NULL;
|
||
|
mm_jpeg_debug_exif_params_t *exif_debug_params = NULL;
|
||
|
bool needJpegExifRotation = false;
|
||
|
|
||
|
if (NULL == jpeg_job_data) {
|
||
|
LOGE("Invalid jpeg job");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
recvd_frame = jpeg_job_data->fwk_frame;
|
||
|
if (NULL == recvd_frame) {
|
||
|
LOGE("Invalid input buffer");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
metadata = jpeg_job_data->metadata;
|
||
|
if (NULL == metadata) {
|
||
|
LOGE("Invalid metadata buffer");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
jpeg_settings = jpeg_job_data->jpeg_settings;
|
||
|
if (NULL == jpeg_settings) {
|
||
|
LOGE("Invalid jpeg settings buffer");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
if ((NULL != jpeg_job_data->fwk_frame) && (NULL != jpeg_job_data->src_frame)) {
|
||
|
LOGE("Unsupported case both framework and camera source buffers are invalid!");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
|
||
|
if (hal_obj == NULL) {
|
||
|
LOGE("hal_obj is NULL, Error");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
if (mJpegClientHandle <= 0) {
|
||
|
LOGE("Error: bug here, mJpegClientHandle is 0");
|
||
|
return UNKNOWN_ERROR;
|
||
|
}
|
||
|
|
||
|
cam_dimension_t src_dim;
|
||
|
memset(&src_dim, 0, sizeof(cam_dimension_t));
|
||
|
src_dim.width = recvd_frame->reproc_config.input_stream_dim.width;
|
||
|
src_dim.height = recvd_frame->reproc_config.input_stream_dim.height;
|
||
|
|
||
|
cam_dimension_t dst_dim;
|
||
|
memset(&dst_dim, 0, sizeof(cam_dimension_t));
|
||
|
dst_dim.width = recvd_frame->reproc_config.output_stream_dim.width;
|
||
|
dst_dim.height = recvd_frame->reproc_config.output_stream_dim.height;
|
||
|
|
||
|
cam_rect_t crop;
|
||
|
memset(&crop, 0, sizeof(cam_rect_t));
|
||
|
//TBD_later - Zoom event removed in stream
|
||
|
//main_stream->getCropInfo(crop);
|
||
|
// Set JPEG encode crop in reprocess frame metadata
|
||
|
// If this JPEG crop info exist, encoder should do cropping
|
||
|
IF_META_AVAILABLE(cam_stream_crop_info_t, jpeg_crop,
|
||
|
CAM_INTF_PARM_JPEG_ENCODE_CROP, metadata) {
|
||
|
memcpy(&crop, &(jpeg_crop->crop), sizeof(cam_rect_t));
|
||
|
}
|
||
|
|
||
|
// Set JPEG encode crop in reprocess frame metadata
|
||
|
// If this JPEG scale info exist, encoder should do scaling
|
||
|
IF_META_AVAILABLE(cam_dimension_t, scale_dim,
|
||
|
CAM_INTF_PARM_JPEG_SCALE_DIMENSION, metadata) {
|
||
|
if (scale_dim->width != 0 && scale_dim->height != 0) {
|
||
|
dst_dim.width = scale_dim->width;
|
||
|
dst_dim.height = scale_dim->height;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
needJpegExifRotation = (hal_obj->needJpegExifRotation() || !needsReprocess(recvd_frame));
|
||
|
|
||
|
// If EXIF rotation metadata is added and used to match the JPEG orientation,
|
||
|
// it means CPP rotation is not involved, whether it is because CPP does not
|
||
|
// support rotation, or the reprocessed frame is not sent to CPP.
|
||
|
// Override CAM_INTF_PARM_ROTATION to 0 to avoid wrong CPP rotation info
|
||
|
// to be filled in to JPEG metadata.
|
||
|
if (needJpegExifRotation) {
|
||
|
cam_rotation_info_t rotation_info;
|
||
|
memset(&rotation_info, 0, sizeof(rotation_info));
|
||
|
rotation_info.rotation = ROTATE_0;
|
||
|
rotation_info.streamId = 0;
|
||
|
ADD_SET_PARAM_ENTRY_TO_BATCH(metadata, CAM_INTF_PARM_ROTATION, rotation_info);
|
||
|
}
|
||
|
|
||
|
LOGH("Need new session?:%d jpeg_orientation %d needJpegExifRotation %d useExifRotation %d",
|
||
|
needNewSess, jpeg_settings->jpeg_orientation, needJpegExifRotation,
|
||
|
hal_obj->useExifRotation());
|
||
|
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) {
|
||
|
LOGE("Error destroying an old jpeg encoding session, id = %d",
|
||
|
mJpegSessionId);
|
||
|
return ret;
|
||
|
}
|
||
|
mJpegSessionId = 0;
|
||
|
}
|
||
|
// create jpeg encoding session
|
||
|
mm_jpeg_encode_params_t encodeParam;
|
||
|
memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t));
|
||
|
getFWKJpegEncodeConfig(encodeParam, recvd_frame, jpeg_settings);
|
||
|
QCamera3StreamMem *memObj = (QCamera3StreamMem *)(recvd_frame->input_buffer.mem_info);
|
||
|
if (NULL == memObj) {
|
||
|
LOGE("Memeory Obj of main frame is NULL");
|
||
|
return NO_MEMORY;
|
||
|
}
|
||
|
// clean and invalidate cache ops through mem obj of the frame
|
||
|
memObj->cleanInvalidateCache(recvd_frame->input_buffer.buf_idx);
|
||
|
|
||
|
LOGH("#src bufs:%d # tmb bufs:%d #dst_bufs:%d",
|
||
|
encodeParam.num_src_bufs,encodeParam.num_tmb_bufs,encodeParam.num_dst_bufs);
|
||
|
if (!needJpegExifRotation &&
|
||
|
(jpeg_settings->jpeg_orientation == 90 ||
|
||
|
jpeg_settings->jpeg_orientation == 270)) {
|
||
|
// swap src width and height, stride and scanline due to rotation
|
||
|
encodeParam.main_dim.src_dim.width = src_dim.height;
|
||
|
encodeParam.main_dim.src_dim.height = src_dim.width;
|
||
|
encodeParam.thumb_dim.src_dim.width = src_dim.height;
|
||
|
encodeParam.thumb_dim.src_dim.height = src_dim.width;
|
||
|
|
||
|
int32_t temp = encodeParam.src_main_buf[0].offset.mp[0].stride;
|
||
|
encodeParam.src_main_buf[0].offset.mp[0].stride =
|
||
|
encodeParam.src_main_buf[0].offset.mp[0].scanline;
|
||
|
encodeParam.src_main_buf[0].offset.mp[0].scanline = temp;
|
||
|
|
||
|
temp = encodeParam.src_thumb_buf[0].offset.mp[0].stride;
|
||
|
encodeParam.src_thumb_buf[0].offset.mp[0].stride =
|
||
|
encodeParam.src_thumb_buf[0].offset.mp[0].scanline;
|
||
|
encodeParam.src_thumb_buf[0].offset.mp[0].scanline = temp;
|
||
|
} else {
|
||
|
encodeParam.main_dim.src_dim = src_dim;
|
||
|
encodeParam.thumb_dim.src_dim = src_dim;
|
||
|
}
|
||
|
encodeParam.main_dim.dst_dim = dst_dim;
|
||
|
encodeParam.thumb_dim.dst_dim = jpeg_settings->thumbnail_size;
|
||
|
|
||
|
if (!hal_obj->useExifRotation() && needJpegExifRotation) {
|
||
|
encodeParam.rotation = jpeg_settings->jpeg_orientation;
|
||
|
encodeParam.thumb_rotation = jpeg_settings->jpeg_orientation;
|
||
|
}
|
||
|
|
||
|
LOGI("Src Buffer cnt = %d, res = %dX%d len = %d rot = %d "
|
||
|
"src_dim = %dX%d dst_dim = %dX%d",
|
||
|
encodeParam.num_src_bufs,
|
||
|
encodeParam.src_main_buf[0].offset.mp[0].stride,
|
||
|
encodeParam.src_main_buf[0].offset.mp[0].scanline,
|
||
|
encodeParam.src_main_buf[0].offset.frame_len,
|
||
|
encodeParam.rotation,
|
||
|
src_dim.width, src_dim.height,
|
||
|
dst_dim.width, dst_dim.height);
|
||
|
LOGI("Src THUMB buf_cnt = %d, res = %dX%d len = %d rot = %d "
|
||
|
"src_dim = %dX%d, dst_dim = %dX%d",
|
||
|
encodeParam.num_tmb_bufs,
|
||
|
encodeParam.src_thumb_buf[0].offset.mp[0].stride,
|
||
|
encodeParam.src_thumb_buf[0].offset.mp[0].scanline,
|
||
|
encodeParam.src_thumb_buf[0].offset.frame_len,
|
||
|
encodeParam.thumb_rotation,
|
||
|
encodeParam.thumb_dim.src_dim.width,
|
||
|
encodeParam.thumb_dim.src_dim.height,
|
||
|
encodeParam.thumb_dim.dst_dim.width,
|
||
|
encodeParam.thumb_dim.dst_dim.height);
|
||
|
|
||
|
LOGH("#src bufs:%d # tmb bufs:%d #dst_bufs:%d",
|
||
|
encodeParam.num_src_bufs,encodeParam.num_tmb_bufs,encodeParam.num_dst_bufs);
|
||
|
|
||
|
ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId);
|
||
|
if (ret != NO_ERROR) {
|
||
|
LOGE("Error creating a new jpeg encoding session, ret = %d", 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 = 0;
|
||
|
jpg_job.encode_job.dst_index = 0;
|
||
|
|
||
|
// Set main dim job parameters and handle rotation
|
||
|
if (!needJpegExifRotation && (jpeg_settings->jpeg_orientation == 90 ||
|
||
|
jpeg_settings->jpeg_orientation == 270)) {
|
||
|
|
||
|
jpg_job.encode_job.main_dim.src_dim.width = src_dim.height;
|
||
|
jpg_job.encode_job.main_dim.src_dim.height = src_dim.width;
|
||
|
|
||
|
jpg_job.encode_job.main_dim.dst_dim.width = dst_dim.height;
|
||
|
jpg_job.encode_job.main_dim.dst_dim.height = dst_dim.width;
|
||
|
|
||
|
jpg_job.encode_job.main_dim.crop.width = crop.height;
|
||
|
jpg_job.encode_job.main_dim.crop.height = crop.width;
|
||
|
jpg_job.encode_job.main_dim.crop.left = crop.top;
|
||
|
jpg_job.encode_job.main_dim.crop.top = crop.left;
|
||
|
} else {
|
||
|
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 3a sw version info
|
||
|
cam_q3a_version_t sw_version;
|
||
|
memset(&sw_version, 0, sizeof(sw_version));
|
||
|
if (hal_obj)
|
||
|
hal_obj->get3AVersion(sw_version);
|
||
|
|
||
|
// get exif data
|
||
|
QCamera3Exif *pJpegExifObj = getExifData(metadata, jpeg_settings,
|
||
|
(needJpegExifRotation && hal_obj->useExifRotation()));
|
||
|
jpeg_job_data->pJpegExifObj = pJpegExifObj;
|
||
|
if (pJpegExifObj != NULL) {
|
||
|
jpg_job.encode_job.exif_info.exif_data = pJpegExifObj->getEntries();
|
||
|
jpg_job.encode_job.exif_info.numOfEntries =
|
||
|
pJpegExifObj->getNumOfEntries();
|
||
|
jpg_job.encode_job.exif_info.debug_data.sw_3a_version[0] =
|
||
|
sw_version.major_version;
|
||
|
jpg_job.encode_job.exif_info.debug_data.sw_3a_version[1] =
|
||
|
sw_version.minor_version;
|
||
|
jpg_job.encode_job.exif_info.debug_data.sw_3a_version[2] =
|
||
|
sw_version.patch_version;
|
||
|
jpg_job.encode_job.exif_info.debug_data.sw_3a_version[3] =
|
||
|
sw_version.new_feature_des;
|
||
|
}
|
||
|
|
||
|
if (!hal_obj->useExifRotation() && needJpegExifRotation) {
|
||
|
jpg_job.encode_job.rotation= jpeg_settings->jpeg_orientation;
|
||
|
}
|
||
|
|
||
|
// thumbnail dim
|
||
|
LOGH("Thumbnail needed:%d", m_bThumbnailNeeded);
|
||
|
if (m_bThumbnailNeeded == TRUE) {
|
||
|
jpg_job.encode_job.thumb_dim.dst_dim =
|
||
|
jpeg_settings->thumbnail_size;
|
||
|
|
||
|
if (!needJpegExifRotation && (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.width = src_dim.height;
|
||
|
jpg_job.encode_job.thumb_dim.src_dim.height = src_dim.width;
|
||
|
|
||
|
jpg_job.encode_job.thumb_dim.crop.width = crop.height;
|
||
|
jpg_job.encode_job.thumb_dim.crop.height = crop.width;
|
||
|
jpg_job.encode_job.thumb_dim.crop.left = crop.top;
|
||
|
jpg_job.encode_job.thumb_dim.crop.top = crop.left;
|
||
|
} else {
|
||
|
jpg_job.encode_job.thumb_dim.src_dim = src_dim;
|
||
|
jpg_job.encode_job.thumb_dim.crop = crop;
|
||
|
}
|
||
|
jpg_job.encode_job.thumb_index = 0;
|
||
|
LOGI("Thumbnail idx = %d src w/h (%dx%d), dst w/h (%dx%d)",
|
||
|
jpg_job.encode_job.thumb_index,
|
||
|
jpg_job.encode_job.thumb_dim.src_dim.width,
|
||
|
jpg_job.encode_job.thumb_dim.src_dim.height,
|
||
|
jpg_job.encode_job.thumb_dim.dst_dim.width,
|
||
|
jpg_job.encode_job.thumb_dim.dst_dim.height);
|
||
|
}
|
||
|
|
||
|
LOGI("Main image idx = %d src w/h (%dx%d), dst w/h (%dx%d) rot = %d",
|
||
|
jpg_job.encode_job.src_index,
|
||
|
jpg_job.encode_job.main_dim.src_dim.width,
|
||
|
jpg_job.encode_job.main_dim.src_dim.height,
|
||
|
jpg_job.encode_job.main_dim.dst_dim.width,
|
||
|
jpg_job.encode_job.main_dim.dst_dim.height,
|
||
|
jpg_job.encode_job.rotation);
|
||
|
// Allocate for a local copy of debug parameters
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params =
|
||
|
(mm_jpeg_debug_exif_params_t *) malloc (sizeof(mm_jpeg_debug_exif_params_t));
|
||
|
if (!jpg_job.encode_job.cam_exif_params.debug_params) {
|
||
|
LOGE("Out of Memory. Allocation failed for 3A debug exif params");
|
||
|
return NO_MEMORY;
|
||
|
}
|
||
|
|
||
|
memset(jpg_job.encode_job.cam_exif_params.debug_params, 0,
|
||
|
sizeof(mm_jpeg_debug_exif_params_t));
|
||
|
exif_debug_params = jpg_job.encode_job.cam_exif_params.debug_params;
|
||
|
|
||
|
jpg_job.encode_job.mobicat_mask = hal_obj->getMobicatMask();
|
||
|
|
||
|
if (metadata != NULL) {
|
||
|
// Fill in the metadata passed as parameter
|
||
|
jpg_job.encode_job.p_metadata = metadata;
|
||
|
|
||
|
// Fill in exif debug data
|
||
|
if (exif_debug_params) {
|
||
|
// AE
|
||
|
IF_META_AVAILABLE(cam_ae_exif_debug_t, ae_exif_debug_params,
|
||
|
CAM_INTF_META_EXIF_DEBUG_AE, metadata) {
|
||
|
memcpy(&exif_debug_params->ae_debug_params, ae_exif_debug_params,
|
||
|
sizeof(cam_ae_exif_debug_t));
|
||
|
memcpy(&jpg_job.encode_job.p_metadata->statsdebug_ae_data,
|
||
|
ae_exif_debug_params, sizeof(cam_ae_exif_debug_t));
|
||
|
exif_debug_params->ae_debug_params_valid = TRUE;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_ae_params_valid = TRUE;
|
||
|
}
|
||
|
// AWB
|
||
|
IF_META_AVAILABLE(cam_awb_exif_debug_t, awb_exif_debug_params,
|
||
|
CAM_INTF_META_EXIF_DEBUG_AWB, metadata) {
|
||
|
memcpy(&exif_debug_params->awb_debug_params, awb_exif_debug_params,
|
||
|
sizeof(cam_awb_exif_debug_t));
|
||
|
memcpy(&jpg_job.encode_job.p_metadata->statsdebug_awb_data,
|
||
|
awb_exif_debug_params, sizeof(cam_awb_exif_debug_t));
|
||
|
exif_debug_params->awb_debug_params_valid = TRUE;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_awb_params_valid = TRUE;
|
||
|
}
|
||
|
// AF
|
||
|
IF_META_AVAILABLE(cam_af_exif_debug_t, af_exif_debug_params,
|
||
|
CAM_INTF_META_EXIF_DEBUG_AF, metadata) {
|
||
|
memcpy(&exif_debug_params->af_debug_params, af_exif_debug_params,
|
||
|
sizeof(cam_af_exif_debug_t));
|
||
|
memcpy(&jpg_job.encode_job.p_metadata->statsdebug_af_data,
|
||
|
af_exif_debug_params, sizeof(cam_af_exif_debug_t));
|
||
|
exif_debug_params->af_debug_params_valid = TRUE;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_af_params_valid = TRUE;
|
||
|
}
|
||
|
// ASD
|
||
|
IF_META_AVAILABLE(cam_asd_exif_debug_t, asd_exif_debug_params,
|
||
|
CAM_INTF_META_EXIF_DEBUG_ASD, metadata) {
|
||
|
memcpy(&exif_debug_params->asd_debug_params, asd_exif_debug_params,
|
||
|
sizeof(cam_asd_exif_debug_t));
|
||
|
memcpy(&jpg_job.encode_job.p_metadata->statsdebug_asd_data,
|
||
|
asd_exif_debug_params, sizeof(cam_asd_exif_debug_t));
|
||
|
exif_debug_params->asd_debug_params_valid = TRUE;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_asd_params_valid = TRUE;
|
||
|
}
|
||
|
// STATS
|
||
|
IF_META_AVAILABLE(cam_stats_buffer_exif_debug_t, stats_exif_debug_params,
|
||
|
CAM_INTF_META_EXIF_DEBUG_STATS, metadata) {
|
||
|
memcpy(&exif_debug_params->stats_debug_params, stats_exif_debug_params,
|
||
|
sizeof(cam_stats_buffer_exif_debug_t));
|
||
|
memcpy(&jpg_job.encode_job.p_metadata->statsdebug_stats_buffer_data,
|
||
|
stats_exif_debug_params, sizeof(cam_stats_buffer_exif_debug_t));
|
||
|
exif_debug_params->stats_debug_params_valid = TRUE;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_stats_params_valid = TRUE;
|
||
|
}
|
||
|
// BE STATS
|
||
|
IF_META_AVAILABLE(cam_bestats_buffer_exif_debug_t, bestats_exif_debug_params,
|
||
|
CAM_INTF_META_EXIF_DEBUG_BESTATS, metadata) {
|
||
|
memcpy(&exif_debug_params->bestats_debug_params, bestats_exif_debug_params,
|
||
|
sizeof(cam_bestats_buffer_exif_debug_t));
|
||
|
memcpy(&jpg_job.encode_job.p_metadata->statsdebug_bestats_buffer_data,
|
||
|
bestats_exif_debug_params, sizeof(cam_bestats_buffer_exif_debug_t));
|
||
|
exif_debug_params->bestats_debug_params_valid = TRUE;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_bestats_params_valid = TRUE;
|
||
|
}
|
||
|
// BHIST
|
||
|
IF_META_AVAILABLE(cam_bhist_buffer_exif_debug_t, bhist_exif_debug_params,
|
||
|
CAM_INTF_META_EXIF_DEBUG_BHIST, metadata) {
|
||
|
memcpy(&exif_debug_params->bhist_debug_params, bhist_exif_debug_params,
|
||
|
sizeof(cam_bhist_buffer_exif_debug_t));
|
||
|
memcpy(&jpg_job.encode_job.p_metadata->statsdebug_bhist_data,
|
||
|
bhist_exif_debug_params, sizeof(cam_bhist_buffer_exif_debug_t));
|
||
|
exif_debug_params->bhist_debug_params_valid = TRUE;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_bhist_params_valid = TRUE;
|
||
|
}
|
||
|
// Q3A
|
||
|
IF_META_AVAILABLE(cam_q3a_tuning_info_t, q3a_tuning_exif_debug_params,
|
||
|
CAM_INTF_META_EXIF_DEBUG_3A_TUNING, metadata) {
|
||
|
memcpy(&exif_debug_params->q3a_tuning_debug_params, q3a_tuning_exif_debug_params,
|
||
|
sizeof(cam_q3a_tuning_info_t));
|
||
|
memcpy(&jpg_job.encode_job.p_metadata->statsdebug_3a_tuning_data,
|
||
|
q3a_tuning_exif_debug_params, sizeof(cam_q3a_tuning_info_t));
|
||
|
exif_debug_params->q3a_tuning_debug_params_valid = TRUE;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_3a_tuning_params_valid = TRUE;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
LOGW("Metadata is null");
|
||
|
}
|
||
|
|
||
|
// Multi image info
|
||
|
if (hal_obj->isDeviceLinked() == TRUE) {
|
||
|
jpg_job.encode_job.multi_image_info.type = MM_JPEG_TYPE_JPEG;
|
||
|
jpg_job.encode_job.multi_image_info.num_of_images = 1;
|
||
|
jpg_job.encode_job.multi_image_info.enable_metadata = 1;
|
||
|
if (hal_obj->isMainCamera() == TRUE) {
|
||
|
jpg_job.encode_job.multi_image_info.is_primary = 1;
|
||
|
} else {
|
||
|
jpg_job.encode_job.multi_image_info.is_primary = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
jpg_job.encode_job.hal_version = CAM_HAL_V3;
|
||
|
|
||
|
//Start jpeg encoding
|
||
|
ret = mJpegHandle.start_job(&jpg_job, &jobId);
|
||
|
if (jpg_job.encode_job.cam_exif_params.debug_params) {
|
||
|
free(jpg_job.encode_job.cam_exif_params.debug_params);
|
||
|
}
|
||
|
if (ret == NO_ERROR) {
|
||
|
// remember job info
|
||
|
jpeg_job_data->jobId = jobId;
|
||
|
}
|
||
|
|
||
|
LOGD("X");
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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_hal3_jpeg_data_t *jpeg_job_data,
|
||
|
uint8_t &needNewSess)
|
||
|
{
|
||
|
ATRACE_CAMSCOPE_CALL(CAMSCOPE_HAL3_PPROC_ENCODEDATA);
|
||
|
LOGD("E");
|
||
|
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;
|
||
|
cam_stream_parm_buffer_t param;
|
||
|
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;
|
||
|
mm_jpeg_debug_exif_params_t *exif_debug_params = NULL;
|
||
|
if (m_parent != NULL) {
|
||
|
hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
|
||
|
if (hal_obj == NULL) {
|
||
|
LOGE("hal_obj is NULL, Error");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
} else {
|
||
|
LOGE("m_parent is NULL, Error");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
bool needJpegExifRotation = false;
|
||
|
|
||
|
recvd_frame = jpeg_job_data->src_frame;
|
||
|
metadata = jpeg_job_data->metadata;
|
||
|
jpeg_settings = jpeg_job_data->jpeg_settings;
|
||
|
|
||
|
LOGD("encoding bufIndex: %u",
|
||
|
jpeg_job_data->src_frame->bufs[0]->buf_idx);
|
||
|
|
||
|
QCamera3Channel *pChannel = NULL;
|
||
|
// first check picture channel
|
||
|
if ((is_dual_camera_by_handle(m_parent->getMyHandle())
|
||
|
&& ((get_main_camera_handle(m_parent->getMyHandle()) == recvd_frame->ch_id)
|
||
|
|| (get_aux_camera_handle(m_parent->getMyHandle()) == recvd_frame->ch_id)))
|
||
|
|| (m_parent->getMyHandle() == recvd_frame->ch_id)) {
|
||
|
pChannel = m_parent;
|
||
|
}
|
||
|
// check reprocess channel if not found
|
||
|
if (pChannel == NULL) {
|
||
|
for (int8_t i = 0; i < m_ppChannelCnt; i++) {
|
||
|
if (m_pReprocChannel[i] != NULL &&
|
||
|
m_pReprocChannel[i]->getMyHandle() == recvd_frame->ch_id) {
|
||
|
pChannel = m_pReprocChannel[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
srcChannel = pChannel;
|
||
|
|
||
|
if (srcChannel == NULL) {
|
||
|
LOGE("No corresponding channel (ch_id = %d) exist, return here",
|
||
|
recvd_frame->ch_id);
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
// find snapshot frame and thumnail frame
|
||
|
//Note: In this version we will receive only snapshot frame.
|
||
|
for (uint32_t i = 0; i < recvd_frame->num_bufs; i++) {
|
||
|
QCamera3Stream *srcStream = NULL;
|
||
|
srcStream = srcChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id);
|
||
|
if (srcStream != NULL) {
|
||
|
switch (srcStream->getMyType()) {
|
||
|
case CAM_STREAM_TYPE_SNAPSHOT:
|
||
|
case CAM_STREAM_TYPE_OFFLINE_PROC:
|
||
|
main_stream = srcStream;
|
||
|
main_frame = recvd_frame->bufs[i];
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(NULL == main_frame){
|
||
|
LOGE("Main frame is NULL");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
if (!jpeg_job_data->halPPAllocatedBuf) {
|
||
|
QCamera3StreamMem *memObj = (QCamera3StreamMem *)main_frame->mem_info;
|
||
|
if (NULL == memObj) {
|
||
|
LOGE("Memeory Obj of main frame is NULL");
|
||
|
return NO_MEMORY;
|
||
|
}
|
||
|
|
||
|
// clean and invalidate cache ops through mem obj of the frame
|
||
|
memObj->cleanInvalidateCache(main_frame->buf_idx);
|
||
|
}
|
||
|
|
||
|
if (mJpegClientHandle <= 0) {
|
||
|
LOGE("Error: bug here, mJpegClientHandle is 0");
|
||
|
return UNKNOWN_ERROR;
|
||
|
}
|
||
|
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));
|
||
|
|
||
|
//For depth images calculate src and des dim from getDepthMapSize.
|
||
|
if(jpeg_settings->image_type == CAM_HAL3_JPEG_TYPE_DEPTH)
|
||
|
{
|
||
|
#ifdef ENABLE_QC_BOKEH
|
||
|
qrcp::getDepthMapSize(src_dim.width, src_dim.height,
|
||
|
src_dim.width, src_dim.height);
|
||
|
#endif //ENABLE_QC_BOKEH
|
||
|
dst_dim = src_dim;
|
||
|
} else if(jpeg_settings->is_dim_valid){
|
||
|
dst_dim = jpeg_settings->output_dim;
|
||
|
} else {
|
||
|
if (NO_ERROR != m_parent->getStreamSize(dst_dim)) {
|
||
|
LOGE("Failed to get size of the JPEG stream");
|
||
|
return UNKNOWN_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
needJpegExifRotation = hal_obj->needJpegExifRotation();
|
||
|
IF_META_AVAILABLE(cam_rotation_info_t, rotation_info, CAM_INTF_PARM_ROTATION, metadata) {
|
||
|
if (jpeg_settings->jpeg_orientation != 0 && rotation_info->rotation == ROTATE_0) {
|
||
|
needJpegExifRotation = TRUE;
|
||
|
LOGH("Need EXIF JPEG ROTATION");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Although in HAL3, legacy flip mode is not advertised
|
||
|
// default value of CAM_INTF_PARM_FLIP is still added here
|
||
|
// for jpge metadata
|
||
|
int32_t flipMode = 0; // no flip
|
||
|
ADD_SET_PARAM_ENTRY_TO_BATCH(metadata, CAM_INTF_PARM_FLIP, flipMode);
|
||
|
|
||
|
LOGH("Need new session?:%d jpeg_orientation %d needJpegExifRotation %d useExifRotation %d",
|
||
|
needNewSess, jpeg_settings->jpeg_orientation, needJpegExifRotation,
|
||
|
hal_obj->useExifRotation());
|
||
|
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) {
|
||
|
LOGE("Error destroying an old jpeg encoding session, id = %d",
|
||
|
mJpegSessionId);
|
||
|
return ret;
|
||
|
}
|
||
|
mJpegSessionId = 0;
|
||
|
}
|
||
|
// create jpeg encoding session
|
||
|
mm_jpeg_encode_params_t encodeParam;
|
||
|
memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t));
|
||
|
if(jpeg_settings->image_type == CAM_HAL3_JPEG_TYPE_DEPTH ||
|
||
|
jpeg_settings->image_type == CAM_HAL3_JPEG_TYPE_BOKEH)
|
||
|
{
|
||
|
getJpegEncodeConfig(encodeParam, main_stream, jpeg_settings, recvd_frame->bufs[0]);
|
||
|
} else {
|
||
|
getJpegEncodeConfig(encodeParam, main_stream, jpeg_settings);
|
||
|
}
|
||
|
LOGH("#src bufs:%d # tmb bufs:%d #dst_bufs:%d",
|
||
|
encodeParam.num_src_bufs,encodeParam.num_tmb_bufs,encodeParam.num_dst_bufs);
|
||
|
if (!needJpegExifRotation &&
|
||
|
(jpeg_settings->jpeg_orientation == 90 ||
|
||
|
jpeg_settings->jpeg_orientation == 270)) {
|
||
|
//swap src width and height, stride and scanline due to rotation
|
||
|
encodeParam.main_dim.src_dim.width = src_dim.height;
|
||
|
encodeParam.main_dim.src_dim.height = src_dim.width;
|
||
|
encodeParam.thumb_dim.src_dim.width = src_dim.height;
|
||
|
encodeParam.thumb_dim.src_dim.height = src_dim.width;
|
||
|
|
||
|
int32_t temp = encodeParam.src_main_buf[0].offset.mp[0].stride;
|
||
|
encodeParam.src_main_buf[0].offset.mp[0].stride =
|
||
|
encodeParam.src_main_buf[0].offset.mp[0].scanline;
|
||
|
encodeParam.src_main_buf[0].offset.mp[0].scanline = temp;
|
||
|
|
||
|
temp = encodeParam.src_thumb_buf[0].offset.mp[0].stride;
|
||
|
encodeParam.src_thumb_buf[0].offset.mp[0].stride =
|
||
|
encodeParam.src_thumb_buf[0].offset.mp[0].scanline;
|
||
|
encodeParam.src_thumb_buf[0].offset.mp[0].scanline = temp;
|
||
|
} else {
|
||
|
encodeParam.main_dim.src_dim = src_dim;
|
||
|
encodeParam.thumb_dim.src_dim = src_dim;
|
||
|
}
|
||
|
encodeParam.main_dim.dst_dim = dst_dim;
|
||
|
encodeParam.thumb_dim.dst_dim = jpeg_settings->thumbnail_size;
|
||
|
|
||
|
if (!hal_obj->useExifRotation() && needJpegExifRotation) {
|
||
|
encodeParam.rotation = jpeg_settings->jpeg_orientation;
|
||
|
encodeParam.thumb_rotation = jpeg_settings->jpeg_orientation;
|
||
|
}
|
||
|
|
||
|
LOGI("Src Buffer cnt = %d, res = %dX%d len = %d rot = %d "
|
||
|
"src_dim = %dX%d dst_dim = %dX%d",
|
||
|
encodeParam.num_src_bufs,
|
||
|
encodeParam.src_main_buf[0].offset.mp[0].stride,
|
||
|
encodeParam.src_main_buf[0].offset.mp[0].scanline,
|
||
|
encodeParam.src_main_buf[0].offset.frame_len,
|
||
|
encodeParam.rotation,
|
||
|
src_dim.width, src_dim.height,
|
||
|
dst_dim.width, dst_dim.height);
|
||
|
LOGI("Src THUMB buf_cnt = %d, res = %dX%d len = %d rot = %d "
|
||
|
"src_dim = %dX%d, dst_dim = %dX%d",
|
||
|
encodeParam.num_tmb_bufs,
|
||
|
encodeParam.src_thumb_buf[0].offset.mp[0].stride,
|
||
|
encodeParam.src_thumb_buf[0].offset.mp[0].scanline,
|
||
|
encodeParam.src_thumb_buf[0].offset.frame_len,
|
||
|
encodeParam.thumb_rotation,
|
||
|
encodeParam.thumb_dim.src_dim.width,
|
||
|
encodeParam.thumb_dim.src_dim.height,
|
||
|
encodeParam.thumb_dim.dst_dim.width,
|
||
|
encodeParam.thumb_dim.dst_dim.height);
|
||
|
ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId);
|
||
|
if (ret != NO_ERROR) {
|
||
|
LOGE("Error creating a new jpeg encoding session, ret = %d", 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 = (int32_t)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);
|
||
|
if(jpeg_settings->is_crop_valid)
|
||
|
{
|
||
|
crop = jpeg_settings->crop;
|
||
|
}else {
|
||
|
crop.left = 0;
|
||
|
crop.top = 0;
|
||
|
crop.height = src_dim.height;
|
||
|
crop.width = src_dim.width;
|
||
|
}
|
||
|
|
||
|
if (jpeg_settings->hdr_snapshot) {
|
||
|
memset(¶m, 0, sizeof(cam_stream_parm_buffer_t));
|
||
|
param.type = CAM_STREAM_PARAM_TYPE_GET_OUTPUT_CROP;
|
||
|
ret = main_stream->getParameter(param);
|
||
|
if (ret != NO_ERROR) {
|
||
|
LOGE("%s: stream getParameter for reprocess failed", __func__);
|
||
|
} else {
|
||
|
for (int i = 0; i < param.outputCrop.num_of_streams; i++) {
|
||
|
if (param.outputCrop.crop_info[i].stream_id
|
||
|
== main_stream->getMyServerID()) {
|
||
|
crop = param.outputCrop.crop_info[i].crop;
|
||
|
main_stream->setCropInfo(crop);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (jpeg_settings->multiframe_snapshot) {
|
||
|
memset(¶m, 0, sizeof(cam_stream_parm_buffer_t));
|
||
|
param.type = CAM_STREAM_PARAM_TYPE_GET_IMG_PROP;
|
||
|
ret = main_stream->getParameter(param);
|
||
|
if (ret != NO_ERROR) {
|
||
|
LOGE(" stream getParameter for reprocess failed");
|
||
|
} else {
|
||
|
main_stream->setCropInfo(param.imgProp.crop);
|
||
|
crop = param.imgProp.crop;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set main dim job parameters and handle rotation
|
||
|
if (!needJpegExifRotation && (jpeg_settings->jpeg_orientation == 90 ||
|
||
|
jpeg_settings->jpeg_orientation == 270)) {
|
||
|
|
||
|
jpg_job.encode_job.main_dim.src_dim.width = src_dim.height;
|
||
|
jpg_job.encode_job.main_dim.src_dim.height = src_dim.width;
|
||
|
|
||
|
jpg_job.encode_job.main_dim.dst_dim.width = dst_dim.height;
|
||
|
jpg_job.encode_job.main_dim.dst_dim.height = dst_dim.width;
|
||
|
|
||
|
jpg_job.encode_job.main_dim.crop.width = crop.height;
|
||
|
jpg_job.encode_job.main_dim.crop.height = crop.width;
|
||
|
jpg_job.encode_job.main_dim.crop.left = crop.top;
|
||
|
jpg_job.encode_job.main_dim.crop.top = crop.left;
|
||
|
} else {
|
||
|
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 3a sw version info
|
||
|
cam_q3a_version_t sw_version;
|
||
|
memset(&sw_version, 0, sizeof(sw_version));
|
||
|
|
||
|
if (hal_obj)
|
||
|
hal_obj->get3AVersion(sw_version);
|
||
|
|
||
|
if(jpeg_job_data->src_reproc_frame != NULL)
|
||
|
{
|
||
|
if((m_parent->getMyHandle() == jpeg_job_data->src_reproc_frame->ch_id)
|
||
|
&& (jpeg_job_data->src_reproc_frame->num_bufs != 0))
|
||
|
{
|
||
|
mm_camera_buf_def_t *buf = jpeg_job_data->src_reproc_frame->bufs[0];
|
||
|
if(buf->mem_info && (buf->stream_type == CAM_STREAM_TYPE_SNAPSHOT))
|
||
|
{
|
||
|
QCamera3StreamMem *memObj =
|
||
|
(QCamera3StreamMem *)buf->mem_info;
|
||
|
int bufidx = buf->buf_idx;
|
||
|
jpg_job.encode_job.work_buf.buf_size = memObj->getSize(bufidx);
|
||
|
jpg_job.encode_job.work_buf.buf_vaddr = (uint8_t *)memObj->getPtr(bufidx);
|
||
|
jpg_job.encode_job.work_buf.fd = memObj->getFd(bufidx);
|
||
|
memObj->invalidateCache(bufidx);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get exif data
|
||
|
QCamera3Exif *pJpegExifObj = getExifData(metadata, jpeg_settings,
|
||
|
(needJpegExifRotation && hal_obj->useExifRotation()));
|
||
|
jpeg_job_data->pJpegExifObj = pJpegExifObj;
|
||
|
if (pJpegExifObj != NULL) {
|
||
|
jpg_job.encode_job.exif_info.exif_data = pJpegExifObj->getEntries();
|
||
|
jpg_job.encode_job.exif_info.numOfEntries =
|
||
|
pJpegExifObj->getNumOfEntries();
|
||
|
jpg_job.encode_job.exif_info.debug_data.sw_3a_version[0] =
|
||
|
sw_version.major_version;
|
||
|
jpg_job.encode_job.exif_info.debug_data.sw_3a_version[1] =
|
||
|
sw_version.minor_version;
|
||
|
jpg_job.encode_job.exif_info.debug_data.sw_3a_version[2] =
|
||
|
sw_version.patch_version;
|
||
|
jpg_job.encode_job.exif_info.debug_data.sw_3a_version[3] =
|
||
|
sw_version.new_feature_des;
|
||
|
}
|
||
|
|
||
|
if (!hal_obj->useExifRotation() && needJpegExifRotation) {
|
||
|
jpg_job.encode_job.rotation= jpeg_settings->jpeg_orientation;
|
||
|
}
|
||
|
|
||
|
// thumbnail dim
|
||
|
LOGH("Thumbnail needed:%d", m_bThumbnailNeeded);
|
||
|
if (m_bThumbnailNeeded == TRUE) {
|
||
|
jpg_job.encode_job.thumb_dim.dst_dim =
|
||
|
jpeg_settings->thumbnail_size;
|
||
|
|
||
|
if (!needJpegExifRotation &&
|
||
|
(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.width = src_dim.height;
|
||
|
jpg_job.encode_job.thumb_dim.src_dim.height = src_dim.width;
|
||
|
|
||
|
jpg_job.encode_job.thumb_dim.crop.width = crop.height;
|
||
|
jpg_job.encode_job.thumb_dim.crop.height = crop.width;
|
||
|
jpg_job.encode_job.thumb_dim.crop.left = crop.top;
|
||
|
jpg_job.encode_job.thumb_dim.crop.top = crop.left;
|
||
|
} else {
|
||
|
jpg_job.encode_job.thumb_dim.src_dim = src_dim;
|
||
|
jpg_job.encode_job.thumb_dim.crop = crop;
|
||
|
}
|
||
|
jpg_job.encode_job.thumb_index = main_frame->buf_idx;
|
||
|
LOGI("Thumbnail idx = %d src w/h (%dx%d), dst w/h (%dx%d)",
|
||
|
jpg_job.encode_job.thumb_index,
|
||
|
jpg_job.encode_job.thumb_dim.src_dim.width,
|
||
|
jpg_job.encode_job.thumb_dim.src_dim.height,
|
||
|
jpg_job.encode_job.thumb_dim.dst_dim.width,
|
||
|
jpg_job.encode_job.thumb_dim.dst_dim.height);
|
||
|
}
|
||
|
LOGI("Main image idx = %d src w/h (%dx%d), dst w/h (%dx%d) rot = %d"
|
||
|
"crop t/lt (%dx%d) wxh (%dx%d)",
|
||
|
jpg_job.encode_job.src_index,
|
||
|
jpg_job.encode_job.main_dim.src_dim.width,
|
||
|
jpg_job.encode_job.main_dim.src_dim.height,
|
||
|
jpg_job.encode_job.main_dim.dst_dim.width,
|
||
|
jpg_job.encode_job.main_dim.dst_dim.height,
|
||
|
jpg_job.encode_job.rotation,
|
||
|
jpg_job.encode_job.main_dim.crop.top,
|
||
|
jpg_job.encode_job.main_dim.crop.left,
|
||
|
jpg_job.encode_job.main_dim.crop.width,
|
||
|
jpg_job.encode_job.main_dim.crop.height);
|
||
|
|
||
|
jpg_job.encode_job.cam_exif_params = hal_obj->get3AExifParams();
|
||
|
exif_debug_params = jpg_job.encode_job.cam_exif_params.debug_params;
|
||
|
|
||
|
// Allocate for a local copy of debug parameters
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params =
|
||
|
(mm_jpeg_debug_exif_params_t *) malloc (sizeof(mm_jpeg_debug_exif_params_t));
|
||
|
if (!jpg_job.encode_job.cam_exif_params.debug_params) {
|
||
|
LOGE("Out of Memory. Allocation failed for 3A debug exif params");
|
||
|
return NO_MEMORY;
|
||
|
}
|
||
|
|
||
|
jpg_job.encode_job.mobicat_mask = hal_obj->getMobicatMask();
|
||
|
|
||
|
if (metadata != NULL) {
|
||
|
//Fill in the metadata passed as parameter
|
||
|
jpg_job.encode_job.p_metadata = metadata;
|
||
|
|
||
|
jpg_job.encode_job.p_metadata->is_mobicat_aec_params_valid =
|
||
|
jpg_job.encode_job.cam_exif_params.cam_3a_params_valid;
|
||
|
|
||
|
if (jpg_job.encode_job.cam_exif_params.cam_3a_params_valid) {
|
||
|
jpg_job.encode_job.p_metadata->mobicat_aec_params =
|
||
|
jpg_job.encode_job.cam_exif_params.cam_3a_params;
|
||
|
}
|
||
|
|
||
|
if (exif_debug_params) {
|
||
|
// Copy debug parameters locally.
|
||
|
memcpy(jpg_job.encode_job.cam_exif_params.debug_params,
|
||
|
exif_debug_params, (sizeof(mm_jpeg_debug_exif_params_t)));
|
||
|
/* Save a copy of 3A debug params */
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_ae_params_valid =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->ae_debug_params_valid;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_awb_params_valid =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->awb_debug_params_valid;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_af_params_valid =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->af_debug_params_valid;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_asd_params_valid =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->asd_debug_params_valid;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_stats_params_valid =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->stats_debug_params_valid;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_bestats_params_valid =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->bestats_debug_params_valid;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_bhist_params_valid =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->bhist_debug_params_valid;
|
||
|
jpg_job.encode_job.p_metadata->is_statsdebug_3a_tuning_params_valid =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->q3a_tuning_debug_params_valid;
|
||
|
|
||
|
if (jpg_job.encode_job.cam_exif_params.debug_params->ae_debug_params_valid) {
|
||
|
jpg_job.encode_job.p_metadata->statsdebug_ae_data =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->ae_debug_params;
|
||
|
}
|
||
|
if (jpg_job.encode_job.cam_exif_params.debug_params->awb_debug_params_valid) {
|
||
|
jpg_job.encode_job.p_metadata->statsdebug_awb_data =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->awb_debug_params;
|
||
|
}
|
||
|
if (jpg_job.encode_job.cam_exif_params.debug_params->af_debug_params_valid) {
|
||
|
jpg_job.encode_job.p_metadata->statsdebug_af_data =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->af_debug_params;
|
||
|
}
|
||
|
if (jpg_job.encode_job.cam_exif_params.debug_params->asd_debug_params_valid) {
|
||
|
jpg_job.encode_job.p_metadata->statsdebug_asd_data =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->asd_debug_params;
|
||
|
}
|
||
|
if (jpg_job.encode_job.cam_exif_params.debug_params->stats_debug_params_valid) {
|
||
|
jpg_job.encode_job.p_metadata->statsdebug_stats_buffer_data =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->stats_debug_params;
|
||
|
}
|
||
|
if (jpg_job.encode_job.cam_exif_params.debug_params->bestats_debug_params_valid) {
|
||
|
jpg_job.encode_job.p_metadata->statsdebug_bestats_buffer_data =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->bestats_debug_params;
|
||
|
}
|
||
|
if (jpg_job.encode_job.cam_exif_params.debug_params->bhist_debug_params_valid) {
|
||
|
jpg_job.encode_job.p_metadata->statsdebug_bhist_data =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->bhist_debug_params;
|
||
|
}
|
||
|
if (jpg_job.encode_job.cam_exif_params.debug_params->q3a_tuning_debug_params_valid) {
|
||
|
jpg_job.encode_job.p_metadata->statsdebug_3a_tuning_data =
|
||
|
jpg_job.encode_job.cam_exif_params.debug_params->q3a_tuning_debug_params;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
LOGW("Metadata is null");
|
||
|
}
|
||
|
|
||
|
// Multi image info
|
||
|
if ((hal_obj->isDeviceLinked() == TRUE) || (jpeg_settings->encode_type == MM_JPEG_TYPE_MPO )) {
|
||
|
jpg_job.encode_job.multi_image_info.type = jpeg_settings->encode_type;
|
||
|
jpg_job.encode_job.multi_image_info.num_of_images =
|
||
|
(jpeg_settings->encode_type == MM_JPEG_TYPE_MPO)? 3 : 1;
|
||
|
jpg_job.encode_job.multi_image_info.enable_metadata = 0;
|
||
|
if (hal_obj->isMainCamera() == TRUE && (jpeg_settings->encode_type == MM_JPEG_TYPE_MPO ?
|
||
|
jpeg_settings->image_type == CAM_HAL3_JPEG_TYPE_BOKEH : false)) {
|
||
|
jpg_job.encode_job.multi_image_info.is_primary = 1;
|
||
|
} else {
|
||
|
jpg_job.encode_job.multi_image_info.is_primary = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
jpg_job.encode_job.hal_version = CAM_HAL_V3;
|
||
|
|
||
|
//Start jpeg encoding
|
||
|
ret = mJpegHandle.start_job(&jpg_job, &jobId);
|
||
|
if (jpg_job.encode_job.cam_exif_params.debug_params) {
|
||
|
free(jpg_job.encode_job.cam_exif_params.debug_params);
|
||
|
}
|
||
|
if (ret == NO_ERROR) {
|
||
|
// remember job info
|
||
|
jpeg_job_data->jobId = jobId;
|
||
|
}
|
||
|
|
||
|
LOGD("X");
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : doNextJob
|
||
|
*
|
||
|
* DESCRIPTION: send DO_NEXT_JOB command to dataProc thread.
|
||
|
*
|
||
|
* PARAMETERS : none
|
||
|
*
|
||
|
* RETURN : none
|
||
|
*==========================================================================*/
|
||
|
void QCamera3PostProcessor::doNextJob()
|
||
|
{
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : composeMpo
|
||
|
*
|
||
|
* DESCRIPTION: compress jpeg images to mpo format. Use jpeg interface handle
|
||
|
* to compose mpo image. Sends callback to pic channel (mpoevthandle)
|
||
|
* with composed mpo.
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @mpo_info : contain list of input images and output buffer.
|
||
|
* @userdata : need to pass with mpo callback.
|
||
|
*
|
||
|
* RETURN : NO_ERROR on success else -1.
|
||
|
*==========================================================================*/
|
||
|
int32_t QCamera3PostProcessor::composeMpo(qcamera_hal3_mpo_compose_info_t &mpo_info,
|
||
|
void *userdata)
|
||
|
{
|
||
|
LOGH("E");
|
||
|
if((mpo_info.num_of_aux_image + 1) > MM_JPEG_MAX_MPO_IMAGES)
|
||
|
{
|
||
|
LOGE("Error: cannot composeMpo of %d images",mpo_info.num_of_aux_image + 1);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
ssize_t output_size = 0;
|
||
|
mm_jpeg_mpo_info_t mpo_compose_info;
|
||
|
mpo_compose_info.primary_image = mpo_info.main_image; //first images will be the primary image
|
||
|
output_size += mpo_info.main_image.buf_filled_len;
|
||
|
|
||
|
for(uint32_t i = 0; i < mpo_info.num_of_aux_image; i++)
|
||
|
{
|
||
|
mpo_compose_info.aux_images[i] = mpo_info.aux_images[i];
|
||
|
output_size += mpo_info.aux_images[i].buf_filled_len;
|
||
|
}
|
||
|
mpo_compose_info.num_of_images = mpo_info.num_of_aux_image + 1 /*num of main image*/;
|
||
|
mpo_compose_info.output_buff = mpo_info.output;
|
||
|
mpo_compose_info.output_buff.buf_filled_len = 0;
|
||
|
mpo_compose_info.output_buff_size = output_size;
|
||
|
|
||
|
int rc = mMpoHandle.compose_mpo(&mpo_compose_info);
|
||
|
if(rc != 0)
|
||
|
{
|
||
|
LOGE("Error: failed to compose mpo image");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
mMpoCB( JPEG_JOB_STATUS_DONE, &mpo_compose_info.output_buff, userdata);
|
||
|
|
||
|
LOGH("X");
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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;
|
||
|
uint8_t sync = FALSE;
|
||
|
mm_camera_super_buf_t *meta_buffer = NULL;
|
||
|
LOGD("E");
|
||
|
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) {
|
||
|
LOGE("cam_sem_wait error (%s)",
|
||
|
strerror(errno));
|
||
|
return NULL;
|
||
|
}
|
||
|
} while (ret != 0);
|
||
|
|
||
|
sync = FALSE;
|
||
|
// we got notified about new cmd avail in cmd queue
|
||
|
camera_cmd_type_t cmd = cmdThread->getCmd(sync);
|
||
|
switch (cmd) {
|
||
|
case CAMERA_CMD_TYPE_START_DATA_PROC:
|
||
|
LOGH("start data proc");
|
||
|
is_active = TRUE;
|
||
|
needNewSess = TRUE;
|
||
|
|
||
|
pme->m_ongoingPPQ.init();
|
||
|
pme->m_inputJpegQ.init();
|
||
|
pme->m_inputPPQ.init();
|
||
|
pme->m_inputFWKPPQ.init();
|
||
|
pme->m_inputMultiReprocQ.init();
|
||
|
pme->m_inputMetaQ.init();
|
||
|
if(sync)
|
||
|
{
|
||
|
cam_sem_post(&cmdThread->sync_sem);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
case CAMERA_CMD_TYPE_CANCEL_PP_FRAME:
|
||
|
{
|
||
|
if(pme->m_inputPPQ.isEmpty()){
|
||
|
LOGH("pp queue is empty. Invalid cancel request.");
|
||
|
}else {
|
||
|
LOGH("PP frame request cancel");
|
||
|
qcamera_hal3_pp_buffer_t* pp_buf =
|
||
|
(qcamera_hal3_pp_buffer_t *)pme->m_inputPPQ.dequeue();
|
||
|
if (NULL != pp_buf) {
|
||
|
if (pp_buf->input) {
|
||
|
pme->releaseSuperBuf(pp_buf->input);
|
||
|
free(pp_buf->input);
|
||
|
pp_buf->input = NULL;
|
||
|
}
|
||
|
if(pme->m_pReprocChannel[0] != NULL)
|
||
|
{
|
||
|
int rc = NO_ERROR;
|
||
|
rc = pme->m_pReprocChannel[0]->releaseOutputBuffer(pp_buf->output,
|
||
|
pp_buf->frameNumber);
|
||
|
if(rc != NO_ERROR)
|
||
|
{
|
||
|
LOGE("failed to return o/p buffer.error = %d",rc);
|
||
|
}
|
||
|
}
|
||
|
free(pp_buf);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case CAMERA_CMD_TYPE_STOP_DATA_PROC:
|
||
|
{
|
||
|
LOGH("stop data proc");
|
||
|
is_active = FALSE;
|
||
|
// cancel all ongoing jpeg jobs
|
||
|
qcamera_hal3_jpeg_data_t *jpeg_job =
|
||
|
(qcamera_hal3_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_hal3_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue();
|
||
|
}
|
||
|
|
||
|
// destroy jpeg encoding session
|
||
|
if ( 0 < pme->mJpegSessionId ) {
|
||
|
pme->mJpegHandle.destroy_session(pme->mJpegSessionId);
|
||
|
pme->mJpegSessionId = 0;
|
||
|
}
|
||
|
|
||
|
pme->releaseFreeJpegSessions();
|
||
|
|
||
|
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 framework input Postproc Queue
|
||
|
pme->m_inputFWKPPQ.flush();
|
||
|
|
||
|
pme->m_inputMultiReprocQ.flush();
|
||
|
|
||
|
pme->m_inputMetaQ.flush();
|
||
|
pme->m_jpegSettingsQ.flush();
|
||
|
|
||
|
while(pme->mReprocessNode.size())
|
||
|
{
|
||
|
List<ReprocessBuffer>::iterator reprocData;
|
||
|
reprocData = pme->mReprocessNode.begin();
|
||
|
qcamera_hal3_pp_buffer_t *pp_buffer = reprocData->reprocBuf;
|
||
|
qcamera_hal3_meta_pp_buffer_t *meta_pp_buffer = reprocData->metaBuffer;
|
||
|
|
||
|
pme->mReprocessNode.erase(pme->mReprocessNode.begin());
|
||
|
// free frame
|
||
|
if (pp_buffer != NULL) {
|
||
|
if (pp_buffer->input) {
|
||
|
pme->releaseSuperBuf(pp_buffer->input);
|
||
|
free(pp_buffer->input);
|
||
|
}
|
||
|
free(pp_buffer);
|
||
|
}
|
||
|
//free metadata
|
||
|
if (NULL != meta_pp_buffer) {
|
||
|
if(NULL != meta_pp_buffer->metabuf)
|
||
|
{
|
||
|
pme->m_parent->metadataBufDone(meta_pp_buffer->metabuf);
|
||
|
free(meta_pp_buffer->metabuf);
|
||
|
}
|
||
|
free(meta_pp_buffer);
|
||
|
}
|
||
|
}
|
||
|
// signal cmd is completed
|
||
|
if(sync)
|
||
|
{
|
||
|
cam_sem_post(&cmdThread->sync_sem);
|
||
|
}
|
||
|
pthread_mutex_lock(&pme->mHDRJobLock);
|
||
|
pme->mChannelStop = true;
|
||
|
pthread_cond_signal(&pme->mProcChStopCond);
|
||
|
pthread_mutex_unlock(&pme->mHDRJobLock);
|
||
|
}
|
||
|
break;
|
||
|
case CAMERA_CMD_TYPE_DO_NEXT_JOB:
|
||
|
{
|
||
|
LOGH("Do next job, active is %d", is_active);
|
||
|
/* needNewSess is set to TRUE as postproc is not re-STARTed
|
||
|
* anymore for every captureRequest */
|
||
|
needNewSess = TRUE;
|
||
|
if (is_active == TRUE) {
|
||
|
// check if there is any ongoing jpeg jobs
|
||
|
if (pme->m_ongoingJpegQ.isEmpty()) {
|
||
|
LOGD("ongoing jpeg queue is empty so doing the jpeg job");
|
||
|
// no ongoing jpeg job, we are fine to send jpeg encoding job
|
||
|
qcamera_hal3_jpeg_data_t *jpeg_job =
|
||
|
(qcamera_hal3_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
|
||
|
|
||
|
if (NULL != jpeg_job) {
|
||
|
// add into ongoing jpeg job Q
|
||
|
pme->m_ongoingJpegQ.enqueue((void *)jpeg_job);
|
||
|
|
||
|
if (jpeg_job->fwk_frame) {
|
||
|
ret = pme->encodeFWKData(jpeg_job, needNewSess);
|
||
|
} else {
|
||
|
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);
|
||
|
}
|
||
|
pme->releaseFreeJpegSessions();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!pme->m_inputMultiReprocQ.isEmpty()) {
|
||
|
QCamera3HardwareInterface* hal_obj =
|
||
|
(QCamera3HardwareInterface *)pme->m_parent->mUserData;
|
||
|
qcamera_hal3_pp_data_t *pp_job =
|
||
|
(qcamera_hal3_pp_data_t *)pme->m_inputMultiReprocQ.dequeue();
|
||
|
if (pp_job != NULL) {
|
||
|
LOGH("multi reproc Q is not empty, pp channel idx:%d, total pp cnt:%d",
|
||
|
pp_job->pp_ch_idx, pme->m_ppChannelCnt);
|
||
|
if (pp_job->pp_ch_idx < pme->m_ppChannelCnt &&
|
||
|
pme->m_pReprocChannel[pp_job->pp_ch_idx] != NULL) {
|
||
|
LOGH("do reproc on %dth reprocess channel", pp_job->pp_ch_idx + 1);
|
||
|
|
||
|
qcamera_fwk_input_pp_data_t fwk_frame;
|
||
|
memset(&fwk_frame, 0, sizeof(qcamera_fwk_input_pp_data_t));
|
||
|
if (pp_job->fwk_src_frame != NULL) {
|
||
|
LOGD("reprocess for fwk input frame");
|
||
|
fwk_frame = *(pp_job->fwk_src_frame);
|
||
|
fwk_frame.input_buffer
|
||
|
= *(pp_job->reprocessed_src_frame->bufs[0]);
|
||
|
} else {
|
||
|
fwk_frame.frameNumber = pp_job->frameNumber;
|
||
|
fwk_frame.input_buffer
|
||
|
= *(pp_job->reprocessed_src_frame->bufs[0]);
|
||
|
fwk_frame.metadata_buffer = *(pp_job->src_metadata->bufs[0]);
|
||
|
|
||
|
uint32_t stream_id = hal_obj->mQCFACaptureChannel->getStreamSvrId();
|
||
|
LOGD("src stream server id:%d", stream_id);
|
||
|
ret = pme->m_pReprocChannel[pp_job->pp_ch_idx]->overrideMetadata(
|
||
|
(metadata_buffer_t *)fwk_frame.metadata_buffer.buffer,
|
||
|
pp_job->jpeg_settings, stream_id);
|
||
|
if (ret != NO_ERROR) {
|
||
|
LOGE("fail to override metadata.");
|
||
|
}
|
||
|
}
|
||
|
LOGD("frame number: %d", fwk_frame.frameNumber);
|
||
|
pme->m_ongoingPPQ.enqueue((void *)pp_job);
|
||
|
ret = pme->m_pReprocChannel[pp_job->pp_ch_idx]->doReprocessOffline(
|
||
|
&fwk_frame, true);
|
||
|
if (ret != NO_ERROR) {
|
||
|
pme->m_ongoingPPQ.dequeue(false);
|
||
|
LOGE("fail to do offline reprocess");
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
LOGE("fail to dequeue pp job!");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// check if there are any framework pp jobs
|
||
|
if (!pme->m_inputFWKPPQ.isEmpty()) {
|
||
|
qcamera_fwk_input_pp_data_t *fwk_frame =
|
||
|
(qcamera_fwk_input_pp_data_t *) pme->m_inputFWKPPQ.dequeue();
|
||
|
if (NULL != fwk_frame) {
|
||
|
qcamera_hal3_pp_data_t *pp_job =
|
||
|
(qcamera_hal3_pp_data_t *)malloc(sizeof(qcamera_hal3_pp_data_t));
|
||
|
jpeg_settings_t *jpeg_settings =
|
||
|
(jpeg_settings_t *)pme->m_jpegSettingsQ.dequeue();
|
||
|
if (pp_job != NULL) {
|
||
|
memset(pp_job, 0, sizeof(qcamera_hal3_pp_data_t));
|
||
|
pp_job->jpeg_settings = jpeg_settings;
|
||
|
if (pme->m_pReprocChannel[0] != NULL) {
|
||
|
if (NO_ERROR !=
|
||
|
pme->m_pReprocChannel[0]->overrideFwkMetadata(fwk_frame)) {
|
||
|
LOGE("Failed to extract output crop");
|
||
|
}
|
||
|
// add into ongoing PP job Q
|
||
|
pp_job->fwk_src_frame = fwk_frame;
|
||
|
pp_job->pp_ch_idx = 0;
|
||
|
pp_job->frameNumber = fwk_frame->frameNumber;
|
||
|
pme->m_ongoingPPQ.enqueue((void *)pp_job);
|
||
|
ret = pme->m_pReprocChannel[0]->doReprocessOffline(fwk_frame);
|
||
|
if (NO_ERROR != ret) {
|
||
|
// remove from ongoing PP job Q
|
||
|
pme->m_ongoingPPQ.dequeue(false);
|
||
|
}
|
||
|
} else {
|
||
|
LOGE("Reprocess channel is NULL");
|
||
|
ret = -1;
|
||
|
}
|
||
|
} else {
|
||
|
LOGE("no mem for qcamera_hal3_pp_data_t");
|
||
|
ret = -1;
|
||
|
}
|
||
|
|
||
|
if (0 != ret) {
|
||
|
// free pp_job
|
||
|
if (pp_job != NULL) {
|
||
|
free(pp_job);
|
||
|
}
|
||
|
// free frame
|
||
|
if (fwk_frame != NULL) {
|
||
|
free(fwk_frame);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LOGH("dequeuing pp frame");
|
||
|
pthread_mutex_lock(&pme->mReprocJobLock);
|
||
|
if(pme->mReprocessNode.size()) {
|
||
|
List<ReprocessBuffer>::iterator reprocData;
|
||
|
reprocData = pme->mReprocessNode.begin();
|
||
|
qcamera_hal3_pp_buffer_t *pp_buffer = reprocData->reprocBuf;
|
||
|
qcamera_hal3_meta_pp_buffer_t *meta_pp_buffer = reprocData->metaBuffer;
|
||
|
pme->mReprocessNode.erase(pme->mReprocessNode.begin());
|
||
|
LOGD(" Reprocess Buffer Frame Number :%d and %d",
|
||
|
pp_buffer->frameNumber, meta_pp_buffer->metaFrameNumber);
|
||
|
meta_buffer =
|
||
|
(mm_camera_super_buf_t *)meta_pp_buffer->metabuf;
|
||
|
jpeg_settings_t *jpeg_settings =
|
||
|
(jpeg_settings_t *)pme->m_jpegSettingsQ.dequeue();
|
||
|
jpeg_settings_t *ppOutput_jpeg_settings = NULL;
|
||
|
|
||
|
//In bokeh case, there will be no AUX image jpeg settings.
|
||
|
//DEPTH image jpeg_settings need to assign to ppOutPut_jpeg_settings.
|
||
|
//BOKEH image jpeg_settings need to assign to ppOutPut_jpeg_settings.
|
||
|
QCamera3HardwareInterface* hal_obj =
|
||
|
(QCamera3HardwareInterface*)pme->m_parent->mUserData;
|
||
|
if(hal_obj->isDualCamera() && jpeg_settings != NULL)
|
||
|
{
|
||
|
if(jpeg_settings->image_type != CAM_HAL3_JPEG_TYPE_MAIN)
|
||
|
{
|
||
|
ppOutput_jpeg_settings = jpeg_settings;
|
||
|
jpeg_settings = (jpeg_settings_t *)pme->m_jpegSettingsQ.dequeue();
|
||
|
} else {
|
||
|
QCamera3HardwareInterface *hal_obj =
|
||
|
(QCamera3HardwareInterface *)pme->m_parent->mUserData;
|
||
|
if(hal_obj->getHalPPType() == CAM_HAL_PP_TYPE_BOKEH)
|
||
|
{
|
||
|
ppOutput_jpeg_settings = (jpeg_settings_t *)
|
||
|
pme->m_jpegSettingsQ.dequeue();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pthread_mutex_unlock(&pme->mReprocJobLock);
|
||
|
qcamera_hal3_pp_data_t *pp_job =
|
||
|
(qcamera_hal3_pp_data_t *)malloc(sizeof(qcamera_hal3_pp_data_t));
|
||
|
if (pp_job == NULL) {
|
||
|
LOGE("no mem for qcamera_hal3_pp_data_t");
|
||
|
ret = -1;
|
||
|
} else if (meta_buffer == NULL) {
|
||
|
LOGE("failed to dequeue from m_inputMetaQ");
|
||
|
ret = -1;
|
||
|
} else if (pp_buffer == NULL) {
|
||
|
LOGE("failed to dequeue from m_inputPPQ");
|
||
|
ret = -1;
|
||
|
} else if (pp_buffer != NULL){
|
||
|
memset(pp_job, 0, sizeof(qcamera_hal3_pp_data_t));
|
||
|
pp_job->src_frame = pp_buffer->input;
|
||
|
pp_job->src_metadata = meta_buffer;
|
||
|
if (meta_buffer->bufs[0] != NULL) {
|
||
|
pp_job->metadata = (metadata_buffer_t *)
|
||
|
meta_buffer->bufs[0]->buffer;
|
||
|
}
|
||
|
pp_job->jpeg_settings = jpeg_settings;
|
||
|
pp_job->ppOutput_jpeg_settings = ppOutput_jpeg_settings;
|
||
|
|
||
|
pp_job->pp_ch_idx = 0;
|
||
|
pp_job->frameNumber = pp_buffer->frameNumber;
|
||
|
pme->m_ongoingPPQ.enqueue((void *)pp_job);
|
||
|
if (pme->m_pReprocChannel[0] != NULL) {
|
||
|
mm_camera_buf_def_t *meta_buffer_arg = NULL;
|
||
|
meta_buffer_arg = meta_buffer->bufs[0];
|
||
|
qcamera_fwk_input_pp_data_t fwk_frame;
|
||
|
memset(&fwk_frame, 0, sizeof(qcamera_fwk_input_pp_data_t));
|
||
|
fwk_frame.frameNumber = pp_buffer->frameNumber;
|
||
|
if (pme->m_ppChannelCnt > 1) {
|
||
|
LOGD("multi pass reprocess, no need override meta here.");
|
||
|
fwk_frame.input_buffer = *(pp_buffer->input->bufs[0]);
|
||
|
fwk_frame.metadata_buffer = *(meta_buffer->bufs[0]);
|
||
|
fwk_frame.output_buffer = pp_buffer->output;
|
||
|
} else {
|
||
|
if(pp_job->jpeg_settings != NULL)
|
||
|
{
|
||
|
if(hal_obj->m_bInSensorQCFA &&
|
||
|
(hal_obj->mQCFACaptureChannel != NULL)) {
|
||
|
uint32_t stream_id =
|
||
|
hal_obj->mQCFACaptureChannel->getStreamSvrId();
|
||
|
fwk_frame.input_buffer = *(pp_buffer->input->bufs[0]);
|
||
|
fwk_frame.metadata_buffer = *(meta_buffer->bufs[0]);
|
||
|
fwk_frame.output_buffer = pp_buffer->output;
|
||
|
LOGD("src stream server id:%d", stream_id);
|
||
|
ret = pme->m_pReprocChannel[0]->overrideMetadata(
|
||
|
(metadata_buffer_t *)meta_buffer_arg->buffer,
|
||
|
pp_job->jpeg_settings, stream_id);
|
||
|
} else {
|
||
|
ret = pme->m_pReprocChannel[0]->overrideMetadata(
|
||
|
pp_buffer, meta_buffer_arg,
|
||
|
pp_job->jpeg_settings,
|
||
|
fwk_frame);
|
||
|
}
|
||
|
} else {
|
||
|
ret = pme->m_pReprocChannel[0]->overrideMetadata(
|
||
|
pp_buffer, meta_buffer_arg,
|
||
|
pp_job->ppOutput_jpeg_settings,
|
||
|
fwk_frame);
|
||
|
}
|
||
|
}
|
||
|
if (NO_ERROR == ret) {
|
||
|
// add into ongoing PP job Q
|
||
|
pme->mPerfLockMgr.acquirePerfLock(PERF_LOCK_OFFLINE_REPROC);
|
||
|
ret = pme->m_pReprocChannel[0]->doReprocessOffline(
|
||
|
&fwk_frame, true);
|
||
|
pme->mPerfLockMgr.releasePerfLock(PERF_LOCK_OFFLINE_REPROC);
|
||
|
if (NO_ERROR != ret) {
|
||
|
// remove from ongoing PP job Q
|
||
|
pme->m_ongoingPPQ.dequeue(false);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
LOGE("No reprocess. Calling processPPData directly");
|
||
|
ret = pme->processPPData(pp_buffer->input);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (0 != ret) {
|
||
|
// free pp_job
|
||
|
if (pp_job != NULL) {
|
||
|
free(pp_job);
|
||
|
}
|
||
|
// free frame
|
||
|
if (pp_buffer != NULL) {
|
||
|
if (pp_buffer->input) {
|
||
|
pme->releaseSuperBuf(pp_buffer->input);
|
||
|
free(pp_buffer->input);
|
||
|
}
|
||
|
free(pp_buffer);
|
||
|
}
|
||
|
//free metadata
|
||
|
if (NULL != meta_buffer) {
|
||
|
pme->m_parent->metadataBufDone(meta_buffer);
|
||
|
free(meta_buffer);
|
||
|
}
|
||
|
} else {
|
||
|
if (pp_buffer != NULL) {
|
||
|
free(pp_buffer);
|
||
|
}
|
||
|
}
|
||
|
if (NULL != meta_pp_buffer) {
|
||
|
free(meta_pp_buffer);
|
||
|
meta_pp_buffer = NULL;
|
||
|
}
|
||
|
} else {
|
||
|
pthread_mutex_unlock(&pme->mReprocJobLock);
|
||
|
}
|
||
|
} else {
|
||
|
// not active, simply return buf and do no op
|
||
|
qcamera_hal3_jpeg_data_t *jpeg_job =
|
||
|
(qcamera_hal3_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
|
||
|
if (NULL != jpeg_job) {
|
||
|
free(jpeg_job);
|
||
|
}
|
||
|
|
||
|
qcamera_hal3_pp_buffer_t* pp_buf =
|
||
|
(qcamera_hal3_pp_buffer_t *)pme->m_inputPPQ.dequeue();
|
||
|
if (NULL != pp_buf) {
|
||
|
if (pp_buf->input) {
|
||
|
pme->releaseSuperBuf(pp_buf->input);
|
||
|
free(pp_buf->input);
|
||
|
pp_buf->input = NULL;
|
||
|
}
|
||
|
free(pp_buf);
|
||
|
}
|
||
|
mm_camera_super_buf_t *metadata = (mm_camera_super_buf_t *)
|
||
|
pme->m_inputMetaQ.dequeue();
|
||
|
if (metadata != NULL) {
|
||
|
pme->m_parent->metadataBufDone(metadata);
|
||
|
free(metadata);
|
||
|
}
|
||
|
qcamera_fwk_input_pp_data_t *fwk_frame =
|
||
|
(qcamera_fwk_input_pp_data_t *) pme->m_inputFWKPPQ.dequeue();
|
||
|
if (NULL != fwk_frame) {
|
||
|
free(fwk_frame);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case CAMERA_CMD_TYPE_INIT_JPEG:{
|
||
|
if(pme->mJpegClientHandle <= 0)
|
||
|
{
|
||
|
pme->mJpegClientHandle = jpeg_open(&pme->mJpegHandle, &pme->mMpoHandle,
|
||
|
pme->max_pic_size, &pme->mJpegMetadata);
|
||
|
if (!pme->mJpegClientHandle) {
|
||
|
LOGE("jpeg_open did not work");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case CAMERA_CMD_TYPE_EXIT:
|
||
|
running = 0;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
} while (running);
|
||
|
LOGD("X");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : processHalPPDataCB
|
||
|
*
|
||
|
* DESCRIPTION: callback function to process frame after HAL PP block
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @pOutput : output after HAL PP processed
|
||
|
* @pUserData : user data ptr (QCameraReprocessor)
|
||
|
*
|
||
|
* RETURN : None
|
||
|
*==========================================================================*/
|
||
|
void QCamera3PostProcessor::processHalPPDataCB(qcamera_hal_pp_data_t *pOutput, void* pUserData)
|
||
|
{
|
||
|
QCamera3PostProcessor *pme = (QCamera3PostProcessor *)pUserData;
|
||
|
pme->processHalPPData(pOutput);
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : processHalPPData
|
||
|
*
|
||
|
* DESCRIPTION: process received frame after HAL PP block.
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @pData : received qcamera_hal_pp_data_t data from HAL PP callback.
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*
|
||
|
* NOTE : The frame after HAL PP need to send to jpeg encoding.
|
||
|
*==========================================================================*/
|
||
|
int32_t QCamera3PostProcessor::processHalPPData(qcamera_hal_pp_data_t *pData)
|
||
|
{
|
||
|
int32_t rc = NO_ERROR;
|
||
|
LOGH("E");
|
||
|
|
||
|
if (pData == NULL) {
|
||
|
LOGE("HAL PP processed data is NULL");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
mm_camera_super_buf_t *frame = pData->frame;
|
||
|
if (frame == NULL) {
|
||
|
LOGE("HAL PP processed frame is NULL");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
// send to JPEG encoding
|
||
|
qcamera_hal3_jpeg_data_t *jpeg_job =
|
||
|
(qcamera_hal3_jpeg_data_t *)malloc(sizeof(qcamera_hal3_jpeg_data_t));
|
||
|
if (jpeg_job == NULL) {
|
||
|
LOGE("No memory for jpeg job");
|
||
|
return NO_MEMORY;
|
||
|
}
|
||
|
|
||
|
memset(jpeg_job, 0, sizeof(qcamera_hal3_jpeg_data_t));
|
||
|
jpeg_job->src_frame = frame;
|
||
|
jpeg_job->src_reproc_frame = pData->src_reproc_frame;
|
||
|
//for bokeh and Depth bufs[1] will be NULL.
|
||
|
if(pData->metadata != NULL)
|
||
|
{
|
||
|
jpeg_job->metadata = pData->metadata;
|
||
|
}
|
||
|
else {
|
||
|
jpeg_job->metadata = (metadata_buffer_t*) pData->bufs[1].buffer;
|
||
|
}
|
||
|
jpeg_job->src_metadata = pData->src_metadata;
|
||
|
jpeg_job->jpeg_settings = pData->jpeg_settings;
|
||
|
|
||
|
jpeg_job->halPPAllocatedBuf = pData->halPPAllocatedBuf;
|
||
|
jpeg_job->hal_pp_bufs = pData->bufs;
|
||
|
jpeg_job->snapshot_heap = pData->snapshot_heap;
|
||
|
jpeg_job->metadata_heap = pData->metadata_heap;
|
||
|
|
||
|
LOGD("halPPAllocatedBuf = %d needEncode %d", pData->halPPAllocatedBuf, pData->needEncode);
|
||
|
|
||
|
if ((!pData->halPPAllocatedBuf && !pData->needEncode)
|
||
|
|| ((jpeg_job->jpeg_settings == NULL)
|
||
|
|| (jpeg_job->jpeg_settings->image_type == CAM_HAL3_JPEG_TYPE_AUX))) {
|
||
|
LOGH("No need to encode input buffer, just release it.");
|
||
|
if(jpeg_job->src_reproc_frame)
|
||
|
{
|
||
|
QCamera3PicChannel *pChannel = (QCamera3PicChannel *)m_parent;
|
||
|
pChannel->releaseSnapshotBuffer(jpeg_job->src_reproc_frame);
|
||
|
}
|
||
|
releaseJpegJobData(jpeg_job);
|
||
|
free(jpeg_job);
|
||
|
jpeg_job = NULL;
|
||
|
free(pData);
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
if (pData->is_dim_valid) {
|
||
|
jpeg_job->jpeg_settings->is_dim_valid = true;
|
||
|
jpeg_job->jpeg_settings->output_dim = pData->outputDim;
|
||
|
}
|
||
|
|
||
|
if (pData->is_offset_valid) {
|
||
|
jpeg_job->jpeg_settings->is_offset_valid = true;
|
||
|
jpeg_job->jpeg_settings->offset = pData->snap_offset;
|
||
|
}
|
||
|
|
||
|
if (pData->is_format_valid) {
|
||
|
jpeg_job->jpeg_settings->is_format_valid = true;
|
||
|
jpeg_job->jpeg_settings->format = pData->outputFormat;
|
||
|
}
|
||
|
|
||
|
if (pData->is_crop_valid) {
|
||
|
jpeg_job->jpeg_settings->is_crop_valid = true;
|
||
|
jpeg_job->jpeg_settings->crop = pData->outputCrop;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Enqueue frame to jpeg input queue
|
||
|
if (false == m_inputJpegQ.enqueue((void *)jpeg_job)) {
|
||
|
LOGW("Input Jpeg Q is not active!!!");
|
||
|
releaseJpegJobData(jpeg_job);
|
||
|
free(jpeg_job);
|
||
|
jpeg_job = NULL;
|
||
|
}
|
||
|
|
||
|
// wake up data proc thread
|
||
|
LOGH("Send frame for jpeg encoding");
|
||
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
|
||
|
|
||
|
free(pData);
|
||
|
LOGH("X");
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
void QCamera3PostProcessor::createHalPPManager()
|
||
|
{
|
||
|
LOGH("E");
|
||
|
if (m_pHalPPManager == NULL) {
|
||
|
m_pHalPPManager = QCameraHALPPManager::getInstance();
|
||
|
LOGH("Created HAL PP manager");
|
||
|
}
|
||
|
LOGH("X");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : initHalPPManager
|
||
|
*
|
||
|
* DESCRIPTION: function to create and init HALPP manager
|
||
|
* RETURN : None
|
||
|
*==========================================================================*/
|
||
|
int32_t QCamera3PostProcessor::initHalPPManager()
|
||
|
{
|
||
|
int32_t rc = NO_ERROR;
|
||
|
|
||
|
if (m_pHalPPManager == NULL) {
|
||
|
LOGE("failed as PP manager is NULL");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
|
||
|
QCamera3HardwareInterface* hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
|
||
|
|
||
|
void *staticParam = hal_obj->getCamHalCapabilities();;
|
||
|
cam_hal_pp_type_t halPPType = hal_obj->getHalPPType();
|
||
|
LOGH("E halPPType:%d mPProcType: %d", halPPType, m_pHalPPManager->getPprocType());
|
||
|
if (m_pHalPPManager->getPprocType() != halPPType) {
|
||
|
//HAL PP block might change, deinit and re init
|
||
|
rc = m_pHalPPManager->deinit();
|
||
|
if (rc != NO_ERROR) {
|
||
|
LOGE("HAL PP type %d init failed, rc = %d", halPPType, rc);
|
||
|
return rc;
|
||
|
}
|
||
|
rc = m_pHalPPManager->init(halPPType, QCamera3PostProcessor::processHalPPDataCB,
|
||
|
QCamera3PostProcessor::releaseSuperBufCb, staticParam);
|
||
|
if (rc != NO_ERROR) {
|
||
|
LOGE("HAL PP type %d init failed, rc = %d", halPPType, rc);
|
||
|
}
|
||
|
}
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
void QCamera3PostProcessor::releaseSuperBufCb(mm_camera_super_buf_t *super_buf, void* pUserData)
|
||
|
{
|
||
|
QCamera3PostProcessor *pme = (QCamera3PostProcessor *)pUserData;
|
||
|
pme->releaseSuperBuf(super_buf);
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getChannelByHandle
|
||
|
*
|
||
|
* DESCRIPTION: function to get channel by handle
|
||
|
* PARAMETERS :
|
||
|
* @channelHandle : channel handle
|
||
|
* RETURN : QCameraChannel
|
||
|
*==========================================================================*/
|
||
|
QCamera3Channel *QCamera3PostProcessor::getChannelByHandle(uint32_t channelHandle)
|
||
|
{
|
||
|
QCamera3Channel *pChannel = NULL;
|
||
|
|
||
|
if (m_parent->getMyHandle() == channelHandle) {
|
||
|
pChannel = m_parent;
|
||
|
}
|
||
|
// check reprocess channel if not found
|
||
|
if (pChannel == NULL) {
|
||
|
for (int8_t i = 0; i < m_ppChannelCnt; i++) {
|
||
|
if (m_pReprocChannel[i] != NULL &&
|
||
|
m_pReprocChannel[i]->getMyHandle() == channelHandle) {
|
||
|
pChannel = m_pReprocChannel[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return pChannel;
|
||
|
}
|
||
|
|
||
|
/* EXIF related helper methods */
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getRational
|
||
|
*
|
||
|
* DESCRIPTION: compose rational struct
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @rat : ptr to struct to store rational info
|
||
|
* @num :num of the rational
|
||
|
* @denom : denom of the rational
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t getRational(rat_t *rat, int num, int denom)
|
||
|
{
|
||
|
if ((0 > num) || (0 >= denom)) {
|
||
|
LOGE("Negative values");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
if (NULL == rat) {
|
||
|
LOGE("NULL rat input");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
rat->num = (uint32_t)num;
|
||
|
rat->denom = (uint32_t)denom;
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : parseGPSCoordinate
|
||
|
*
|
||
|
* DESCRIPTION: parse GPS coordinate string
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @coord_str : [input] coordinate string
|
||
|
* @coord : [output] ptr to struct to store coordinate
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int parseGPSCoordinate(const char *coord_str, rat_t* coord)
|
||
|
{
|
||
|
if(coord == NULL) {
|
||
|
LOGE("error, invalid argument coord == NULL");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
double degF = atof(coord_str);
|
||
|
if (degF < 0) {
|
||
|
degF = -degF;
|
||
|
}
|
||
|
double minF = (degF - (int) degF) * 60;
|
||
|
double secF = (minF - (int) minF) * 60;
|
||
|
|
||
|
getRational(&coord[0], (int)degF, 1);
|
||
|
getRational(&coord[1], (int)minF, 1);
|
||
|
getRational(&coord[2], (int)(secF * 10000), 10000);
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getExifDateTime
|
||
|
*
|
||
|
* DESCRIPTION: query exif date time
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @dateTime : string to store exif date time
|
||
|
* @subsecTime : string to store exif subsec time
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t getExifDateTime(String8 &dateTime, String8 &subsecTime)
|
||
|
{
|
||
|
int32_t ret = NO_ERROR;
|
||
|
|
||
|
//get time and date from system
|
||
|
struct timeval tv;
|
||
|
struct tm timeinfo_data;
|
||
|
|
||
|
int res = gettimeofday(&tv, NULL);
|
||
|
if (0 == res) {
|
||
|
struct tm *timeinfo = localtime_r(&tv.tv_sec, &timeinfo_data);
|
||
|
if (NULL != timeinfo) {
|
||
|
//Write datetime according to EXIF Spec
|
||
|
//"YYYY:MM:DD HH:MM:SS" (20 chars including \0)
|
||
|
dateTime = String8::format("%04d:%02d:%02d %02d:%02d:%02d",
|
||
|
timeinfo->tm_year + 1900, timeinfo->tm_mon + 1,
|
||
|
timeinfo->tm_mday, timeinfo->tm_hour,
|
||
|
timeinfo->tm_min, timeinfo->tm_sec);
|
||
|
//Write subsec according to EXIF Sepc
|
||
|
subsecTime = String8::format("%06ld", tv.tv_usec);
|
||
|
} else {
|
||
|
LOGE("localtime_r() error");
|
||
|
ret = UNKNOWN_ERROR;
|
||
|
}
|
||
|
} else if (-1 == res) {
|
||
|
LOGE("gettimeofday() error: %s", strerror(errno));
|
||
|
ret = UNKNOWN_ERROR;
|
||
|
} else {
|
||
|
LOGE("gettimeofday() unexpected return code: %d", res);
|
||
|
ret = UNKNOWN_ERROR;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getExifFocalLength
|
||
|
*
|
||
|
* DESCRIPTION: get exif focal length
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @focalLength : ptr to rational struct to store focal length
|
||
|
* @value : focal length value
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t getExifFocalLength(rat_t *focalLength, float value)
|
||
|
{
|
||
|
int focalLengthValue =
|
||
|
(int)(value * FOCAL_LENGTH_DECIMAL_PRECISION);
|
||
|
return getRational(focalLength, focalLengthValue, FOCAL_LENGTH_DECIMAL_PRECISION);
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getExifExpTimeInfo
|
||
|
*
|
||
|
* DESCRIPTION: get exif exposure time information
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @expoTimeInfo : rational exposure time value
|
||
|
* @value : exposure time value
|
||
|
* RETURN : nt32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t getExifExpTimeInfo(rat_t *expoTimeInfo, int64_t value)
|
||
|
{
|
||
|
|
||
|
int64_t cal_exposureTime;
|
||
|
if (value != 0)
|
||
|
cal_exposureTime = value;
|
||
|
else
|
||
|
cal_exposureTime = 60;
|
||
|
|
||
|
return getRational(expoTimeInfo, 1, (int)cal_exposureTime);
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getExifGpsProcessingMethod
|
||
|
*
|
||
|
* DESCRIPTION: get GPS processing method
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @gpsProcessingMethod : string to store GPS process method
|
||
|
* @count : length of the string
|
||
|
* @value : the value of the processing method
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t getExifGpsProcessingMethod(char *gpsProcessingMethod,
|
||
|
uint32_t &count, char* value)
|
||
|
{
|
||
|
if(value != NULL) {
|
||
|
memcpy(gpsProcessingMethod, ExifAsciiPrefix, EXIF_ASCII_PREFIX_SIZE);
|
||
|
count = EXIF_ASCII_PREFIX_SIZE;
|
||
|
strlcpy(gpsProcessingMethod + EXIF_ASCII_PREFIX_SIZE,
|
||
|
value,
|
||
|
GPS_PROCESSING_METHOD_SIZE);
|
||
|
count += (uint32_t)strlen(value);
|
||
|
gpsProcessingMethod[count++] = '\0'; // increase 1 for the last NULL char
|
||
|
return NO_ERROR;
|
||
|
} else {
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getExifLatitude
|
||
|
*
|
||
|
* DESCRIPTION: get exif latitude
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @latitude : ptr to rational struct to store latitude info
|
||
|
* @latRef : character to indicate latitude reference
|
||
|
* @value : value of the latitude
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t getExifLatitude(rat_t *latitude, char *latRef, double value)
|
||
|
{
|
||
|
char str[30];
|
||
|
snprintf(str, sizeof(str), "%f", value);
|
||
|
if(str[0] != '\0') {
|
||
|
parseGPSCoordinate(str, latitude);
|
||
|
|
||
|
//set Latitude Ref
|
||
|
float latitudeValue = strtof(str, 0);
|
||
|
if(latitudeValue < 0.0f) {
|
||
|
latRef[0] = 'S';
|
||
|
} else {
|
||
|
latRef[0] = 'N';
|
||
|
}
|
||
|
latRef[1] = '\0';
|
||
|
return NO_ERROR;
|
||
|
}else{
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getExifLongitude
|
||
|
*
|
||
|
* DESCRIPTION: get exif longitude
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @longitude : ptr to rational struct to store longitude info
|
||
|
* @lonRef : character to indicate longitude reference
|
||
|
* @value : value of the longitude
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t getExifLongitude(rat_t *longitude, char *lonRef, double value)
|
||
|
{
|
||
|
char str[30];
|
||
|
snprintf(str, sizeof(str), "%f", value);
|
||
|
if(str[0] != '\0') {
|
||
|
parseGPSCoordinate(str, longitude);
|
||
|
|
||
|
//set Longitude Ref
|
||
|
float longitudeValue = strtof(str, 0);
|
||
|
if(longitudeValue < 0.0f) {
|
||
|
lonRef[0] = 'W';
|
||
|
} else {
|
||
|
lonRef[0] = 'E';
|
||
|
}
|
||
|
lonRef[1] = '\0';
|
||
|
return NO_ERROR;
|
||
|
}else{
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getExifAltitude
|
||
|
*
|
||
|
* DESCRIPTION: get exif altitude
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @altitude : ptr to rational struct to store altitude info
|
||
|
* @altRef : character to indicate altitude reference
|
||
|
* @argValue : altitude value
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t getExifAltitude(rat_t *altitude, char *altRef, double argValue)
|
||
|
{
|
||
|
char str[30];
|
||
|
snprintf(str, sizeof(str), "%f", argValue);
|
||
|
if (str[0] != '\0') {
|
||
|
double value = atof(str);
|
||
|
*altRef = 0;
|
||
|
if(value < 0){
|
||
|
*altRef = 1;
|
||
|
value = -value;
|
||
|
}
|
||
|
return getRational(altitude, (int)(value * 1000), 1000);
|
||
|
} else {
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getExifGpsDateTimeStamp
|
||
|
*
|
||
|
* DESCRIPTION: get exif GPS date time stamp
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @gpsDateStamp : GPS date time stamp string
|
||
|
* @bufLen : length of the string
|
||
|
* @gpsTimeStamp : ptr to rational struct to store time stamp info
|
||
|
* @value : timestamp value
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t getExifGpsDateTimeStamp(char *gpsDateStamp, uint32_t bufLen,
|
||
|
rat_t *gpsTimeStamp, int64_t value)
|
||
|
{
|
||
|
char str[30];
|
||
|
snprintf(str, sizeof(str), "%lld", (long long int)value);
|
||
|
if(str[0] != '\0') {
|
||
|
time_t unixTime = (time_t)atol(str);
|
||
|
struct tm *UTCTimestamp = gmtime(&unixTime);
|
||
|
if (UTCTimestamp != NULL && gpsDateStamp != NULL
|
||
|
&& gpsTimeStamp != NULL) {
|
||
|
strftime(gpsDateStamp, bufLen, "%Y:%m:%d", UTCTimestamp);
|
||
|
|
||
|
getRational(&gpsTimeStamp[0], UTCTimestamp->tm_hour, 1);
|
||
|
getRational(&gpsTimeStamp[1], UTCTimestamp->tm_min, 1);
|
||
|
getRational(&gpsTimeStamp[2], UTCTimestamp->tm_sec, 1);
|
||
|
return NO_ERROR;
|
||
|
} else {
|
||
|
LOGE("Could not get the timestamp");
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
} else {
|
||
|
return BAD_VALUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getExifExposureValue
|
||
|
*
|
||
|
* DESCRIPTION: get exif GPS date time stamp
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @exposure_val : rational exposure value
|
||
|
* @exposure_comp : exposure compensation
|
||
|
* @step : exposure step
|
||
|
*
|
||
|
* RETURN : int32_t type of status
|
||
|
* NO_ERROR -- success
|
||
|
* none-zero failure code
|
||
|
*==========================================================================*/
|
||
|
int32_t getExifExposureValue(srat_t* exposure_val, int32_t exposure_comp,
|
||
|
cam_rational_type_t step)
|
||
|
{
|
||
|
exposure_val->num = exposure_comp * step.numerator;
|
||
|
exposure_val->denom = step.denominator;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* FUNCTION : getExifData
|
||
|
*
|
||
|
* DESCRIPTION: get exif data to be passed into jpeg encoding
|
||
|
*
|
||
|
* PARAMETERS :
|
||
|
* @metadata : metadata of the encoding request
|
||
|
* @jpeg_settings : jpeg_settings for encoding
|
||
|
* @needJpegExifRotation: check if rotation need to added in EXIF
|
||
|
*
|
||
|
* RETURN : exif data from user setting and GPS
|
||
|
*==========================================================================*/
|
||
|
QCamera3Exif *QCamera3PostProcessor::getExifData(metadata_buffer_t *metadata,
|
||
|
jpeg_settings_t *jpeg_settings, bool needJpegExifRotation)
|
||
|
{
|
||
|
QCamera3Exif *exif = new QCamera3Exif();
|
||
|
if (exif == NULL) {
|
||
|
LOGE("No memory for QCamera3Exif");
|
||
|
return NULL;
|
||
|
}
|
||
|
QCamera3HardwareInterface* hal_obj = NULL;
|
||
|
if (m_parent != NULL) {
|
||
|
hal_obj = (QCamera3HardwareInterface*)m_parent->mUserData;
|
||
|
} else {
|
||
|
LOGE("m_parent is NULL, Error");
|
||
|
delete exif;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
int32_t rc = NO_ERROR;
|
||
|
uint32_t count = 0;
|
||
|
|
||
|
// add exif entries
|
||
|
String8 dateTime;
|
||
|
String8 subsecTime;
|
||
|
rc = getExifDateTime(dateTime, subsecTime);
|
||
|
if (rc == NO_ERROR) {
|
||
|
exif->addEntry(EXIFTAGID_DATE_TIME, EXIF_ASCII,
|
||
|
(uint32_t)(dateTime.length() + 1), (void *)dateTime.string());
|
||
|
exif->addEntry(EXIFTAGID_EXIF_DATE_TIME_ORIGINAL, EXIF_ASCII,
|
||
|
(uint32_t)(dateTime.length() + 1), (void *)dateTime.string());
|
||
|
exif->addEntry(EXIFTAGID_EXIF_DATE_TIME_DIGITIZED, EXIF_ASCII,
|
||
|
(uint32_t)(dateTime.length() + 1), (void *)dateTime.string());
|
||
|
exif->addEntry(EXIFTAGID_SUBSEC_TIME, EXIF_ASCII,
|
||
|
(uint32_t)(subsecTime.length() + 1), (void *)subsecTime.string());
|
||
|
exif->addEntry(EXIFTAGID_SUBSEC_TIME_ORIGINAL, EXIF_ASCII,
|
||
|
(uint32_t)(subsecTime.length() + 1), (void *)subsecTime.string());
|
||
|
exif->addEntry(EXIFTAGID_SUBSEC_TIME_DIGITIZED, EXIF_ASCII,
|
||
|
(uint32_t)(subsecTime.length() + 1), (void *)subsecTime.string());
|
||
|
} else {
|
||
|
LOGW("getExifDateTime failed");
|
||
|
}
|
||
|
|
||
|
|
||
|
if (metadata != NULL) {
|
||
|
IF_META_AVAILABLE(float, focal_length, CAM_INTF_META_LENS_FOCAL_LENGTH, metadata) {
|
||
|
rat_t focalLength;
|
||
|
rc = getExifFocalLength(&focalLength, *focal_length);
|
||
|
if (rc == NO_ERROR) {
|
||
|
exif->addEntry(EXIFTAGID_FOCAL_LENGTH,
|
||
|
EXIF_RATIONAL,
|
||
|
1,
|
||
|
(void *)&(focalLength));
|
||
|
} else {
|
||
|
LOGW("getExifFocalLength failed");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
char* jpeg_gps_processing_method = jpeg_settings->gps_processing_method;
|
||
|
if (strlen(jpeg_gps_processing_method) > 0) {
|
||
|
char gpsProcessingMethod[EXIF_ASCII_PREFIX_SIZE +
|
||
|
GPS_PROCESSING_METHOD_SIZE];
|
||
|
count = 0;
|
||
|
rc = getExifGpsProcessingMethod(gpsProcessingMethod,
|
||
|
count,
|
||
|
jpeg_gps_processing_method);
|
||
|
if(rc == NO_ERROR) {
|
||
|
exif->addEntry(EXIFTAGID_GPS_PROCESSINGMETHOD,
|
||
|
EXIFTAGTYPE_GPS_PROCESSINGMETHOD,
|
||
|
count,
|
||
|
(void *)gpsProcessingMethod);
|
||
|
} else {
|
||
|
LOGW("getExifGpsProcessingMethod failed");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (jpeg_settings->gps_coordinates_valid) {
|
||
|
|
||
|
//latitude
|
||
|
rat_t latitude[3];
|
||
|
char latRef[2];
|
||
|
rc = getExifLatitude(latitude, latRef,
|
||
|
jpeg_settings->gps_coordinates[0]);
|
||
|
if(rc == NO_ERROR) {
|
||
|
exif->addEntry(EXIFTAGID_GPS_LATITUDE,
|
||
|
EXIF_RATIONAL,
|
||
|
3,
|
||
|
(void *)latitude);
|
||
|
exif->addEntry(EXIFTAGID_GPS_LATITUDE_REF,
|
||
|
EXIF_ASCII,
|
||
|
2,
|
||
|
(void *)latRef);
|
||
|
} else {
|
||
|
LOGW("getExifLatitude failed");
|
||
|
}
|
||
|
|
||
|
//longitude
|
||
|
rat_t longitude[3];
|
||
|
char lonRef[2];
|
||
|
rc = getExifLongitude(longitude, lonRef,
|
||
|
jpeg_settings->gps_coordinates[1]);
|
||
|
if(rc == NO_ERROR) {
|
||
|
exif->addEntry(EXIFTAGID_GPS_LONGITUDE,
|
||
|
EXIF_RATIONAL,
|
||
|
3,
|
||
|
(void *)longitude);
|
||
|
|
||
|
exif->addEntry(EXIFTAGID_GPS_LONGITUDE_REF,
|
||
|
EXIF_ASCII,
|
||
|
2,
|
||
|
(void *)lonRef);
|
||
|
} else {
|
||
|
LOGW("getExifLongitude failed");
|
||
|
}
|
||
|
|
||
|
//altitude
|
||
|
rat_t altitude;
|
||
|
char altRef;
|
||
|
rc = getExifAltitude(&altitude, &altRef,
|
||
|
jpeg_settings->gps_coordinates[2]);
|
||
|
if(rc == NO_ERROR) {
|
||
|
exif->addEntry(EXIFTAGID_GPS_ALTITUDE,
|
||
|
EXIF_RATIONAL,
|
||
|
1,
|
||
|
(void *)&(altitude));
|
||
|
|
||
|
exif->addEntry(EXIFTAGID_GPS_ALTITUDE_REF,
|
||
|
EXIF_BYTE,
|
||
|
1,
|
||
|
(void *)&altRef);
|
||
|
} else {
|
||
|
LOGW("getExifAltitude failed");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (jpeg_settings->gps_timestamp_valid) {
|
||
|
|
||
|
char gpsDateStamp[20];
|
||
|
rat_t gpsTimeStamp[3];
|
||
|
rc = getExifGpsDateTimeStamp(gpsDateStamp, 20, gpsTimeStamp,
|
||
|
jpeg_settings->gps_timestamp);
|
||
|
if(rc == NO_ERROR) {
|
||
|
exif->addEntry(EXIFTAGID_GPS_DATESTAMP, EXIF_ASCII,
|
||
|
(uint32_t)(strlen(gpsDateStamp) + 1),
|
||
|
(void *)gpsDateStamp);
|
||
|
|
||
|
exif->addEntry(EXIFTAGID_GPS_TIMESTAMP,
|
||
|
EXIF_RATIONAL,
|
||
|
3,
|
||
|
(void *)gpsTimeStamp);
|
||
|
} else {
|
||
|
LOGW("getExifGpsDataTimeStamp failed");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
IF_META_AVAILABLE(int32_t, exposure_comp, CAM_INTF_PARM_EXPOSURE_COMPENSATION, metadata) {
|
||
|
IF_META_AVAILABLE(cam_rational_type_t, comp_step, CAM_INTF_PARM_EV_STEP, metadata) {
|
||
|
srat_t exposure_val;
|
||
|
rc = getExifExposureValue(&exposure_val, *exposure_comp, *comp_step);
|
||
|
if(rc == NO_ERROR) {
|
||
|
exif->addEntry(EXIFTAGID_EXPOSURE_BIAS_VALUE,
|
||
|
EXIF_SRATIONAL,
|
||
|
1,
|
||
|
(void *)(&exposure_val));
|
||
|
} else {
|
||
|
LOGW("getExifExposureValue failed ");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
LOGW("no metadata provided ");
|
||
|
}
|
||
|
|
||
|
#ifdef ENABLE_MODEL_INFO_EXIF
|
||
|
|
||
|
char value[PROPERTY_VALUE_MAX];
|
||
|
if (property_get("ro.product.manufacturer", value, "QCOM-AA") > 0) {
|
||
|
exif->addEntry(EXIFTAGID_MAKE, EXIF_ASCII,
|
||
|
(uint32_t)(strlen(value) + 1), (void *)value);
|
||
|
} else {
|
||
|
LOGW("getExifMaker failed");
|
||
|
}
|
||
|
|
||
|
if (property_get("ro.product.model", value, "QCAM-AA") > 0) {
|
||
|
exif->addEntry(EXIFTAGID_MODEL, EXIF_ASCII,
|
||
|
(uint32_t)(strlen(value) + 1), (void *)value);
|
||
|
} else {
|
||
|
LOGW("getExifModel failed");
|
||
|
}
|
||
|
|
||
|
if (property_get("ro.build.description", value, "QCAM-AA") > 0) {
|
||
|
exif->addEntry(EXIFTAGID_SOFTWARE, EXIF_ASCII,
|
||
|
(uint32_t)(strlen(value) + 1), (void *)value);
|
||
|
} else {
|
||
|
LOGW("getExifSoftware failed");
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
if (jpeg_settings->image_desc_valid) {
|
||
|
if (exif->addEntry(EXIFTAGID_IMAGE_DESCRIPTION, EXIF_ASCII,
|
||
|
strlen(jpeg_settings->image_desc)+1,
|
||
|
(void *)jpeg_settings->image_desc)) {
|
||
|
LOGW("Adding IMAGE_DESCRIPTION tag failed");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LOGD("needJpegExifRotation %d jpeg_settings->jpeg_orientation %d",
|
||
|
needJpegExifRotation, jpeg_settings->jpeg_orientation);
|
||
|
|
||
|
if (needJpegExifRotation) {
|
||
|
int16_t orientation;
|
||
|
switch (jpeg_settings->jpeg_orientation) {
|
||
|
case 0:
|
||
|
orientation = 1;
|
||
|
break;
|
||
|
case 90:
|
||
|
orientation = 6;
|
||
|
break;
|
||
|
case 180:
|
||
|
orientation = 3;
|
||
|
break;
|
||
|
case 270:
|
||
|
orientation = 8;
|
||
|
break;
|
||
|
default:
|
||
|
orientation = 1;
|
||
|
break;
|
||
|
}
|
||
|
exif->addEntry(EXIFTAGID_ORIENTATION,
|
||
|
EXIF_SHORT,
|
||
|
1,
|
||
|
(void *)&orientation);
|
||
|
exif->addEntry(EXIFTAGID_TN_ORIENTATION,
|
||
|
EXIF_SHORT,
|
||
|
1,
|
||
|
(void *)&orientation);
|
||
|
|
||
|
}
|
||
|
|
||
|
return exif;
|
||
|
}
|
||
|
|
||
|
/*===========================================================================
|
||
|
* 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:
|
||
|
LOGW("Error, Unknown type");
|
||
|
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_HAL3_EXIF_TABLE_ENTRIES) {
|
||
|
LOGE("Number of entries exceeded limit");
|
||
|
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) {
|
||
|
LOGE("No memory for byte array");
|
||
|
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) {
|
||
|
LOGE("No memory for ascii string");
|
||
|
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:
|
||
|
{
|
||
|
uint16_t *exif_data = (uint16_t *)data;
|
||
|
if (count > 1) {
|
||
|
uint16_t *values =
|
||
|
(uint16_t *)malloc(count * sizeof(uint16_t));
|
||
|
if (values == NULL) {
|
||
|
LOGE("No memory for short array");
|
||
|
rc = NO_MEMORY;
|
||
|
} else {
|
||
|
memcpy(values, exif_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:
|
||
|
{
|
||
|
uint32_t *exif_data = (uint32_t *)data;
|
||
|
if (count > 1) {
|
||
|
uint32_t *values =
|
||
|
(uint32_t *)malloc(count * sizeof(uint32_t));
|
||
|
if (values == NULL) {
|
||
|
LOGE("No memory for long array");
|
||
|
rc = NO_MEMORY;
|
||
|
} else {
|
||
|
memcpy(values, exif_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:
|
||
|
{
|
||
|
rat_t *exif_data = (rat_t *)data;
|
||
|
if (count > 1) {
|
||
|
rat_t *values = (rat_t *)malloc(count * sizeof(rat_t));
|
||
|
if (values == NULL) {
|
||
|
LOGE("No memory for rational array");
|
||
|
rc = NO_MEMORY;
|
||
|
} else {
|
||
|
memcpy(values, exif_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) {
|
||
|
LOGE("No memory for undefined array");
|
||
|
rc = NO_MEMORY;
|
||
|
} else {
|
||
|
memcpy(values, data, count);
|
||
|
m_Entries[m_nNumEntries].tag_entry.data._undefined = values;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case EXIF_SLONG:
|
||
|
{
|
||
|
int32_t *exif_data = (int32_t *)data;
|
||
|
if (count > 1) {
|
||
|
int32_t *values =
|
||
|
(int32_t *)malloc(count * sizeof(int32_t));
|
||
|
if (values == NULL) {
|
||
|
LOGE("No memory for signed long array");
|
||
|
rc = NO_MEMORY;
|
||
|
} else {
|
||
|
memcpy(values, exif_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:
|
||
|
{
|
||
|
srat_t *exif_data = (srat_t *)data;
|
||
|
if (count > 1) {
|
||
|
srat_t *values = (srat_t *)malloc(count * sizeof(srat_t));
|
||
|
if (values == NULL) {
|
||
|
LOGE("No memory for sign rational array");
|
||
|
rc = NO_MEMORY;
|
||
|
} else {
|
||
|
memcpy(values, exif_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:
|
||
|
LOGE("Error, Unknown type");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Increase number of entries
|
||
|
m_nNumEntries++;
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
}; // namespace qcamera
|