You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4256 lines
155 KiB
4256 lines
155 KiB
/* Copyright (c) 2012-2016, 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 "QCameraPostProc" |
|
|
|
// System dependencies |
|
#include <fcntl.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <utils/Errors.h> |
|
|
|
// Camera dependencies |
|
#include "QCamera2HWI.h" |
|
#include "QCameraPostProc.h" |
|
#include "QCameraTrace.h" |
|
#include "QCameraHALPP.h" |
|
#include "QCameraDualFOVPP.h" |
|
extern "C" { |
|
#include "mm_camera_dbg.h" |
|
} |
|
|
|
namespace qcamera { |
|
|
|
const char *QCameraPostProcessor::STORE_LOCATION = "/sdcard/img_%d.jpg"; |
|
|
|
#define FREE_JPEG_OUTPUT_BUFFER(ptr,cnt) \ |
|
int jpeg_bufs; \ |
|
for (jpeg_bufs = 0; jpeg_bufs < (int)cnt; jpeg_bufs++) { \ |
|
if (ptr[jpeg_bufs] != NULL) { \ |
|
free(ptr[jpeg_bufs]); \ |
|
ptr[jpeg_bufs] = NULL; \ |
|
} \ |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : QCameraPostProcessor |
|
* |
|
* DESCRIPTION: constructor of QCameraPostProcessor. |
|
* |
|
* PARAMETERS : |
|
* @cam_ctrl : ptr to HWI object |
|
* |
|
* RETURN : None |
|
*==========================================================================*/ |
|
QCameraPostProcessor::QCameraPostProcessor(QCamera2HardwareInterface *cam_ctrl) |
|
: m_parent(cam_ctrl), |
|
mJpegCB(NULL), |
|
mJpegUserData(NULL), |
|
mJpegClientHandle(0), |
|
mJpegSessionId(0), |
|
mJpegSessionIdHalPP(0), |
|
m_pJpegExifObj(NULL), |
|
m_bThumbnailNeeded(TRUE), |
|
mPPChannelCount(0), |
|
m_bInited(FALSE), |
|
m_inputPPQ(releaseOngoingPPData, this), |
|
m_ongoingPPQ(releaseOngoingPPData, this), |
|
m_inputJpegQ(releaseJpegData, this), |
|
m_ongoingJpegQ(releaseJpegData, this), |
|
m_inputRawQ(releaseRawData, this), |
|
mSaveFrmCnt(0), |
|
mUseSaveProc(false), |
|
mUseJpegBurst(false), |
|
mJpegMemOpt(true), |
|
m_JpegOutputMemCount(0), |
|
m_JpegOutputMemCountHALPP(0), |
|
pJpegSrcStream(NULL), |
|
mNewJpegSessionNeeded(true), |
|
mNewJpegSessionNeededHalPP(true), |
|
m_bufCountPPQ(0), |
|
m_PPindex(0), |
|
m_halPPType(QCAMERA_HAL_PP_TYPE_UNDEFINED), |
|
m_halPP(NULL) |
|
{ |
|
memset(&mJpegHandle, 0, sizeof(mJpegHandle)); |
|
memset(&mJpegMpoHandle, 0, sizeof(mJpegMpoHandle)); |
|
memset(&m_pJpegOutputMem, 0, sizeof(m_pJpegOutputMem)); |
|
memset(m_pJpegOutputMemHalPP, 0, sizeof(void *) * MM_JPEG_MAX_BUF); |
|
memset(mPPChannels, 0, sizeof(mPPChannels)); |
|
m_DataMem = NULL; |
|
mOfflineDataBufs = NULL; |
|
pthread_mutex_init(&m_reprocess_lock,NULL); |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : ~QCameraPostProcessor |
|
* |
|
* DESCRIPTION: deconstructor of QCameraPostProcessor. |
|
* |
|
* PARAMETERS : None |
|
* |
|
* RETURN : None |
|
*==========================================================================*/ |
|
QCameraPostProcessor::~QCameraPostProcessor() |
|
{ |
|
{FREE_JPEG_OUTPUT_BUFFER(m_pJpegOutputMem,m_JpegOutputMemCount);} |
|
{FREE_JPEG_OUTPUT_BUFFER(m_pJpegOutputMemHalPP, m_JpegOutputMemCountHALPP);} |
|
if (m_pJpegExifObj != NULL) { |
|
delete m_pJpegExifObj; |
|
m_pJpegExifObj = NULL; |
|
} |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
QCameraChannel *pChannel = mPPChannels[i]; |
|
if ( pChannel != NULL ) { |
|
pChannel->stop(); |
|
delete pChannel; |
|
pChannel = NULL; |
|
} |
|
} |
|
if (m_halPP != NULL) { |
|
delete m_halPP; |
|
m_halPP = NULL; |
|
} |
|
mPPChannelCount = 0; |
|
pthread_mutex_destroy(&m_reprocess_lock); |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : setJpegHandle |
|
* |
|
* DESCRIPTION: set JPEG client handles |
|
* |
|
* PARAMETERS : |
|
* @pJpegHandle : JPEG ops handle |
|
* @pJpegMpoHandle : MPO JPEG ops handle |
|
* @clientHandle : JPEG client handle |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::setJpegHandle(mm_jpeg_ops_t *pJpegHandle, |
|
mm_jpeg_mpo_ops_t *pJpegMpoHandle, uint32_t clientHandle) |
|
{ |
|
LOGH("E mJpegClientHandle: %d, clientHandle: %d", |
|
mJpegClientHandle, clientHandle); |
|
|
|
if(pJpegHandle) { |
|
memcpy(&mJpegHandle, pJpegHandle, sizeof(mm_jpeg_ops_t)); |
|
} |
|
|
|
if(pJpegMpoHandle) { |
|
memcpy(&mJpegMpoHandle, pJpegMpoHandle, sizeof(mm_jpeg_mpo_ops_t)); |
|
} |
|
mJpegClientHandle = clientHandle; |
|
LOGH("X mJpegClientHandle: %d, clientHandle: %d", |
|
mJpegClientHandle, clientHandle); |
|
return NO_ERROR; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : init |
|
* |
|
* DESCRIPTION: initialization of postprocessor |
|
* |
|
* PARAMETERS : |
|
* @jpeg_cb : callback to handle jpeg event from mm-camera-interface |
|
* @user_data : user data ptr for jpeg callback |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::init(jpeg_encode_callback_t jpeg_cb, void *user_data) |
|
{ |
|
int32_t rc = NO_ERROR; |
|
mJpegCB = jpeg_cb; |
|
mJpegUserData = user_data; |
|
m_dataProcTh.launch(dataProcessRoutine, this); |
|
m_saveProcTh.launch(dataSaveRoutine, this); |
|
m_parent->mParameters.setReprocCount(); |
|
|
|
/* get setting from mParameters to decie create halpp block or not, |
|
* like: mParameters.getHalPPType(). |
|
* |
|
* read from property for now. |
|
*/ |
|
char prop[PROPERTY_VALUE_MAX]; |
|
memset(prop, 0, sizeof(prop)); |
|
property_get("persist.camera.halpp", prop, "0"); |
|
|
|
m_halPPType = (HALPPType)atoi(prop); |
|
if (m_halPPType < QCAMERA_HAL_PP_TYPE_UNDEFINED || |
|
m_halPPType >= QCAMERA_HAL_PP_TYPE_MAX) { |
|
m_halPPType = QCAMERA_HAL_PP_TYPE_UNDEFINED; |
|
} |
|
LOGH("m_halPPType:%d", m_halPPType); |
|
|
|
if ((m_parent->isDualCamera() && m_halPPType == QCAMERA_HAL_PP_TYPE_DUAL_FOV) || |
|
(m_parent->isDualCamera() && m_halPPType == QCAMERA_HAL_PP_TYPE_BOKEH) || |
|
(m_parent->isDualCamera() && m_halPPType == QCAMERA_HAL_PP_TYPE_CLEARSIGHT)) { |
|
rc = initHALPP(); |
|
} |
|
|
|
m_bInited = TRUE; |
|
return rc; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : deinit |
|
* |
|
* DESCRIPTION: de-initialization of postprocessor |
|
* |
|
* PARAMETERS : None |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::deinit() |
|
{ |
|
if (m_bInited == TRUE) { |
|
m_dataProcTh.exit(); |
|
m_saveProcTh.exit(); |
|
if (m_halPP != NULL) { |
|
m_halPP->deinit(); |
|
m_halPPType = QCAMERA_HAL_PP_TYPE_UNDEFINED; |
|
} |
|
m_bInited = FALSE; |
|
} |
|
return NO_ERROR; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : start |
|
* |
|
* DESCRIPTION: start postprocessor. Data process thread and data notify thread |
|
* will be launched. |
|
* |
|
* PARAMETERS : |
|
* @pSrcChannel : source channel obj ptr that possibly needs reprocess |
|
* |
|
* 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 QCameraPostProcessor::start(QCameraChannel *pSrcChannel) |
|
{ |
|
char prop[PROPERTY_VALUE_MAX]; |
|
int32_t rc = NO_ERROR; |
|
QCameraChannel *pInputChannel = pSrcChannel; |
|
|
|
LOGH("E "); |
|
if (m_bInited == FALSE) { |
|
LOGE("postproc not initialized yet"); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
if (m_DataMem != NULL) { |
|
m_DataMem->release(m_DataMem); |
|
m_DataMem = NULL; |
|
} |
|
|
|
if (pInputChannel == NULL) { |
|
LOGE("Input Channel for pproc is NULL."); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
if ( m_parent->needReprocess() ) { |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
// Delete previous reproc channel |
|
QCameraReprocessChannel *pChannel = mPPChannels[i]; |
|
if (pChannel != NULL) { |
|
pChannel->stop(); |
|
delete pChannel; |
|
pChannel = NULL; |
|
} |
|
} |
|
mPPChannelCount = 0; |
|
|
|
m_bufCountPPQ = 0; |
|
if (!m_parent->isLongshotEnabled()) { |
|
m_parent->mParameters.setReprocCount(); |
|
} |
|
|
|
if (m_parent->mParameters.getManualCaptureMode() >= |
|
CAM_MANUAL_CAPTURE_TYPE_3) { |
|
mPPChannelCount = m_parent->mParameters.getReprocCount() - 1; |
|
} else { |
|
mPPChannelCount = m_parent->mParameters.getReprocCount(); |
|
} |
|
|
|
// Create all reproc channels and start channel |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
mPPChannels[i] = m_parent->addReprocChannel(pInputChannel, i); |
|
if (mPPChannels[i] == NULL) { |
|
LOGE("cannot add multi reprocess channel i = %d", i); |
|
return UNKNOWN_ERROR; |
|
} |
|
rc = mPPChannels[i]->start(); |
|
if (rc != 0) { |
|
LOGE("cannot start multi reprocess channel i = %d", i); |
|
delete mPPChannels[i]; |
|
mPPChannels[i] = NULL; |
|
return UNKNOWN_ERROR; |
|
} |
|
pInputChannel = static_cast<QCameraChannel *>(mPPChannels[i]); |
|
} |
|
} |
|
|
|
if (m_halPP != NULL && m_parent->needHALPP()) { |
|
LOGD("HALPP is need, call QCameraHALPP::start() here"); |
|
rc = m_halPP->start(); |
|
} |
|
|
|
property_get("persist.camera.longshot.save", prop, "0"); |
|
mUseSaveProc = atoi(prop) > 0 ? true : false; |
|
|
|
m_PPindex = 0; |
|
m_InputMetadata.clear(); |
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, TRUE, FALSE); |
|
m_parent->m_cbNotifier.startSnapshots(); |
|
LOGH("X rc = %d", rc); |
|
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 QCameraPostProcessor::stop() |
|
{ |
|
if (m_bInited == TRUE) { |
|
m_parent->m_cbNotifier.stopSnapshots(); |
|
|
|
if (m_DataMem != NULL) { |
|
m_DataMem->release(m_DataMem); |
|
m_DataMem = NULL; |
|
} |
|
|
|
// dataProc Thread need to process "stop" as sync call because abort jpeg job should be a sync call |
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE); |
|
} |
|
// stop reproc channel if exists |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
QCameraReprocessChannel *pChannel = mPPChannels[i]; |
|
if (pChannel != NULL) { |
|
pChannel->stop(); |
|
delete pChannel; |
|
pChannel = NULL; |
|
mPPChannels[i] = NULL; |
|
} |
|
} |
|
mPPChannelCount = 0; |
|
m_PPindex = 0; |
|
m_InputMetadata.clear(); |
|
|
|
if (mOfflineDataBufs != NULL) { |
|
mOfflineDataBufs->deallocate(); |
|
delete mOfflineDataBufs; |
|
mOfflineDataBufs = NULL; |
|
} |
|
|
|
if (m_halPP != NULL && m_parent->needHALPP()) { |
|
LOGD("HALPP is need, call QCameraHALPP::stop() here"); |
|
m_halPP->stop(); |
|
} |
|
|
|
return NO_ERROR; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : createJpegSession |
|
* |
|
* DESCRIPTION: start JPEG session in parallel to reproces to reduce the KPI |
|
* |
|
* PARAMETERS : |
|
* @pSrcChannel : source channel obj ptr that possibly needs reprocess |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::createJpegSession(QCameraChannel *pSrcChannel) |
|
{ |
|
int32_t rc = NO_ERROR; |
|
|
|
LOGH("E "); |
|
if (m_bInited == FALSE) { |
|
LOGE("postproc not initialized yet"); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
if (pSrcChannel == NULL) { |
|
LOGE("Input Channel for pproc is NULL."); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
if (mPPChannelCount > 0) { |
|
QCameraChannel *pChannel = NULL; |
|
int ppChannel_idx = mPPChannelCount - 1; |
|
pChannel = m_parent->needReprocess() ? mPPChannels[ppChannel_idx] : |
|
pSrcChannel; |
|
QCameraStream *pSnapshotStream = NULL; |
|
QCameraStream *pThumbStream = NULL; |
|
bool thumb_stream_needed = ((!m_parent->isZSLMode() || |
|
(m_parent->mParameters.getFlipMode(CAM_STREAM_TYPE_SNAPSHOT) == |
|
m_parent->mParameters.getFlipMode(CAM_STREAM_TYPE_PREVIEW))) && |
|
!m_parent->mParameters.generateThumbFromMain()); |
|
|
|
if (pChannel == NULL) { |
|
LOGE("Input Channel for pproc is NULL for index %d.", |
|
ppChannel_idx); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
for (uint32_t i = 0; i < pChannel->getNumOfStreams(); ++i) { |
|
QCameraStream *pStream = pChannel->getStreamByIndex(i); |
|
|
|
if ( NULL == pStream ) { |
|
break; |
|
} |
|
|
|
if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) || |
|
pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT)) { |
|
pSnapshotStream = pStream; |
|
} |
|
|
|
if ((thumb_stream_needed) && |
|
(pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) || |
|
pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) || |
|
pStream->isOrignalTypeOf(CAM_STREAM_TYPE_PREVIEW) || |
|
pStream->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW))) { |
|
pThumbStream = pStream; |
|
} |
|
} |
|
|
|
// If thumbnail is not part of the reprocess channel, then |
|
// try to get it from the source channel |
|
if ((thumb_stream_needed) && (NULL == pThumbStream) && |
|
(pChannel == mPPChannels[ppChannel_idx])) { |
|
for (uint32_t i = 0; i < pSrcChannel->getNumOfStreams(); ++i) { |
|
QCameraStream *pStream = pSrcChannel->getStreamByIndex(i); |
|
|
|
if ( NULL == pStream ) { |
|
break; |
|
} |
|
|
|
if (pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) || |
|
pStream->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW) || |
|
pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) || |
|
pStream->isOrignalTypeOf(CAM_STREAM_TYPE_PREVIEW)) { |
|
pThumbStream = pStream; |
|
} |
|
} |
|
} |
|
|
|
if ( NULL != pSnapshotStream ) { |
|
mm_jpeg_encode_params_t encodeParam; |
|
memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t)); |
|
rc = getJpegEncodingConfig(encodeParam, pSnapshotStream, pThumbStream); |
|
if (rc != NO_ERROR) { |
|
LOGE("error getting encoding config"); |
|
return rc; |
|
} |
|
LOGH("[KPI Perf] : call jpeg create_session"); |
|
|
|
rc = mJpegHandle.create_session(mJpegClientHandle, |
|
&encodeParam, |
|
&mJpegSessionId); |
|
if (rc != NO_ERROR) { |
|
LOGE("error creating a new jpeg encoding session"); |
|
return rc; |
|
} |
|
pJpegSrcStream = pSnapshotStream; |
|
mNewJpegSessionNeeded = false; |
|
} |
|
} |
|
LOGH("X "); |
|
return rc; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : getJpegEncodingConfig |
|
* |
|
* DESCRIPTION: function to prepare encoding job information |
|
* |
|
* PARAMETERS : |
|
* @encode_parm : param to be filled with encoding configuration |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::getJpegEncodingConfig(mm_jpeg_encode_params_t& encode_parm, |
|
QCameraStream *main_stream, |
|
QCameraStream *thumb_stream, |
|
const mm_camera_super_buf_t *halpp_out_buf) |
|
{ |
|
LOGD("E"); |
|
int32_t ret = NO_ERROR; |
|
size_t out_size; |
|
|
|
char prop[PROPERTY_VALUE_MAX]; |
|
property_get("persist.camera.jpeg_burst", prop, "0"); |
|
mUseJpegBurst = (atoi(prop) > 0) && !mUseSaveProc; |
|
encode_parm.burst_mode = mUseJpegBurst; |
|
|
|
cam_rect_t crop; |
|
memset(&crop, 0, sizeof(cam_rect_t)); |
|
main_stream->getCropInfo(crop); |
|
|
|
cam_dimension_t src_dim, dst_dim; |
|
memset(&src_dim, 0, sizeof(cam_dimension_t)); |
|
memset(&dst_dim, 0, sizeof(cam_dimension_t)); |
|
main_stream->getFrameDimension(src_dim); |
|
|
|
LOGD("src stream dimesion:%dx%d", src_dim.width, src_dim.height); |
|
|
|
bool hdr_output_crop = m_parent->mParameters.isHDROutputCropEnabled(); |
|
if (hdr_output_crop && crop.height) { |
|
dst_dim.height = crop.height; |
|
} else { |
|
dst_dim.height = src_dim.height; |
|
} |
|
if (hdr_output_crop && crop.width) { |
|
dst_dim.width = crop.width; |
|
} else { |
|
dst_dim.width = src_dim.width; |
|
} |
|
|
|
// set rotation only when no online rotation or offline pp rotation is done before |
|
if (!m_parent->needRotationReprocess()) { |
|
encode_parm.rotation = m_parent->mParameters.getJpegRotation(); |
|
} |
|
|
|
encode_parm.main_dim.src_dim = src_dim; |
|
encode_parm.main_dim.dst_dim = dst_dim; |
|
|
|
m_dst_dim = dst_dim; |
|
|
|
encode_parm.jpeg_cb = mJpegCB; |
|
encode_parm.userdata = mJpegUserData; |
|
|
|
m_bThumbnailNeeded = TRUE; // need encode thumbnail by default |
|
// system property to disable the thumbnail encoding in order to reduce the power |
|
// by default thumbnail encoding is set to TRUE and explicitly set this property to |
|
// disable the thumbnail encoding |
|
property_get("persist.camera.tn.disable", prop, "0"); |
|
if (atoi(prop) == 1) { |
|
m_bThumbnailNeeded = FALSE; |
|
LOGH("m_bThumbnailNeeded is %d", m_bThumbnailNeeded); |
|
} |
|
cam_dimension_t thumbnailSize; |
|
memset(&thumbnailSize, 0, sizeof(cam_dimension_t)); |
|
m_parent->getThumbnailSize(thumbnailSize); |
|
if (thumbnailSize.width == 0 || thumbnailSize.height == 0) { |
|
// (0,0) means no thumbnail |
|
m_bThumbnailNeeded = FALSE; |
|
} |
|
encode_parm.encode_thumbnail = m_bThumbnailNeeded; |
|
|
|
// get color format |
|
cam_format_t img_fmt = CAM_FORMAT_YUV_420_NV12; |
|
main_stream->getFormat(img_fmt); |
|
encode_parm.color_format = getColorfmtFromImgFmt(img_fmt); |
|
|
|
// get jpeg quality |
|
uint32_t val = m_parent->getJpegQuality(); |
|
if (0U < val) { |
|
encode_parm.quality = val; |
|
} else { |
|
LOGH("Using default JPEG quality"); |
|
encode_parm.quality = 85; |
|
} |
|
cam_frame_len_offset_t main_offset; |
|
memset(&main_offset, 0, sizeof(cam_frame_len_offset_t)); |
|
main_stream->getFrameOffset(main_offset); |
|
|
|
LOGD("frame offset info: len:%d, w:%d, h:%d, stride:%d, scanline:%d", |
|
main_offset.frame_len, main_offset.mp[0].width, main_offset.mp[0].height, |
|
main_offset.mp[0].stride, main_offset.mp[0].scanline); |
|
|
|
// src buf config |
|
if (halpp_out_buf == NULL) { |
|
QCameraMemory *pStreamMem = main_stream->getStreamBufs(); |
|
if (pStreamMem == NULL) { |
|
LOGE("cannot get stream bufs from main stream"); |
|
ret = BAD_VALUE; |
|
goto on_error; |
|
} |
|
encode_parm.num_src_bufs = pStreamMem->getCnt(); |
|
for (uint32_t i = 0; i < encode_parm.num_src_bufs; i++) { |
|
camera_memory_t *stream_mem = pStreamMem->getMemory(i, false); |
|
if (stream_mem != NULL) { |
|
encode_parm.src_main_buf[i].index = i; |
|
encode_parm.src_main_buf[i].buf_size = stream_mem->size; |
|
encode_parm.src_main_buf[i].buf_vaddr = (uint8_t *)stream_mem->data; |
|
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 { |
|
LOGH("use halpp output super buffer as jpeg input buffer!"); |
|
|
|
/* only one buffer from halpp output */ |
|
encode_parm.num_src_bufs = 1; |
|
for (uint32_t i = 0; i < encode_parm.num_src_bufs; i++) { |
|
encode_parm.src_main_buf[i].index = i; |
|
encode_parm.src_main_buf[i].buf_size = halpp_out_buf->bufs[0]->frame_len; |
|
encode_parm.src_main_buf[i].buf_vaddr = (uint8_t *)halpp_out_buf->bufs[0]->buffer; |
|
encode_parm.src_main_buf[i].fd = halpp_out_buf->bufs[0]->fd; |
|
encode_parm.src_main_buf[i].format = MM_JPEG_FMT_YUV; |
|
encode_parm.src_main_buf[i].offset = main_offset; |
|
LOGD("src main buf: idx %d, size:%d, vaddr:%p, fd:%d", |
|
encode_parm.src_main_buf[i].index, |
|
encode_parm.src_main_buf[i].buf_size, |
|
encode_parm.src_main_buf[i].buf_vaddr, |
|
encode_parm.src_main_buf[i].fd); |
|
} |
|
} |
|
|
|
LOGI("Src Buffer cnt = %d, res = %dX%d len = %d rot = %d " |
|
"src_dim = %dX%d dst_dim = %dX%d", |
|
encode_parm.num_src_bufs, |
|
main_offset.mp[0].width, main_offset.mp[0].height, |
|
main_offset.frame_len, encode_parm.rotation, |
|
src_dim.width, src_dim.height, |
|
dst_dim.width, dst_dim.height); |
|
|
|
if (m_bThumbnailNeeded == TRUE) { |
|
m_parent->getThumbnailSize(encode_parm.thumb_dim.dst_dim); |
|
|
|
if (thumb_stream == NULL) { |
|
thumb_stream = main_stream; |
|
} |
|
if (((90 == m_parent->mParameters.getJpegRotation()) |
|
|| (270 == m_parent->mParameters.getJpegRotation())) |
|
&& (m_parent->needRotationReprocess())) { |
|
// swap thumbnail dimensions |
|
cam_dimension_t tmp_dim = encode_parm.thumb_dim.dst_dim; |
|
encode_parm.thumb_dim.dst_dim.width = tmp_dim.height; |
|
encode_parm.thumb_dim.dst_dim.height = tmp_dim.width; |
|
} |
|
|
|
if (halpp_out_buf == NULL) { |
|
QCameraMemory * pStreamMem = thumb_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)); |
|
thumb_stream->getFrameOffset(thumb_offset); |
|
encode_parm.num_tmb_bufs = pStreamMem->getCnt(); |
|
for (uint32_t i = 0; i < pStreamMem->getCnt(); i++) { |
|
camera_memory_t *stream_mem = pStreamMem->getMemory(i, false); |
|
if (stream_mem != NULL) { |
|
encode_parm.src_thumb_buf[i].index = i; |
|
encode_parm.src_thumb_buf[i].buf_size = stream_mem->size; |
|
encode_parm.src_thumb_buf[i].buf_vaddr = (uint8_t *)stream_mem->data; |
|
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; |
|
} |
|
} |
|
|
|
cam_format_t img_fmt_thumb = CAM_FORMAT_YUV_420_NV12; |
|
thumb_stream->getFormat(img_fmt_thumb); |
|
encode_parm.thumb_color_format = getColorfmtFromImgFmt(img_fmt_thumb); |
|
|
|
// crop is the same if frame is the same |
|
if (thumb_stream != main_stream) { |
|
memset(&crop, 0, sizeof(cam_rect_t)); |
|
thumb_stream->getCropInfo(crop); |
|
} |
|
|
|
memset(&src_dim, 0, sizeof(cam_dimension_t)); |
|
thumb_stream->getFrameDimension(src_dim); |
|
encode_parm.thumb_dim.src_dim = src_dim; |
|
|
|
if (!m_parent->needRotationReprocess()) { |
|
encode_parm.thumb_rotation = m_parent->mParameters.getJpegRotation(); |
|
} |
|
encode_parm.thumb_dim.crop = crop; |
|
encode_parm.thumb_from_postview = |
|
!m_parent->mParameters.generateThumbFromMain() && |
|
(img_fmt_thumb != CAM_FORMAT_YUV_420_NV12_UBWC) && |
|
(m_parent->mParameters.useJpegExifRotation() || |
|
m_parent->mParameters.getJpegRotation() == 0); |
|
|
|
if (encode_parm.thumb_from_postview && |
|
m_parent->mParameters.useJpegExifRotation()){ |
|
encode_parm.thumb_rotation = |
|
m_parent->mParameters.getJpegExifRotation(); |
|
} |
|
} else { |
|
LOGH("use halpp output super buffer for thumbnail!"); |
|
|
|
// use main buf for thumbnail encoding in this case. |
|
encode_parm.num_tmb_bufs = encode_parm.num_src_bufs; |
|
for (uint32_t i = 0; i < encode_parm.num_tmb_bufs; i++) { |
|
memcpy(&encode_parm.src_thumb_buf[i], &encode_parm.src_main_buf[i], |
|
sizeof(mm_jpeg_buf_t)); |
|
} |
|
encode_parm.thumb_color_format = encode_parm.color_format; |
|
|
|
// copy params from src main frame |
|
encode_parm.thumb_dim.src_dim = encode_parm.main_dim.src_dim; |
|
encode_parm.thumb_rotation = encode_parm.rotation; |
|
encode_parm.thumb_dim.crop = encode_parm.main_dim.crop; |
|
|
|
encode_parm.thumb_from_postview = FALSE; |
|
} |
|
|
|
LOGI("Src THUMB buf_cnt = %d, res = %dX%d len = %d rot = %d " |
|
"src_dim = %dX%d, dst_dim = %dX%d", |
|
encode_parm.num_tmb_bufs, |
|
encode_parm.src_thumb_buf[0].offset.mp[0].width, |
|
encode_parm.src_thumb_buf[0].offset.mp[0].height, |
|
encode_parm.src_thumb_buf[0].offset.frame_len, |
|
encode_parm.thumb_rotation, |
|
encode_parm.thumb_dim.src_dim.width, |
|
encode_parm.thumb_dim.src_dim.height, |
|
encode_parm.thumb_dim.dst_dim.width, |
|
encode_parm.thumb_dim.dst_dim.height); |
|
} |
|
|
|
encode_parm.num_dst_bufs = 1; |
|
if ((halpp_out_buf == NULL && mUseJpegBurst) || |
|
(halpp_out_buf != NULL && mUseJpegBurstHalPP)) { |
|
encode_parm.num_dst_bufs = MAX_JPEG_BURST; |
|
} |
|
|
|
encode_parm.get_memory = NULL; |
|
out_size = main_offset.frame_len; |
|
if (mJpegMemOpt) { |
|
encode_parm.get_memory = getJpegMemory; |
|
encode_parm.put_memory = releaseJpegMemory; |
|
out_size = sizeof(omx_jpeg_ouput_buf_t); |
|
encode_parm.num_dst_bufs = encode_parm.num_src_bufs; |
|
} |
|
|
|
if (halpp_out_buf == NULL) { |
|
m_JpegOutputMemCount = (uint32_t)encode_parm.num_dst_bufs; |
|
for (uint32_t i = 0; i < m_JpegOutputMemCount; i++) { |
|
if (m_pJpegOutputMem[i] != NULL) |
|
free(m_pJpegOutputMem[i]); |
|
omx_jpeg_ouput_buf_t omx_out_buf; |
|
memset(&omx_out_buf, 0, sizeof(omx_jpeg_ouput_buf_t)); |
|
omx_out_buf.handle = this; |
|
// allocate output buf for jpeg encoding |
|
m_pJpegOutputMem[i] = malloc(out_size); |
|
|
|
if (NULL == m_pJpegOutputMem[i]) { |
|
ret = NO_MEMORY; |
|
LOGE("initHeapMem for jpeg, ret = NO_MEMORY"); |
|
goto on_error; |
|
} |
|
|
|
if (mJpegMemOpt) { |
|
memcpy(m_pJpegOutputMem[i], &omx_out_buf, sizeof(omx_out_buf)); |
|
} |
|
|
|
encode_parm.dest_buf[i].index = i; |
|
encode_parm.dest_buf[i].buf_size = main_offset.frame_len; |
|
encode_parm.dest_buf[i].buf_vaddr = (uint8_t *)m_pJpegOutputMem[i]; |
|
encode_parm.dest_buf[i].fd = -1; |
|
encode_parm.dest_buf[i].format = MM_JPEG_FMT_YUV; |
|
encode_parm.dest_buf[i].offset = main_offset; |
|
} |
|
} else { |
|
m_JpegOutputMemCountHALPP = (uint32_t)encode_parm.num_dst_bufs; |
|
LOGD("num dst bufs:%d", encode_parm.num_dst_bufs); |
|
for (uint32_t i = 0; i < m_JpegOutputMemCountHALPP; i++) { |
|
if (m_pJpegOutputMemHalPP[i] != NULL) { |
|
free(m_pJpegOutputMemHalPP[i]); |
|
m_pJpegOutputMemHalPP[i] = NULL; |
|
} |
|
omx_jpeg_ouput_buf_t omx_out_buf; |
|
memset(&omx_out_buf, 0, sizeof(omx_jpeg_ouput_buf_t)); |
|
omx_out_buf.handle = this; |
|
|
|
// allocate output buf for jpeg encoding |
|
m_pJpegOutputMemHalPP[i] = malloc(out_size); |
|
if (NULL == m_pJpegOutputMemHalPP[i]) { |
|
ret = NO_MEMORY; |
|
LOGE("initHeapMem for jpeg, ret = NO_MEMORY"); |
|
goto on_error; |
|
} |
|
|
|
if (mJpegMemOpt) { |
|
memcpy(m_pJpegOutputMemHalPP[i], &omx_out_buf, sizeof(omx_out_buf)); |
|
} |
|
|
|
encode_parm.dest_buf[i].index = i; |
|
encode_parm.dest_buf[i].buf_size = main_offset.frame_len; |
|
encode_parm.dest_buf[i].buf_vaddr = (uint8_t *)m_pJpegOutputMemHalPP[i]; |
|
encode_parm.dest_buf[i].fd = -1; |
|
encode_parm.dest_buf[i].format = MM_JPEG_FMT_YUV; |
|
encode_parm.dest_buf[i].offset = main_offset; |
|
} |
|
} |
|
|
|
LOGD("X"); |
|
return NO_ERROR; |
|
|
|
on_error: |
|
FREE_JPEG_OUTPUT_BUFFER(m_pJpegOutputMem, m_JpegOutputMemCount); |
|
|
|
LOGD("X with error %d", ret); |
|
return ret; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : sendEvtNotify |
|
* |
|
* DESCRIPTION: send event notify through notify callback registered by upper layer |
|
* |
|
* PARAMETERS : |
|
* @msg_type: msg type of notify |
|
* @ext1 : extension |
|
* @ext2 : extension |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::sendEvtNotify(int32_t msg_type, |
|
int32_t ext1, |
|
int32_t ext2) |
|
{ |
|
return m_parent->sendEvtNotify(msg_type, ext1, ext2); |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : sendDataNotify |
|
* |
|
* DESCRIPTION: enqueue data into dataNotify thread |
|
* |
|
* PARAMETERS : |
|
* @msg_type: data callback msg type |
|
* @data : ptr to data memory struct |
|
* @index : index to data buffer |
|
* @metadata: ptr to meta data buffer if there is any |
|
* @release_data : ptr to struct indicating if data need to be released |
|
* after notify |
|
* @super_buf_frame_idx : super buffer frame index |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::sendDataNotify(int32_t msg_type, |
|
camera_memory_t *data, |
|
uint8_t index, |
|
camera_frame_metadata_t *metadata, |
|
qcamera_release_data_t *release_data, |
|
uint32_t super_buf_frame_idx) |
|
{ |
|
qcamera_data_argm_t *data_cb = (qcamera_data_argm_t *)malloc(sizeof(qcamera_data_argm_t)); |
|
if (NULL == data_cb) { |
|
LOGE("no mem for acamera_data_argm_t"); |
|
return NO_MEMORY; |
|
} |
|
memset(data_cb, 0, sizeof(qcamera_data_argm_t)); |
|
data_cb->msg_type = msg_type; |
|
data_cb->data = data; |
|
data_cb->index = index; |
|
data_cb->metadata = metadata; |
|
if (release_data != NULL) { |
|
data_cb->release_data = *release_data; |
|
} |
|
|
|
qcamera_callback_argm_t cbArg; |
|
memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); |
|
cbArg.cb_type = QCAMERA_DATA_SNAPSHOT_CALLBACK; |
|
cbArg.msg_type = msg_type; |
|
cbArg.data = data; |
|
cbArg.metadata = metadata; |
|
cbArg.user_data = data_cb; |
|
cbArg.cookie = this; |
|
cbArg.release_cb = releaseNotifyData; |
|
cbArg.frame_index = super_buf_frame_idx; |
|
int rc = m_parent->m_cbNotifier.notifyCallback(cbArg); |
|
if ( NO_ERROR != rc ) { |
|
LOGE("Error enqueuing jpeg data into notify queue"); |
|
releaseNotifyData(data_cb, this, UNKNOWN_ERROR); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
return rc; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : validatePostProcess |
|
* |
|
* DESCRIPTION: Verify output buffer count of pp module |
|
* |
|
* PARAMETERS : |
|
* @frame : process frame received from mm-camera-interface |
|
* |
|
* RETURN : bool type of status |
|
* TRUE -- success |
|
* FALSE failure |
|
*==========================================================================*/ |
|
bool QCameraPostProcessor::validatePostProcess(mm_camera_super_buf_t *frame) |
|
{ |
|
bool status = TRUE; |
|
QCameraChannel *pChannel = NULL; |
|
QCameraReprocessChannel *m_pReprocChannel = NULL; |
|
|
|
if (frame == NULL) { |
|
return status; |
|
} |
|
|
|
pChannel = m_parent->getChannelByHandle(frame->ch_id); |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
if (pChannel == mPPChannels[i]->getSrcChannel()) { |
|
m_pReprocChannel = mPPChannels[i]; |
|
break; |
|
} |
|
} |
|
|
|
if ((m_pReprocChannel != NULL) && (pChannel == m_pReprocChannel->getSrcChannel())) { |
|
QCameraStream *pStream = NULL; |
|
for (uint8_t i = 0; i < m_pReprocChannel->getNumOfStreams(); i++) { |
|
pStream = m_pReprocChannel->getStreamByIndex(i); |
|
if (pStream && (m_inputPPQ.getCurrentSize() > 0) && |
|
(m_ongoingPPQ.getCurrentSize() >= pStream->getNumQueuedBuf())) { |
|
LOGW("Out of PP Buffer PPQ = %d ongoingQ = %d Jpeg = %d onJpeg = %d", |
|
m_inputPPQ.getCurrentSize(), m_ongoingPPQ.getCurrentSize(), |
|
m_inputJpegQ.getCurrentSize(), m_ongoingJpegQ.getCurrentSize()); |
|
status = FALSE; |
|
break; |
|
} |
|
} |
|
} |
|
return status; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : getOfflinePPInputBuffer |
|
* |
|
* DESCRIPTION: Function to generate offline post proc buffer |
|
* |
|
* PARAMETERS : |
|
* @src_frame : process frame received from mm-camera-interface |
|
* |
|
* RETURN : Buffer pointer if successfull |
|
* : NULL in case of failures |
|
*==========================================================================*/ |
|
mm_camera_buf_def_t *QCameraPostProcessor::getOfflinePPInputBuffer( |
|
mm_camera_super_buf_t *src_frame) |
|
{ |
|
mm_camera_buf_def_t *mBufDefs = NULL; |
|
QCameraChannel *pChannel = NULL; |
|
QCameraStream *src_pStream = NULL; |
|
mm_camera_buf_def_t *data_frame = NULL; |
|
mm_camera_buf_def_t *meta_frame = NULL; |
|
|
|
if (mOfflineDataBufs == NULL) { |
|
LOGE("Offline Buffer not allocated"); |
|
return NULL; |
|
} |
|
|
|
uint32_t num_bufs = mOfflineDataBufs->getCnt(); |
|
size_t bufDefsSize = num_bufs * sizeof(mm_camera_buf_def_t); |
|
mBufDefs = (mm_camera_buf_def_t *)malloc(bufDefsSize); |
|
if (mBufDefs == NULL) { |
|
LOGE("No memory"); |
|
return NULL; |
|
} |
|
memset(mBufDefs, 0, bufDefsSize); |
|
|
|
pChannel = m_parent->getChannelByHandle(src_frame->ch_id); |
|
for (uint32_t i = 0; i < src_frame->num_bufs; i++) { |
|
src_pStream = pChannel->getStreamByHandle( |
|
src_frame->bufs[i]->stream_id); |
|
if (src_pStream != NULL) { |
|
if (src_pStream->getMyType() == CAM_STREAM_TYPE_RAW) { |
|
LOGH("Found RAW input stream"); |
|
data_frame = src_frame->bufs[i]; |
|
} else if (src_pStream->getMyType() == CAM_STREAM_TYPE_METADATA){ |
|
LOGH("Found Metada input stream"); |
|
meta_frame = src_frame->bufs[i]; |
|
} |
|
} |
|
} |
|
|
|
if ((src_pStream != NULL) && (data_frame != NULL)) { |
|
cam_frame_len_offset_t offset; |
|
memset(&offset, 0, sizeof(cam_frame_len_offset_t)); |
|
src_pStream->getFrameOffset(offset); |
|
for (uint32_t i = 0; i < num_bufs; i++) { |
|
mBufDefs[i] = *data_frame; |
|
mOfflineDataBufs->getBufDef(offset, mBufDefs[i], i); |
|
|
|
LOGD("Dumping RAW data on offline buffer"); |
|
/*Actual data memcpy just for verification*/ |
|
memcpy(mBufDefs[i].buffer, data_frame->buffer, |
|
mBufDefs[i].frame_len); |
|
} |
|
releaseSuperBuf(src_frame, CAM_STREAM_TYPE_RAW); |
|
} else { |
|
free(mBufDefs); |
|
mBufDefs = NULL; |
|
} |
|
|
|
LOGH("mBufDefs = %p", mBufDefs); |
|
return mBufDefs; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : processData |
|
* |
|
* DESCRIPTION: enqueue data into dataProc thread |
|
* |
|
* PARAMETERS : |
|
* @frame : process frame received from mm-camera-interface |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
* |
|
* NOTE : depends on if offline reprocess is needed, received frame will |
|
* be sent to either input queue of postprocess or jpeg encoding |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::processData(mm_camera_super_buf_t *frame) |
|
{ |
|
if (m_bInited == FALSE) { |
|
LOGE("postproc not initialized yet"); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
if (frame == NULL) { |
|
LOGE("Invalid parameter"); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
mm_camera_buf_def_t *meta_frame = NULL; |
|
for (uint32_t i = 0; i < frame->num_bufs; i++) { |
|
// look through input superbuf |
|
if (frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) { |
|
meta_frame = frame->bufs[i]; |
|
break; |
|
} |
|
} |
|
if (meta_frame != NULL) { |
|
//Function to upadte metadata for frame based parameter |
|
m_parent->updateMetadata((metadata_buffer_t *)meta_frame->buffer); |
|
} |
|
|
|
if (m_parent->needReprocess()) { |
|
if ((!m_parent->isLongshotEnabled() && |
|
!m_parent->m_stateMachine.isNonZSLCaptureRunning()) || |
|
(m_parent->isLongshotEnabled() && |
|
m_parent->isCaptureShutterEnabled())) { |
|
//play shutter sound |
|
m_parent->playShutter(); |
|
} |
|
|
|
ATRACE_INT("Camera:Reprocess", 1); |
|
LOGH("need reprocess"); |
|
|
|
// enqueu to post proc input queue |
|
qcamera_pp_data_t *pp_request_job = |
|
(qcamera_pp_data_t *)malloc(sizeof(qcamera_pp_data_t)); |
|
if (pp_request_job == NULL) { |
|
LOGE("No memory for pproc job"); |
|
return NO_MEMORY; |
|
} |
|
memset(pp_request_job, 0, sizeof(qcamera_pp_data_t)); |
|
pp_request_job->src_frame = frame; |
|
pp_request_job->src_reproc_frame = frame; |
|
pp_request_job->reprocCount = 0; |
|
pp_request_job->ppChannelIndex = 0; |
|
|
|
if ((NULL != frame) && |
|
(0 < frame->num_bufs) |
|
&& (m_parent->isRegularCapture())) { |
|
/*Regular capture. Source stream will be deleted*/ |
|
mm_camera_buf_def_t *bufs = NULL; |
|
uint32_t num_bufs = frame->num_bufs; |
|
bufs = new mm_camera_buf_def_t[num_bufs]; |
|
if (NULL == bufs) { |
|
LOGE("Unable to allocate cached buffers"); |
|
return NO_MEMORY; |
|
} |
|
|
|
for (uint32_t i = 0; i < num_bufs; i++) { |
|
bufs[i] = *frame->bufs[i]; |
|
frame->bufs[i] = &bufs[i]; |
|
} |
|
pp_request_job->src_reproc_bufs = bufs; |
|
|
|
// Don't release source frame after encoding |
|
// at this point the source channel will not exist. |
|
pp_request_job->reproc_frame_release = true; |
|
} |
|
|
|
if (mOfflineDataBufs != NULL) { |
|
pp_request_job->offline_reproc_buf = |
|
getOfflinePPInputBuffer(frame); |
|
if (pp_request_job->offline_reproc_buf != NULL) { |
|
pp_request_job->offline_buffer = true; |
|
} |
|
} |
|
|
|
if (false == m_inputPPQ.enqueue((void *)pp_request_job)) { |
|
LOGW("Input PP Q is not active!!!"); |
|
releaseSuperBuf(frame); |
|
free(frame); |
|
free(pp_request_job); |
|
frame = NULL; |
|
pp_request_job = NULL; |
|
return NO_ERROR; |
|
} |
|
if (m_parent->mParameters.isAdvCamFeaturesEnabled() |
|
&& (meta_frame != NULL)) { |
|
m_InputMetadata.add(meta_frame); |
|
} |
|
} else if (m_parent->mParameters.isNV16PictureFormat() || |
|
m_parent->mParameters.isNV21PictureFormat()) { |
|
//check if raw frame information is needed. |
|
if(m_parent->mParameters.isYUVFrameInfoNeeded()) |
|
setYUVFrameInfo(frame); |
|
|
|
processRawData(frame); |
|
} else { |
|
//play shutter sound |
|
if(!m_parent->m_stateMachine.isNonZSLCaptureRunning() && |
|
!m_parent->mLongshotEnabled) |
|
m_parent->playShutter(); |
|
|
|
LOGH("no need offline reprocess, sending to jpeg encoding"); |
|
qcamera_jpeg_data_t *jpeg_job = |
|
(qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t)); |
|
if (jpeg_job == NULL) { |
|
LOGE("No memory for jpeg job"); |
|
return NO_MEMORY; |
|
} |
|
|
|
memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t)); |
|
jpeg_job->src_frame = frame; |
|
|
|
if (meta_frame != NULL) { |
|
// fill in meta data frame ptr |
|
jpeg_job->metadata = (metadata_buffer_t *)meta_frame->buffer; |
|
} |
|
|
|
// enqueu to jpeg input queue |
|
if (!m_inputJpegQ.enqueue((void *)jpeg_job)) { |
|
LOGW("Input Jpeg Q is not active!!!"); |
|
releaseJpegJobData(jpeg_job); |
|
free(jpeg_job); |
|
jpeg_job = NULL; |
|
return NO_ERROR; |
|
} |
|
} |
|
|
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
|
return NO_ERROR; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : processRawData |
|
* |
|
* DESCRIPTION: enqueue raw data into dataProc thread |
|
* |
|
* PARAMETERS : |
|
* @frame : process frame received from mm-camera-interface |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::processRawData(mm_camera_super_buf_t *frame) |
|
{ |
|
if (m_bInited == FALSE) { |
|
LOGE("postproc not initialized yet"); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
// enqueu to raw input queue |
|
if (m_inputRawQ.enqueue((void *)frame)) { |
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
|
} else { |
|
LOGW("m_inputRawQ is not active!!!"); |
|
releaseSuperBuf(frame); |
|
free(frame); |
|
frame = NULL; |
|
} |
|
return NO_ERROR; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : processJpegEvt |
|
* |
|
* DESCRIPTION: process jpeg event from mm-jpeg-interface. |
|
* |
|
* PARAMETERS : |
|
* @evt : payload of jpeg event, including information about jpeg encoding |
|
* status, jpeg size and so on. |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
* |
|
* NOTE : This event will also trigger DataProc thread to move to next job |
|
* processing (i.e., send a new jpeg encoding job to mm-jpeg-interface |
|
* if there is any pending job in jpeg input queue) |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::processJpegEvt(qcamera_jpeg_evt_payload_t *evt) |
|
{ |
|
if (m_bInited == FALSE) { |
|
LOGE("postproc not initialized yet"); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
int32_t rc = NO_ERROR; |
|
camera_memory_t *jpeg_mem = NULL; |
|
omx_jpeg_ouput_buf_t *jpeg_out = NULL; |
|
void *jpegData = NULL; |
|
if (mUseSaveProc && m_parent->isLongshotEnabled()) { |
|
qcamera_jpeg_evt_payload_t *saveData = ( qcamera_jpeg_evt_payload_t * ) malloc(sizeof(qcamera_jpeg_evt_payload_t)); |
|
if ( NULL == saveData ) { |
|
LOGE("Can not allocate save data message!"); |
|
return NO_MEMORY; |
|
} |
|
*saveData = *evt; |
|
if (m_inputSaveQ.enqueue((void *) saveData)) { |
|
m_saveProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
|
} else { |
|
LOGD("m_inputSaveQ PP Q is not active!!!"); |
|
free(saveData); |
|
saveData = NULL; |
|
return rc; |
|
} |
|
} else { |
|
/* To be removed later when ISP Frame sync feature is available |
|
qcamera_jpeg_data_t *jpeg_job = |
|
(qcamera_jpeg_data_t *)m_ongoingJpegQ.dequeue(matchJobId, |
|
(void*)&evt->jobId); |
|
uint32_t frame_idx = jpeg_job->src_frame->bufs[0]->frame_idx;*/ |
|
uint32_t frame_idx = 75; |
|
LOGH("FRAME INDEX %d", frame_idx); |
|
// Release jpeg job data |
|
m_ongoingJpegQ.flushNodes(matchJobId, (void*)&evt->jobId); |
|
|
|
if (m_inputPPQ.getCurrentSize() > 0) { |
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
|
} |
|
LOGH("[KPI Perf] : jpeg job %d", evt->jobId); |
|
|
|
if ((false == m_parent->m_bIntJpegEvtPending) && |
|
(m_parent->mDataCb == NULL || |
|
m_parent->msgTypeEnabledWithLock(CAMERA_MSG_COMPRESSED_IMAGE) == 0 )) { |
|
LOGW("No dataCB or CAMERA_MSG_COMPRESSED_IMAGE not enabled"); |
|
rc = NO_ERROR; |
|
goto end; |
|
} |
|
|
|
if(evt->status == JPEG_JOB_STATUS_ERROR) { |
|
LOGE("Error event handled from jpeg, status = %d", |
|
evt->status); |
|
rc = FAILED_TRANSACTION; |
|
goto end; |
|
} |
|
if (!mJpegMemOpt) { |
|
jpegData = evt->out_data.buf_vaddr; |
|
} |
|
else { |
|
jpeg_out = (omx_jpeg_ouput_buf_t*) evt->out_data.buf_vaddr; |
|
if (jpeg_out != NULL) { |
|
jpeg_mem = (camera_memory_t *)jpeg_out->mem_hdl; |
|
if (jpeg_mem != NULL) { |
|
jpegData = jpeg_mem->data; |
|
} |
|
} |
|
} |
|
m_parent->dumpJpegToFile(jpegData, |
|
evt->out_data.buf_filled_len, |
|
evt->jobId); |
|
LOGH("Dump jpeg_size=%d", evt->out_data.buf_filled_len); |
|
if(true == m_parent->m_bIntJpegEvtPending) { |
|
//Sending JPEG snapshot taken notification to HAL |
|
pthread_mutex_lock(&m_parent->m_int_lock); |
|
pthread_cond_signal(&m_parent->m_int_cond); |
|
pthread_mutex_unlock(&m_parent->m_int_lock); |
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
|
return rc; |
|
} |
|
if (!mJpegMemOpt) { |
|
// alloc jpeg memory to pass to upper layer |
|
jpeg_mem = m_parent->mGetMemory(-1, evt->out_data.buf_filled_len, |
|
1, m_parent->mCallbackCookie); |
|
if (NULL == jpeg_mem) { |
|
rc = NO_MEMORY; |
|
LOGE("getMemory for jpeg, ret = NO_MEMORY"); |
|
goto end; |
|
} |
|
memcpy(jpeg_mem->data, evt->out_data.buf_vaddr, evt->out_data.buf_filled_len); |
|
} |
|
LOGH("Calling upperlayer callback to store JPEG image"); |
|
qcamera_release_data_t release_data; |
|
memset(&release_data, 0, sizeof(qcamera_release_data_t)); |
|
release_data.data = jpeg_mem; |
|
LOGI("[KPI Perf]: PROFILE_JPEG_CB"); |
|
rc = sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE, |
|
jpeg_mem, |
|
0, |
|
NULL, |
|
&release_data, |
|
frame_idx); |
|
m_parent->setOutputImageCount(m_parent->getOutputImageCount() + 1); |
|
|
|
end: |
|
if (rc != NO_ERROR) { |
|
// send error msg to upper layer |
|
LOGE("Jpeg Encoding failed. Notify Application"); |
|
sendEvtNotify(CAMERA_MSG_ERROR, |
|
UNKNOWN_ERROR, |
|
0); |
|
|
|
if (NULL != jpeg_mem) { |
|
jpeg_mem->release(jpeg_mem); |
|
jpeg_mem = NULL; |
|
} |
|
} |
|
|
|
/* check whether to send callback for depth map */ |
|
if (m_parent->mParameters.isUbiRefocus() && |
|
(m_parent->getOutputImageCount() + 1 == |
|
m_parent->mParameters.getRefocusOutputCount())) { |
|
m_parent->setOutputImageCount(m_parent->getOutputImageCount() + 1); |
|
|
|
jpeg_mem = m_DataMem; |
|
release_data.data = jpeg_mem; |
|
m_DataMem = NULL; |
|
LOGH("[KPI Perf]: send jpeg callback for depthmap "); |
|
rc = sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE, |
|
jpeg_mem, |
|
0, |
|
NULL, |
|
&release_data, |
|
frame_idx); |
|
if (rc != NO_ERROR) { |
|
// send error msg to upper layer |
|
sendEvtNotify(CAMERA_MSG_ERROR, |
|
UNKNOWN_ERROR, |
|
0); |
|
if (NULL != jpeg_mem) { |
|
jpeg_mem->release(jpeg_mem); |
|
jpeg_mem = NULL; |
|
} |
|
} |
|
m_DataMem = NULL; |
|
} |
|
} |
|
|
|
// wait up data proc thread to do next job, |
|
// if previous request is blocked due to ongoing jpeg job |
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
|
|
|
m_parent->m_perfLockMgr.releasePerfLock(PERF_LOCK_TAKE_SNAPSHOT); |
|
|
|
return rc; |
|
} |
|
|
|
/*=========================================================================== |
|
* 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 QCameraPostProcessor::processPPData(mm_camera_super_buf_t *frame) |
|
{ |
|
bool triggerEvent = TRUE; |
|
|
|
LOGD("QCameraPostProcessor::processPPData"); |
|
bool needSuperBufMatch = m_parent->mParameters.generateThumbFromMain(); |
|
if (m_bInited == FALSE) { |
|
LOGE("postproc not initialized yet"); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
bool needHalPP = m_parent->needHALPP(); |
|
LOGH("needHalPP:%d", needHalPP); |
|
|
|
qcamera_pp_data_t *job = (qcamera_pp_data_t *)m_ongoingPPQ.dequeue(); |
|
if (NULL == job) { |
|
LOGE("Cannot find reprocess job"); |
|
return BAD_VALUE; |
|
} |
|
|
|
if (!needSuperBufMatch && (job->src_frame == NULL |
|
|| job->src_reproc_frame == NULL) ) { |
|
LOGE("Invalid reprocess job"); |
|
return BAD_VALUE; |
|
} |
|
|
|
if (!needSuperBufMatch && (m_parent->mParameters.isNV16PictureFormat() || |
|
m_parent->mParameters.isNV21PictureFormat())) { |
|
releaseOngoingPPData(job, this); |
|
free(job); |
|
|
|
if(m_parent->mParameters.isYUVFrameInfoNeeded()) |
|
setYUVFrameInfo(frame); |
|
return processRawData(frame); |
|
} |
|
|
|
#ifdef TARGET_TS_MAKEUP |
|
// find snapshot frame frame |
|
mm_camera_buf_def_t *pReprocFrame = NULL; |
|
QCameraStream * pSnapshotStream = NULL; |
|
QCameraChannel *pChannel = m_parent->getChannelByHandle(frame->ch_id); |
|
if (pChannel == NULL) { |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
if ((mPPChannels[i] != NULL) && |
|
(validate_handle(mPPChannels[i]->getMyHandle(), frame->ch_id))) { |
|
pChannel = mPPChannels[i]; |
|
break; |
|
} |
|
} |
|
} |
|
if (pChannel == NULL) { |
|
LOGE("No corresponding channel (ch_id = %d) exist, return here", |
|
frame->ch_id); |
|
return BAD_VALUE; |
|
} |
|
|
|
for (uint32_t i = 0; i < frame->num_bufs; i++) { |
|
pSnapshotStream = pChannel->getStreamByHandle(frame->bufs[i]->stream_id); |
|
if (pSnapshotStream != NULL) { |
|
if (pSnapshotStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT)) { |
|
pReprocFrame = frame->bufs[i]; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (pReprocFrame != NULL && m_parent->mParameters.isFaceDetectionEnabled()) { |
|
m_parent->TsMakeupProcess_Snapshot(pReprocFrame,pSnapshotStream); |
|
} else { |
|
LOGH("pReprocFrame == NULL || isFaceDetectionEnabled = %d", |
|
m_parent->mParameters.isFaceDetectionEnabled()); |
|
} |
|
#endif |
|
int8_t mCurReprocCount = job->reprocCount; |
|
if ((m_parent->isLongshotEnabled() |
|
&& (!(m_parent->mParameters.getQuadraCfa())|| (mCurReprocCount == 2))) |
|
&& (!m_parent->isCaptureShutterEnabled()) |
|
&& (!m_parent->mCACDoneReceived)) { |
|
// play shutter sound for longshot |
|
// after reprocess is done |
|
m_parent->playShutter(); |
|
} |
|
m_parent->mCACDoneReceived = FALSE; |
|
|
|
int8_t mCurChannelIndex = job->ppChannelIndex; |
|
if ( mCurReprocCount > 1 ) { |
|
//In case of pp 2nd pass, we can release input of 2nd pass |
|
releaseSuperBuf(job->src_frame); |
|
free(job->src_frame); |
|
job->src_frame = NULL; |
|
} |
|
|
|
LOGD("mCurReprocCount = %d mCurChannelIndex = %d mTotalNumReproc = %d", |
|
mCurReprocCount, mCurChannelIndex, |
|
m_parent->mParameters.getReprocCount()); |
|
if (mCurReprocCount < m_parent->mParameters.getReprocCount()) { |
|
//More pp pass needed. Push frame back to pp queue. |
|
qcamera_pp_data_t *pp_request_job = job; |
|
pp_request_job->src_frame = frame; |
|
|
|
if ((mPPChannels[mCurChannelIndex]->getReprocCount() |
|
== mCurReprocCount) && |
|
(mPPChannels[mCurChannelIndex + 1] != NULL)) { |
|
pp_request_job->ppChannelIndex++; |
|
} |
|
|
|
// enqueu to post proc input queue |
|
if (false == m_inputPPQ.enqueue((void *)pp_request_job)) { |
|
LOGW("m_input PP Q is not active!!!"); |
|
releaseOngoingPPData(pp_request_job,this); |
|
free(pp_request_job); |
|
pp_request_job = NULL; |
|
triggerEvent = FALSE; |
|
} |
|
} else if (m_halPP != NULL && needHalPP) { |
|
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)); |
|
hal_pp_job->frame = frame; |
|
hal_pp_job->src_reproc_frame = job ? job->src_reproc_frame : NULL; |
|
hal_pp_job->src_reproc_bufs = job ? job->src_reproc_bufs : NULL; |
|
hal_pp_job->reproc_frame_release = job ? job->reproc_frame_release : false; |
|
hal_pp_job->offline_reproc_buf = job ? job->offline_reproc_buf : NULL; |
|
hal_pp_job->offline_buffer = job ? job->offline_buffer : false; |
|
m_halPP->feedInput(hal_pp_job); |
|
} else { |
|
//Done with post processing. Send frame to Jpeg |
|
qcamera_jpeg_data_t *jpeg_job = |
|
(qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t)); |
|
if (jpeg_job == NULL) { |
|
LOGE("No memory for jpeg job"); |
|
return NO_MEMORY; |
|
} |
|
|
|
memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t)); |
|
jpeg_job->src_frame = frame; |
|
jpeg_job->src_reproc_frame = job ? job->src_reproc_frame : NULL; |
|
jpeg_job->src_reproc_bufs = job ? job->src_reproc_bufs : NULL; |
|
jpeg_job->reproc_frame_release = job ? job->reproc_frame_release : false; |
|
jpeg_job->offline_reproc_buf = job ? job->offline_reproc_buf : NULL; |
|
jpeg_job->offline_buffer = job ? job->offline_buffer : false; |
|
|
|
// find meta data frame |
|
mm_camera_buf_def_t *meta_frame = NULL; |
|
if (m_parent->mParameters.isAdvCamFeaturesEnabled()) { |
|
size_t meta_idx = m_parent->mParameters.getExifBufIndex(m_PPindex); |
|
if (m_InputMetadata.size() >= (meta_idx + 1)) { |
|
meta_frame = m_InputMetadata.itemAt(meta_idx); |
|
} else { |
|
LOGW("Input metadata vector contains %d entries, index required %d", |
|
m_InputMetadata.size(), meta_idx); |
|
} |
|
m_PPindex++; |
|
} else { |
|
for (uint32_t i = 0; job && job->src_reproc_frame && |
|
(i < job->src_reproc_frame->num_bufs); i++) { |
|
// look through input superbuf |
|
if (job->src_reproc_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) { |
|
meta_frame = job->src_reproc_frame->bufs[i]; |
|
break; |
|
} |
|
} |
|
|
|
if (meta_frame == NULL) { |
|
// look through reprocess superbuf |
|
for (uint32_t i = 0; i < frame->num_bufs; i++) { |
|
if (frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) { |
|
meta_frame = frame->bufs[i]; |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
if (meta_frame != NULL) { |
|
// fill in meta data frame ptr |
|
jpeg_job->metadata = (metadata_buffer_t *)meta_frame->buffer; |
|
} |
|
|
|
if (m_parent->mParameters.getQuadraCfa()) { |
|
// find offline metadata frame for quadra CFA |
|
mm_camera_buf_def_t *pOfflineMetaFrame = NULL; |
|
QCameraStream * pOfflineMetadataStream = NULL; |
|
QCameraChannel *pChannel = m_parent->getChannelByHandle(frame->ch_id); |
|
if (pChannel == NULL) { |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
if ((mPPChannels[i] != NULL) && |
|
(mPPChannels[i]->getMyHandle() == frame->ch_id)) { |
|
pChannel = mPPChannels[i]; |
|
break; |
|
} |
|
} |
|
} |
|
if (pChannel == NULL) { |
|
LOGE("No corresponding channel (ch_id = %d) exist, return here", |
|
frame->ch_id); |
|
return BAD_VALUE; |
|
} |
|
|
|
for (uint32_t i = 0; i < frame->num_bufs; i++) { |
|
pOfflineMetadataStream = pChannel->getStreamByHandle(frame->bufs[i]->stream_id); |
|
if (pOfflineMetadataStream != NULL) { |
|
if (pOfflineMetadataStream->isOrignalTypeOf(CAM_STREAM_TYPE_METADATA)) { |
|
pOfflineMetaFrame = frame->bufs[i]; |
|
break; |
|
} |
|
} |
|
} |
|
if (pOfflineMetaFrame != NULL) { |
|
// fill in meta data frame ptr |
|
jpeg_job->metadata = (metadata_buffer_t *)pOfflineMetaFrame->buffer; |
|
|
|
// Dump offline metadata for Tuning |
|
char value[PROPERTY_VALUE_MAX]; |
|
property_get("persist.camera.dumpmetadata", value, "0"); |
|
int32_t enabled = atoi(value); |
|
if (enabled && jpeg_job->metadata->is_tuning_params_valid) { |
|
m_parent->dumpMetadataToFile(pOfflineMetadataStream,pOfflineMetaFrame, |
|
(char *)"Offline_isp_meta"); |
|
} |
|
} |
|
} |
|
|
|
// enqueu reprocessed 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; |
|
triggerEvent = FALSE; |
|
} |
|
|
|
// free pp job buf |
|
pthread_mutex_lock(&m_reprocess_lock); |
|
if (job) { |
|
free(job); |
|
} |
|
pthread_mutex_unlock(&m_reprocess_lock); |
|
} |
|
|
|
LOGD(""); |
|
// wait up data proc thread |
|
|
|
if (triggerEvent) { |
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
|
} |
|
|
|
return NO_ERROR; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : findJpegJobByJobId |
|
* |
|
* DESCRIPTION: find a jpeg job from ongoing Jpeg queue by its job ID |
|
* |
|
* PARAMETERS : |
|
* @jobId : job Id of the job |
|
* |
|
* RETURN : ptr to a jpeg job struct. NULL if not found. |
|
* |
|
* NOTE : Currently only one job is sending to mm-jpeg-interface for jpeg |
|
* encoding. Therefore simply dequeue from the ongoing Jpeg Queue |
|
* will serve the purpose to find the jpeg job. |
|
*==========================================================================*/ |
|
qcamera_jpeg_data_t *QCameraPostProcessor::findJpegJobByJobId(uint32_t jobId) |
|
{ |
|
qcamera_jpeg_data_t * job = NULL; |
|
if (jobId == 0) { |
|
LOGE("not a valid jpeg jobId"); |
|
return NULL; |
|
} |
|
|
|
// currely only one jpeg job ongoing, so simply dequeue the head |
|
job = (qcamera_jpeg_data_t *)m_ongoingJpegQ.dequeue(); |
|
return job; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : releasePPInputData |
|
* |
|
* DESCRIPTION: callback function to release post process input data node |
|
* |
|
* PARAMETERS : |
|
* @data : ptr to post process input data |
|
* @user_data : user data ptr (QCameraReprocessor) |
|
* |
|
* RETURN : None |
|
*==========================================================================*/ |
|
void QCameraPostProcessor::releasePPInputData(void *data, void *user_data) |
|
{ |
|
QCameraPostProcessor *pme = (QCameraPostProcessor *)user_data; |
|
if (NULL != pme) { |
|
qcamera_pp_request_t *pp_job = (qcamera_pp_request_t *)data; |
|
if (NULL != pp_job->src_frame) { |
|
pme->releaseSuperBuf(pp_job->src_frame); |
|
if (pp_job->src_frame == pp_job->src_reproc_frame) |
|
pp_job->src_reproc_frame = NULL; |
|
free(pp_job->src_frame); |
|
pp_job->src_frame = NULL; |
|
} |
|
if (NULL != pp_job->src_reproc_frame) { |
|
pme->releaseSuperBuf(pp_job->src_reproc_frame); |
|
free(pp_job->src_reproc_frame); |
|
pp_job->src_reproc_frame = NULL; |
|
} |
|
pp_job->reprocCount = 0; |
|
} |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : releaseJpegData |
|
* |
|
* DESCRIPTION: callback function to release jpeg job node |
|
* |
|
* PARAMETERS : |
|
* @data : ptr to ongoing jpeg job data |
|
* @user_data : user data ptr (QCameraReprocessor) |
|
* |
|
* RETURN : None |
|
*==========================================================================*/ |
|
void QCameraPostProcessor::releaseJpegData(void *data, void *user_data) |
|
{ |
|
QCameraPostProcessor *pme = (QCameraPostProcessor *)user_data; |
|
if (NULL != pme) { |
|
pme->releaseJpegJobData((qcamera_jpeg_data_t *)data); |
|
LOGH("Rleased job ID %u", |
|
((qcamera_jpeg_data_t *)data)->jobId); |
|
} |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : releaseOngoingPPData |
|
* |
|
* DESCRIPTION: callback function to release ongoing postprocess job node |
|
* |
|
* PARAMETERS : |
|
* @data : ptr to onging postprocess job |
|
* @user_data : user data ptr (QCameraReprocessor) |
|
* |
|
* RETURN : None |
|
*==========================================================================*/ |
|
void QCameraPostProcessor::releaseOngoingPPData(void *data, void *user_data) |
|
{ |
|
QCameraPostProcessor *pme = (QCameraPostProcessor *)user_data; |
|
if (NULL != pme) { |
|
qcamera_pp_data_t *pp_job = (qcamera_pp_data_t *)data; |
|
if (NULL != pp_job->src_frame) { |
|
if (!pp_job->reproc_frame_release) { |
|
pme->releaseSuperBuf(pp_job->src_frame); |
|
} |
|
if (pp_job->src_frame == pp_job->src_reproc_frame) |
|
pp_job->src_reproc_frame = NULL; |
|
|
|
free(pp_job->src_frame); |
|
pp_job->src_frame = NULL; |
|
} |
|
if (NULL != pp_job->src_reproc_frame) { |
|
pme->releaseSuperBuf(pp_job->src_reproc_frame); |
|
free(pp_job->src_reproc_frame); |
|
pp_job->src_reproc_frame = NULL; |
|
} |
|
if ((pp_job->offline_reproc_buf != NULL) |
|
&& (pp_job->offline_buffer)) { |
|
free(pp_job->offline_reproc_buf); |
|
pp_job->offline_buffer = false; |
|
} |
|
pp_job->reprocCount = 0; |
|
} |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : releaseNotifyData |
|
* |
|
* DESCRIPTION: function to release internal resources in notify data struct |
|
* |
|
* PARAMETERS : |
|
* @user_data : ptr user data |
|
* @cookie : callback cookie |
|
* @cb_status : callback status |
|
* |
|
* RETURN : None |
|
* |
|
* NOTE : deallocate jpeg heap memory if it's not NULL |
|
*==========================================================================*/ |
|
void QCameraPostProcessor::releaseNotifyData(void *user_data, |
|
void *cookie, |
|
int32_t cb_status) |
|
{ |
|
LOGD("releaseNotifyData release_data %p", user_data); |
|
|
|
qcamera_data_argm_t *app_cb = ( qcamera_data_argm_t * ) user_data; |
|
QCameraPostProcessor *postProc = ( QCameraPostProcessor * ) cookie; |
|
if ( ( NULL != app_cb ) && ( NULL != postProc ) ) { |
|
|
|
if ( postProc->mUseSaveProc && |
|
app_cb->release_data.unlinkFile && |
|
( NO_ERROR != cb_status ) ) { |
|
|
|
String8 unlinkPath((const char *) app_cb->release_data.data->data, |
|
app_cb->release_data.data->size); |
|
int rc = unlink(unlinkPath.string()); |
|
LOGH("Unlinking stored file rc = %d", |
|
rc); |
|
} |
|
|
|
if (app_cb && NULL != app_cb->release_data.data) { |
|
app_cb->release_data.data->release(app_cb->release_data.data); |
|
app_cb->release_data.data = NULL; |
|
} |
|
if (app_cb && NULL != app_cb->release_data.frame) { |
|
postProc->releaseSuperBuf(app_cb->release_data.frame); |
|
free(app_cb->release_data.frame); |
|
app_cb->release_data.frame = NULL; |
|
} |
|
if (app_cb && NULL != app_cb->release_data.streamBufs) { |
|
app_cb->release_data.streamBufs->deallocate(); |
|
delete app_cb->release_data.streamBufs; |
|
app_cb->release_data.streamBufs = NULL; |
|
} |
|
free(app_cb); |
|
} |
|
} |
|
|
|
/*=========================================================================== |
|
* 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 QCameraPostProcessor::releaseSuperBuf(mm_camera_super_buf_t *super_buf) |
|
{ |
|
QCameraChannel *pChannel = NULL; |
|
|
|
if (NULL != super_buf) { |
|
pChannel = m_parent->getChannelByHandle(super_buf->ch_id); |
|
|
|
if ( NULL == pChannel ) { |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
if ((mPPChannels[i] != NULL) && |
|
(validate_handle(mPPChannels[i]->getMyHandle(), |
|
super_buf->ch_id))) { |
|
pChannel = mPPChannels[i]; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (pChannel != NULL) { |
|
pChannel->bufDone(super_buf); |
|
} else { |
|
LOGE("Channel id %d not found!!", |
|
super_buf->ch_id); |
|
} |
|
} |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : releaseSuperBuf |
|
* |
|
* DESCRIPTION : function to release a superbuf frame by returning back to kernel |
|
* |
|
* PARAMETERS : |
|
* @super_buf : ptr to the superbuf frame |
|
* @stream_type: Type of stream to be released |
|
* |
|
* RETURN : None |
|
*==========================================================================*/ |
|
void QCameraPostProcessor::releaseSuperBuf(mm_camera_super_buf_t *super_buf, |
|
cam_stream_type_t stream_type) |
|
{ |
|
QCameraChannel *pChannel = NULL; |
|
|
|
if (NULL != super_buf) { |
|
pChannel = m_parent->getChannelByHandle(super_buf->ch_id); |
|
if (pChannel == NULL) { |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
if ((mPPChannels[i] != NULL) && |
|
(validate_handle(mPPChannels[i]->getMyHandle(), |
|
super_buf->ch_id))) { |
|
pChannel = mPPChannels[i]; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (pChannel != NULL) { |
|
for (uint32_t i = 0; i < super_buf->num_bufs; i++) { |
|
if (super_buf->bufs[i] != NULL) { |
|
QCameraStream *pStream = |
|
pChannel->getStreamByHandle(super_buf->bufs[i]->stream_id); |
|
if ((pStream != NULL) && ((pStream->getMyType() == stream_type) |
|
|| (pStream->getMyOriginalType() == stream_type))) { |
|
pChannel->bufDone(super_buf, super_buf->bufs[i]->stream_id); |
|
break; |
|
} |
|
} |
|
} |
|
} else { |
|
LOGE("Channel id %d not found!!", |
|
super_buf->ch_id); |
|
} |
|
} |
|
} |
|
|
|
/*=========================================================================== |
|
* 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 QCameraPostProcessor::releaseJpegJobData(qcamera_jpeg_data_t *job) |
|
{ |
|
LOGD("E"); |
|
if (NULL != job) { |
|
if (NULL != job->src_reproc_frame) { |
|
if (!job->reproc_frame_release) { |
|
releaseSuperBuf(job->src_reproc_frame); |
|
} |
|
free(job->src_reproc_frame); |
|
job->src_reproc_frame = NULL; |
|
} |
|
|
|
if (NULL != job->src_frame) { |
|
if (!job->halPPAllocatedBuf) { |
|
releaseSuperBuf(job->src_frame); |
|
} else { |
|
// frame heap buffer was allocated for HAL PP |
|
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->pJpegExifObj) { |
|
delete job->pJpegExifObj; |
|
job->pJpegExifObj = NULL; |
|
} |
|
|
|
if (NULL != job->src_reproc_bufs) { |
|
delete [] job->src_reproc_bufs; |
|
} |
|
|
|
if ((job->offline_reproc_buf != NULL) |
|
&& (job->offline_buffer)) { |
|
free(job->offline_reproc_buf); |
|
job->offline_buffer = false; |
|
} |
|
} |
|
LOGD("X"); |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : releaseSaveJobData |
|
* |
|
* DESCRIPTION: function to release internal resources in store jobs |
|
* |
|
* PARAMETERS : |
|
* @job : ptr to save job struct |
|
* |
|
* RETURN : None |
|
* |
|
*==========================================================================*/ |
|
void QCameraPostProcessor::releaseSaveJobData(void *data, void *user_data) |
|
{ |
|
LOGD("E"); |
|
|
|
QCameraPostProcessor *pme = (QCameraPostProcessor *) user_data; |
|
if (NULL == pme) { |
|
LOGE("Invalid postproc handle"); |
|
return; |
|
} |
|
|
|
qcamera_jpeg_evt_payload_t *job_data = (qcamera_jpeg_evt_payload_t *) data; |
|
if (job_data == NULL) { |
|
LOGE("Invalid jpeg event data"); |
|
return; |
|
} |
|
|
|
// find job by jobId |
|
qcamera_jpeg_data_t *job = pme->findJpegJobByJobId(job_data->jobId); |
|
|
|
if (NULL != job) { |
|
pme->releaseJpegJobData(job); |
|
free(job); |
|
} else { |
|
LOGE("Invalid jpeg job"); |
|
} |
|
|
|
LOGD("X"); |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : releaseRawData |
|
* |
|
* DESCRIPTION: function to release internal resources in store jobs |
|
* |
|
* PARAMETERS : |
|
* @job : ptr to save job struct |
|
* |
|
* RETURN : None |
|
* |
|
*==========================================================================*/ |
|
void QCameraPostProcessor::releaseRawData(void *data, void *user_data) |
|
{ |
|
LOGD("E"); |
|
|
|
QCameraPostProcessor *pme = (QCameraPostProcessor *) user_data; |
|
if (NULL == pme) { |
|
LOGE("Invalid postproc handle"); |
|
return; |
|
} |
|
mm_camera_super_buf_t *super_buf = (mm_camera_super_buf_t *) data; |
|
pme->releaseSuperBuf(super_buf); |
|
|
|
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 QCameraPostProcessor::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; |
|
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 QCameraPostProcessor::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 : queryStreams |
|
* |
|
* DESCRIPTION: utility method for retrieving main, thumbnail and reprocess |
|
* streams and frame from bundled super buffer |
|
* |
|
* PARAMETERS : |
|
* @main : ptr to main stream if present |
|
* @thumb : ptr to thumbnail stream if present |
|
* @reproc : ptr to reprocess stream if present |
|
* @main_image : ptr to main image if present |
|
* @thumb_image: ptr to thumbnail image if present |
|
* @frame : bundled super buffer |
|
* @reproc_frame : bundled source frame buffer |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::queryStreams(QCameraStream **main, |
|
QCameraStream **thumb, |
|
QCameraStream **reproc, |
|
mm_camera_buf_def_t **main_image, |
|
mm_camera_buf_def_t **thumb_image, |
|
mm_camera_super_buf_t *frame, |
|
mm_camera_super_buf_t *reproc_frame) |
|
{ |
|
if (NULL == frame) { |
|
return NO_INIT; |
|
} |
|
|
|
QCameraChannel *pChannel = m_parent->getChannelByHandle(frame->ch_id); |
|
// check reprocess channel if not found |
|
if (pChannel == NULL) { |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
if ((mPPChannels[i] != NULL) && |
|
validate_handle(mPPChannels[i]->getMyHandle(), frame->ch_id)) { |
|
pChannel = mPPChannels[i]; |
|
break; |
|
} |
|
} |
|
} |
|
if (pChannel == NULL) { |
|
LOGD("No corresponding channel (ch_id = %d) exist, return here", |
|
frame->ch_id); |
|
return BAD_VALUE; |
|
} |
|
|
|
// Use snapshot stream to create thumbnail if snapshot and preview |
|
// flip settings doesn't match in ZSL mode. |
|
bool thumb_stream_needed = ((!m_parent->isZSLMode() || |
|
(m_parent->mParameters.getFlipMode(CAM_STREAM_TYPE_SNAPSHOT) == |
|
m_parent->mParameters.getFlipMode(CAM_STREAM_TYPE_PREVIEW))) && |
|
!m_parent->mParameters.generateThumbFromMain()); |
|
|
|
*main = *thumb = *reproc = NULL; |
|
*main_image = *thumb_image = NULL; |
|
// find snapshot frame and thumnail frame |
|
for (uint32_t i = 0; i < frame->num_bufs; i++) { |
|
QCameraStream *pStream = |
|
pChannel->getStreamByHandle(frame->bufs[i]->stream_id); |
|
if (pStream != NULL) { |
|
if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) || |
|
pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT) || |
|
pStream->isTypeOf(CAM_STREAM_TYPE_VIDEO) || |
|
pStream->isOrignalTypeOf(CAM_STREAM_TYPE_VIDEO) || |
|
pStream->isOrignalTypeOf(CAM_STREAM_TYPE_RAW)) { |
|
*main= pStream; |
|
*main_image = frame->bufs[i]; |
|
} else if (thumb_stream_needed && |
|
(pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) || |
|
pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) || |
|
pStream->isOrignalTypeOf(CAM_STREAM_TYPE_PREVIEW) || |
|
pStream->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW))) { |
|
*thumb = pStream; |
|
*thumb_image = frame->bufs[i]; |
|
} |
|
if (pStream->isTypeOf(CAM_STREAM_TYPE_OFFLINE_PROC) ) { |
|
*reproc = pStream; |
|
} |
|
} |
|
} |
|
|
|
if (thumb_stream_needed && *thumb_image == NULL && reproc_frame != NULL) { |
|
QCameraChannel *pSrcReprocChannel = NULL; |
|
pSrcReprocChannel = m_parent->getChannelByHandle(reproc_frame->ch_id); |
|
if (pSrcReprocChannel != NULL) { |
|
// find thumbnail frame |
|
for (uint32_t i = 0; i < reproc_frame->num_bufs; i++) { |
|
QCameraStream *pStream = |
|
pSrcReprocChannel->getStreamByHandle( |
|
reproc_frame->bufs[i]->stream_id); |
|
if (pStream != NULL) { |
|
if (pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) || |
|
pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW)) { |
|
*thumb = pStream; |
|
*thumb_image = reproc_frame->bufs[i]; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
return NO_ERROR; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : syncStreamParams |
|
* |
|
* DESCRIPTION: Query the runtime parameters of all streams included |
|
* in the main and reprocessed frames |
|
* |
|
* PARAMETERS : |
|
* @frame : Main image super buffer |
|
* @reproc_frame : Image supper buffer that got processed |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::syncStreamParams(mm_camera_super_buf_t *frame, |
|
mm_camera_super_buf_t *reproc_frame) |
|
{ |
|
QCameraStream *reproc_stream = NULL; |
|
QCameraStream *main_stream = NULL; |
|
QCameraStream *thumb_stream = NULL; |
|
mm_camera_buf_def_t *main_frame = NULL; |
|
mm_camera_buf_def_t *thumb_frame = NULL; |
|
int32_t ret = NO_ERROR; |
|
|
|
ret = queryStreams(&main_stream, |
|
&thumb_stream, |
|
&reproc_stream, |
|
&main_frame, |
|
&thumb_frame, |
|
frame, |
|
reproc_frame); |
|
if (NO_ERROR != ret) { |
|
LOGE("Camera streams query from input frames failed %d", |
|
ret); |
|
return ret; |
|
} |
|
|
|
if (NULL != main_stream) { |
|
ret = main_stream->syncRuntimeParams(); |
|
if (NO_ERROR != ret) { |
|
LOGE("Syncing of main stream runtime parameters failed %d", |
|
ret); |
|
return ret; |
|
} |
|
} |
|
|
|
if (NULL != thumb_stream) { |
|
ret = thumb_stream->syncRuntimeParams(); |
|
if (NO_ERROR != ret) { |
|
LOGE("Syncing of thumb stream runtime parameters failed %d", |
|
ret); |
|
return ret; |
|
} |
|
} |
|
|
|
if ((NULL != reproc_stream) && (reproc_stream != main_stream)) { |
|
ret = reproc_stream->syncRuntimeParams(); |
|
if (NO_ERROR != ret) { |
|
LOGE("Syncing of reproc stream runtime parameters failed %d", |
|
ret); |
|
return ret; |
|
} |
|
} |
|
|
|
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 QCameraPostProcessor::encodeData(qcamera_jpeg_data_t *jpeg_job_data, |
|
uint8_t &needNewSess) |
|
{ |
|
int32_t ret = NO_ERROR; |
|
mm_jpeg_job_t jpg_job; |
|
uint32_t jobId = 0; |
|
QCameraStream *reproc_stream = NULL; |
|
QCameraStream *main_stream = NULL; |
|
mm_camera_buf_def_t *main_frame = NULL; |
|
QCameraStream *thumb_stream = NULL; |
|
mm_camera_buf_def_t *thumb_frame = NULL; |
|
mm_camera_super_buf_t *recvd_frame = jpeg_job_data->src_frame; |
|
cam_rect_t crop; |
|
cam_stream_parm_buffer_t param; |
|
cam_stream_img_prop_t imgProp; |
|
bool is_halpp_output_buf = jpeg_job_data->halPPAllocatedBuf; |
|
|
|
LOGD("E, need new session:%d, is halpp output:%d", needNewSess, is_halpp_output_buf); |
|
|
|
if (!is_halpp_output_buf) { |
|
// find channel |
|
QCameraChannel *pChannel = m_parent->getChannelByHandle(recvd_frame->ch_id); |
|
// check reprocess channel if not found |
|
if (pChannel == NULL) { |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
if ((mPPChannels[i] != NULL) && |
|
(validate_handle(mPPChannels[i]->getMyHandle(), recvd_frame->ch_id))) { |
|
pChannel = mPPChannels[i]; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (pChannel == NULL) { |
|
LOGE("No corresponding channel (ch_id = %d) exist, return here", |
|
recvd_frame->ch_id); |
|
return BAD_VALUE; |
|
} |
|
|
|
ret = queryStreams(&main_stream, |
|
&thumb_stream, |
|
&reproc_stream, |
|
&main_frame, |
|
&thumb_frame, |
|
recvd_frame, |
|
jpeg_job_data->src_reproc_frame); |
|
if (NO_ERROR != ret) { |
|
return ret; |
|
} |
|
|
|
if(NULL == main_frame){ |
|
LOGE("Main frame is NULL"); |
|
return BAD_VALUE; |
|
} |
|
|
|
if(NULL == thumb_frame){ |
|
LOGD("Thumbnail frame does not exist"); |
|
} |
|
|
|
QCameraMemory *memObj = (QCameraMemory *)main_frame->mem_info; |
|
if (NULL == memObj) { |
|
LOGE("Memeory Obj of main frame is NULL"); |
|
return NO_MEMORY; |
|
} |
|
|
|
// dump snapshot frame if enabled |
|
m_parent->dumpFrameToFile(main_stream, main_frame, |
|
QCAMERA_DUMP_FRM_INPUT_JPEG, (char *)"CPP"); |
|
|
|
// send upperlayer callback for raw image |
|
camera_memory_t *mem = memObj->getMemory(main_frame->buf_idx, false); |
|
if (NULL != m_parent->mDataCb && |
|
m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE) > 0) { |
|
qcamera_callback_argm_t cbArg; |
|
memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); |
|
cbArg.cb_type = QCAMERA_DATA_CALLBACK; |
|
cbArg.msg_type = CAMERA_MSG_RAW_IMAGE; |
|
cbArg.data = mem; |
|
cbArg.index = 0; |
|
// Data callback, set read/write flags |
|
main_frame->cache_flags |= CPU_HAS_READ; |
|
m_parent->m_cbNotifier.notifyCallback(cbArg); |
|
} |
|
if (NULL != m_parent->mNotifyCb && |
|
m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE_NOTIFY) > 0) { |
|
qcamera_callback_argm_t cbArg; |
|
memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); |
|
cbArg.cb_type = QCAMERA_NOTIFY_CALLBACK; |
|
cbArg.msg_type = CAMERA_MSG_RAW_IMAGE_NOTIFY; |
|
cbArg.ext1 = 0; |
|
cbArg.ext2 = 0; |
|
m_parent->m_cbNotifier.notifyCallback(cbArg); |
|
} |
|
} else { |
|
/* we only need to care about src frame here for HAL PP output data */ |
|
LOGD("channle id:%d, stream type:%d", jpeg_job_data->src_frame->ch_id, |
|
jpeg_job_data->hal_pp_bufs[0].stream_type); |
|
|
|
QCameraChannel *pChannel = getChannelByHandle(jpeg_job_data->src_frame->ch_id); |
|
if (pChannel == NULL) { |
|
LOGE("Cannot find channel"); |
|
return -1; |
|
} |
|
|
|
// we use the stream info from reproc stream (type 9) |
|
main_stream = pChannel->getStreamByHandle(jpeg_job_data->src_frame->bufs[0]->stream_id); |
|
if (main_stream == NULL) { |
|
LOGE("main_stream is NULL, encode hal PP output failed"); |
|
return BAD_VALUE; |
|
} |
|
LOGD("stream type:%d, stream original type:%d", main_stream->getMyType(), |
|
main_stream->getMyOriginalType()); |
|
|
|
/* currently we use postproc channel stream info */ |
|
/* if we need to output different dim of hal pp out, we need modify here */ |
|
cam_dimension_t hal_pp_out_dim; |
|
main_stream->getFrameDimension(hal_pp_out_dim); |
|
LOGD("stream dimesion:%dx%d", hal_pp_out_dim.width, hal_pp_out_dim.height); |
|
|
|
recvd_frame = jpeg_job_data->src_frame; |
|
main_frame = jpeg_job_data->src_frame->bufs[0]; |
|
if(main_frame == NULL){ |
|
LOGE("Main frame is NULL"); |
|
return BAD_VALUE; |
|
} |
|
// dump snapshot frame if enabled |
|
m_parent->dumpFrameToFile(main_stream, main_frame, |
|
QCAMERA_DUMP_FRM_INPUT_JPEG, (char *)"HALPP"); |
|
|
|
} |
|
|
|
|
|
if (mJpegClientHandle <= 0) { |
|
LOGE("Error: bug here, mJpegClientHandle is 0"); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
if ((pJpegSrcStream != NULL) && |
|
(!validate_handle(pJpegSrcStream->getMyHandle(), |
|
main_stream->getMyHandle()))) { |
|
if (mJpegSessionId) { |
|
mJpegHandle.destroy_session(mJpegSessionId); |
|
mJpegSessionId = 0; |
|
} |
|
pJpegSrcStream = NULL; |
|
mNewJpegSessionNeeded = TRUE; |
|
} |
|
if (needNewSess) { |
|
// create jpeg encoding session |
|
if (mJpegSessionId) { |
|
mJpegHandle.destroy_session(mJpegSessionId); |
|
mJpegSessionId = 0; |
|
} |
|
mm_jpeg_encode_params_t encodeParam; |
|
memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t)); |
|
if (!is_halpp_output_buf) { |
|
ret = getJpegEncodingConfig(encodeParam, main_stream, thumb_stream); |
|
} else { |
|
LOGH("get jpeg encode config for hal pp output"); |
|
ret = getJpegEncodingConfig(encodeParam, main_stream, NULL, jpeg_job_data->src_frame); |
|
} |
|
if (ret != NO_ERROR) { |
|
LOGE("error getting encoding config"); |
|
return ret; |
|
} |
|
LOGH("[KPI Perf] : call jpeg create_session"); |
|
if (!is_halpp_output_buf) { |
|
ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId); |
|
} else { |
|
ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionIdHalPP); |
|
} |
|
if (ret != NO_ERROR) { |
|
LOGE("error creating a new jpeg encoding session"); |
|
return ret; |
|
} |
|
needNewSess = FALSE; |
|
pJpegSrcStream = main_stream; |
|
} |
|
|
|
// Fill in new job |
|
memset(&jpg_job, 0, sizeof(mm_jpeg_job_t)); |
|
jpg_job.job_type = JPEG_JOB_TYPE_ENCODE; |
|
if (!is_halpp_output_buf) { |
|
jpg_job.encode_job.session_id = mJpegSessionId; |
|
} else { |
|
jpg_job.encode_job.session_id = mJpegSessionIdHalPP; |
|
} |
|
jpg_job.encode_job.src_index = (int32_t)main_frame->buf_idx; |
|
jpg_job.encode_job.dst_index = 0; |
|
|
|
if (mJpegMemOpt) { |
|
jpg_job.encode_job.dst_index = jpg_job.encode_job.src_index; |
|
} else if (mUseJpegBurst) { |
|
jpg_job.encode_job.dst_index = -1; |
|
} |
|
|
|
LOGD("jpeg session id:%d, reproc frame:%p", jpg_job.encode_job.session_id, |
|
jpeg_job_data->src_reproc_frame); |
|
|
|
if (jpg_job.encode_job.session_id == 0) { |
|
LOGE("invalid jpeg session id!"); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
// use src to reproc frame as work buffer; if src buf is not available |
|
// jpeg interface will allocate work buffer |
|
if (jpeg_job_data->src_reproc_frame != NULL) { |
|
int32_t ret = NO_ERROR; |
|
QCameraStream *main_stream = NULL; |
|
mm_camera_buf_def_t *main_frame = NULL; |
|
QCameraStream *thumb_stream = NULL; |
|
mm_camera_buf_def_t *thumb_frame = NULL; |
|
QCameraStream *reproc_stream = NULL; |
|
mm_camera_buf_def_t *workBuf = NULL; |
|
// Call queryStreams to fetch source of reproc frame |
|
ret = queryStreams(&main_stream, |
|
&thumb_stream, |
|
&reproc_stream, |
|
&main_frame, |
|
&thumb_frame, |
|
jpeg_job_data->src_reproc_frame, |
|
NULL); |
|
|
|
if ((NO_ERROR == ret) && ((workBuf = main_frame) != NULL) |
|
&& !m_parent->isLowPowerMode()) { |
|
camera_memory_t *camWorkMem = NULL; |
|
int workBufIndex = workBuf->buf_idx; |
|
QCameraMemory *workMem = (QCameraMemory *)workBuf->mem_info; |
|
if (workMem != NULL) { |
|
camWorkMem = workMem->getMemory(workBufIndex, false); |
|
} |
|
if (camWorkMem != NULL && workMem != NULL) { |
|
jpg_job.encode_job.work_buf.buf_size = camWorkMem->size; |
|
jpg_job.encode_job.work_buf.buf_vaddr = (uint8_t *)camWorkMem->data; |
|
jpg_job.encode_job.work_buf.fd = workMem->getFd(workBufIndex); |
|
workMem->invalidateCache(workBufIndex); |
|
} |
|
} |
|
} |
|
|
|
cam_dimension_t src_dim; |
|
memset(&src_dim, 0, sizeof(cam_dimension_t)); |
|
main_stream->getFrameDimension(src_dim); |
|
|
|
bool hdr_output_crop = m_parent->mParameters.isHDROutputCropEnabled(); |
|
bool img_feature_enabled = |
|
m_parent->mParameters.isUbiFocusEnabled() || |
|
m_parent->mParameters.isUbiRefocus() || |
|
m_parent->mParameters.isChromaFlashEnabled() || |
|
m_parent->mParameters.isOptiZoomEnabled() || |
|
m_parent->mParameters.isStillMoreEnabled(); |
|
|
|
LOGH("Crop needed %d", img_feature_enabled); |
|
crop.left = 0; |
|
crop.top = 0; |
|
crop.height = src_dim.height; |
|
crop.width = src_dim.width; |
|
|
|
param = main_stream->getOutputCrop(); |
|
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 (img_feature_enabled) { |
|
memset(¶m, 0, sizeof(cam_stream_parm_buffer_t)); |
|
|
|
param = main_stream->getImgProp(); |
|
imgProp = param.imgProp; |
|
main_stream->setCropInfo(imgProp.crop); |
|
crop = imgProp.crop; |
|
thumb_stream = NULL; /* use thumbnail from main image */ |
|
|
|
if ((reproc_stream != NULL) && (m_DataMem == NULL) && |
|
m_parent->mParameters.isUbiRefocus()) { |
|
|
|
QCameraHeapMemory* miscBufHandler = reproc_stream->getMiscBuf(); |
|
cam_misc_buf_t* refocusResult = |
|
reinterpret_cast<cam_misc_buf_t *>(miscBufHandler->getPtr(0)); |
|
uint32_t resultSize = refocusResult->header_size + |
|
refocusResult->width * refocusResult->height; |
|
camera_memory_t *dataMem = m_parent->mGetMemory(-1, resultSize, |
|
1, m_parent->mCallbackCookie); |
|
|
|
LOGH("Refocus result header %u dims %dx%d", |
|
resultSize, refocusResult->width, refocusResult->height); |
|
|
|
if (dataMem && dataMem->data) { |
|
memcpy(dataMem->data, refocusResult->data, resultSize); |
|
//save mem pointer for depth map |
|
m_DataMem = dataMem; |
|
} |
|
} |
|
} else if ((reproc_stream != NULL) && (m_parent->mParameters.isTruePortraitEnabled())) { |
|
|
|
QCameraHeapMemory* miscBufHandler = reproc_stream->getMiscBuf(); |
|
cam_misc_buf_t* tpResult = |
|
reinterpret_cast<cam_misc_buf_t *>(miscBufHandler->getPtr(0)); |
|
uint32_t tpMetaSize = tpResult->header_size + tpResult->width * tpResult->height; |
|
|
|
LOGH("True portrait result header %d% dims dx%d", |
|
tpMetaSize, tpResult->width, tpResult->height); |
|
|
|
CAM_DUMP_TO_FILE(QCAMERA_DUMP_FRM_LOCATION"tp", "bm", -1, "y", |
|
&tpResult->data, tpMetaSize); |
|
} |
|
|
|
cam_dimension_t dst_dim; |
|
|
|
if (hdr_output_crop && crop.height) { |
|
dst_dim.height = crop.height; |
|
} else { |
|
dst_dim.height = src_dim.height; |
|
} |
|
if (hdr_output_crop && crop.width) { |
|
dst_dim.width = crop.width; |
|
} else { |
|
dst_dim.width = src_dim.width; |
|
} |
|
|
|
// main dim |
|
jpg_job.encode_job.main_dim.src_dim = src_dim; |
|
jpg_job.encode_job.main_dim.dst_dim = dst_dim; |
|
jpg_job.encode_job.main_dim.crop = crop; |
|
|
|
// get 3a sw version info |
|
cam_q3a_version_t sw_version = |
|
m_parent->getCamHalCapabilities()->q3a_version; |
|
|
|
// get exif data |
|
QCameraExif *pJpegExifObj = m_parent->getExifData(); |
|
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; |
|
} |
|
|
|
// set rotation only when no online rotation or offline pp rotation is done before |
|
uint32_t jpeg_rotation = m_parent->mParameters.getJpegRotation(); |
|
if (!m_parent->needRotationReprocess()) { |
|
jpg_job.encode_job.rotation = jpeg_rotation; |
|
} |
|
LOGH("jpeg rotation is set to %d", jpg_job.encode_job.rotation); |
|
|
|
// thumbnail dim |
|
if (m_bThumbnailNeeded == TRUE) { |
|
m_parent->getThumbnailSize(jpg_job.encode_job.thumb_dim.dst_dim); |
|
|
|
if (thumb_stream == NULL) { |
|
// need jpeg thumbnail, but no postview/preview stream exists |
|
// we use the main stream/frame to encode thumbnail |
|
thumb_stream = main_stream; |
|
thumb_frame = main_frame; |
|
} |
|
if (m_parent->needRotationReprocess() && |
|
((90 == jpeg_rotation) || (270 == jpeg_rotation))) { |
|
// swap thumbnail dimensions |
|
cam_dimension_t tmp_dim = jpg_job.encode_job.thumb_dim.dst_dim; |
|
jpg_job.encode_job.thumb_dim.dst_dim.width = tmp_dim.height; |
|
jpg_job.encode_job.thumb_dim.dst_dim.height = tmp_dim.width; |
|
} |
|
|
|
memset(&src_dim, 0, sizeof(cam_dimension_t)); |
|
thumb_stream->getFrameDimension(src_dim); |
|
jpg_job.encode_job.thumb_dim.src_dim = src_dim; |
|
|
|
// crop is the same if frame is the same |
|
if (thumb_frame != main_frame) { |
|
crop.left = 0; |
|
crop.top = 0; |
|
crop.height = src_dim.height; |
|
crop.width = src_dim.width; |
|
|
|
param = thumb_stream->getOutputCrop(); |
|
for (int i = 0; i < param.outputCrop.num_of_streams; i++) { |
|
if (param.outputCrop.crop_info[i].stream_id |
|
== thumb_stream->getMyServerID()) { |
|
crop = param.outputCrop.crop_info[i].crop; |
|
thumb_stream->setCropInfo(crop); |
|
} |
|
} |
|
} |
|
|
|
|
|
jpg_job.encode_job.thumb_dim.crop = crop; |
|
if (thumb_frame != NULL) { |
|
jpg_job.encode_job.thumb_index = thumb_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)", |
|
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); |
|
|
|
if (thumb_frame != NULL) { |
|
// dump thumbnail frame if enabled |
|
m_parent->dumpFrameToFile(thumb_stream, thumb_frame, QCAMERA_DUMP_FRM_THUMBNAIL); |
|
} |
|
|
|
if (jpeg_job_data->metadata != NULL) { |
|
// fill in meta data frame ptr |
|
jpg_job.encode_job.p_metadata = jpeg_job_data->metadata; |
|
} |
|
|
|
jpg_job.encode_job.hal_version = CAM_HAL_V1; |
|
m_parent->mExifParams.sensor_params.sens_type = m_parent->getSensorType(); |
|
jpg_job.encode_job.cam_exif_params = m_parent->mExifParams; |
|
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 = m_parent->mParameters.getMobicatMask(); |
|
|
|
|
|
if (NULL != jpg_job.encode_job.p_metadata && (jpg_job.encode_job.mobicat_mask > 0)) { |
|
|
|
if (m_parent->mExifParams.debug_params) { |
|
memcpy(jpg_job.encode_job.cam_exif_params.debug_params, |
|
m_parent->mExifParams.debug_params, (sizeof(mm_jpeg_debug_exif_params_t))); |
|
|
|
/* Save a copy of mobicat params */ |
|
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; |
|
} |
|
|
|
/* 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; |
|
} |
|
} |
|
|
|
} |
|
|
|
/* Init the QTable */ |
|
for (int i = 0; i < QTABLE_MAX; i++) { |
|
jpg_job.encode_job.qtable_set[i] = 0; |
|
} |
|
|
|
const cam_sync_related_sensors_event_info_t* related_cam_info = |
|
m_parent->getRelatedCamSyncInfo(); |
|
if (related_cam_info->sync_control == CAM_SYNC_RELATED_SENSORS_ON && |
|
m_parent->getMpoComposition()) { |
|
jpg_job.encode_job.multi_image_info.type = MM_JPEG_TYPE_MPO; |
|
if (related_cam_info->type == CAM_TYPE_MAIN ) { |
|
jpg_job.encode_job.multi_image_info.is_primary = TRUE; |
|
LOGD("Encoding MPO Primary JPEG"); |
|
} else { |
|
jpg_job.encode_job.multi_image_info.is_primary = FALSE; |
|
LOGD("Encoding MPO Aux JPEG"); |
|
} |
|
jpg_job.encode_job.multi_image_info.num_of_images = 2; |
|
} else { |
|
LOGD("Encoding Single JPEG"); |
|
jpg_job.encode_job.multi_image_info.type = MM_JPEG_TYPE_JPEG; |
|
jpg_job.encode_job.multi_image_info.is_primary = FALSE; |
|
jpg_job.encode_job.multi_image_info.num_of_images = 1; |
|
} |
|
//Do Cache ops before sending to encode |
|
if (main_frame != NULL) { |
|
main_stream->handleCacheOps(main_frame); |
|
} |
|
if ((thumb_stream != NULL) && (thumb_frame != NULL)) { |
|
thumb_stream->handleCacheOps(thumb_frame); |
|
} |
|
|
|
LOGI("[KPI Perf] : PROFILE_JPEG_JOB_START"); |
|
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; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : processRawImageImpl |
|
* |
|
* DESCRIPTION: function to send raw image to upper layer |
|
* |
|
* PARAMETERS : |
|
* @recvd_frame : frame to be encoded |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::processRawImageImpl(mm_camera_super_buf_t *recvd_frame) |
|
{ |
|
int32_t rc = NO_ERROR; |
|
|
|
QCameraChannel *pChannel = m_parent->getChannelByHandle(recvd_frame->ch_id); |
|
QCameraStream *pStream = NULL; |
|
mm_camera_buf_def_t *frame = NULL; |
|
// check reprocess channel if not found |
|
if (pChannel == NULL) { |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
if ((mPPChannels[i] != NULL) && |
|
(validate_handle(mPPChannels[i]->getMyHandle(), recvd_frame->ch_id))) { |
|
pChannel = mPPChannels[i]; |
|
break; |
|
} |
|
} |
|
} |
|
if (pChannel == NULL) { |
|
LOGE("No corresponding channel (ch_id = %d) exist, return here", |
|
recvd_frame->ch_id); |
|
return BAD_VALUE; |
|
} |
|
|
|
// find snapshot frame |
|
for (uint32_t i = 0; i < recvd_frame->num_bufs; i++) { |
|
QCameraStream *pCurStream = |
|
pChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id); |
|
if (pCurStream != NULL) { |
|
if (pCurStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) || |
|
pCurStream->isTypeOf(CAM_STREAM_TYPE_RAW) || |
|
pCurStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT) || |
|
pCurStream->isOrignalTypeOf(CAM_STREAM_TYPE_RAW)) { |
|
pStream = pCurStream; |
|
frame = recvd_frame->bufs[i]; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if ( NULL == frame ) { |
|
LOGE("No valid raw buffer"); |
|
return BAD_VALUE; |
|
} |
|
|
|
QCameraMemory *rawMemObj = (QCameraMemory *)frame->mem_info; |
|
bool zslChannelUsed = m_parent->isZSLMode() && |
|
( pChannel != mPPChannels[0] ); |
|
camera_memory_t *raw_mem = NULL; |
|
|
|
if (rawMemObj != NULL) { |
|
if (zslChannelUsed) { |
|
raw_mem = rawMemObj->getMemory(frame->buf_idx, false); |
|
} else { |
|
raw_mem = m_parent->mGetMemory(-1, |
|
frame->frame_len, |
|
1, |
|
m_parent->mCallbackCookie); |
|
if (NULL == raw_mem) { |
|
LOGE("Not enough memory for RAW cb "); |
|
return NO_MEMORY; |
|
} |
|
memcpy(raw_mem->data, frame->buffer, frame->frame_len); |
|
} |
|
} |
|
|
|
if (NULL != rawMemObj && NULL != raw_mem) { |
|
// dump frame into file |
|
if (frame->stream_type == CAM_STREAM_TYPE_SNAPSHOT || |
|
pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT)) { |
|
// for YUV422 NV16 case |
|
m_parent->dumpFrameToFile(pStream, frame, QCAMERA_DUMP_FRM_INPUT_JPEG); |
|
} else { |
|
//Received RAW snapshot taken notification |
|
m_parent->dumpFrameToFile(pStream, frame, QCAMERA_DUMP_FRM_RAW); |
|
|
|
if(true == m_parent->m_bIntRawEvtPending) { |
|
//Sending RAW snapshot taken notification to HAL |
|
memset(&m_dst_dim, 0, sizeof(m_dst_dim)); |
|
pStream->getFrameDimension(m_dst_dim); |
|
pthread_mutex_lock(&m_parent->m_int_lock); |
|
pthread_cond_signal(&m_parent->m_int_cond); |
|
pthread_mutex_unlock(&m_parent->m_int_lock); |
|
raw_mem->release(raw_mem); |
|
return rc; |
|
} |
|
} |
|
|
|
// send data callback / notify for RAW_IMAGE |
|
if (NULL != m_parent->mDataCb && |
|
m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE) > 0) { |
|
qcamera_callback_argm_t cbArg; |
|
memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); |
|
cbArg.cb_type = QCAMERA_DATA_CALLBACK; |
|
cbArg.msg_type = CAMERA_MSG_RAW_IMAGE; |
|
cbArg.data = raw_mem; |
|
cbArg.index = 0; |
|
frame->cache_flags |= CPU_HAS_READ; |
|
m_parent->m_cbNotifier.notifyCallback(cbArg); |
|
} |
|
if (NULL != m_parent->mNotifyCb && |
|
m_parent->msgTypeEnabledWithLock(CAMERA_MSG_RAW_IMAGE_NOTIFY) > 0) { |
|
qcamera_callback_argm_t cbArg; |
|
memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); |
|
cbArg.cb_type = QCAMERA_NOTIFY_CALLBACK; |
|
cbArg.msg_type = CAMERA_MSG_RAW_IMAGE_NOTIFY; |
|
cbArg.ext1 = 0; |
|
cbArg.ext2 = 0; |
|
frame->cache_flags |= CPU_HAS_READ; |
|
m_parent->m_cbNotifier.notifyCallback(cbArg); |
|
} |
|
|
|
if ((m_parent->mDataCb != NULL) && |
|
m_parent->msgTypeEnabledWithLock(CAMERA_MSG_COMPRESSED_IMAGE) > 0) { |
|
qcamera_release_data_t release_data; |
|
memset(&release_data, 0, sizeof(qcamera_release_data_t)); |
|
if ( zslChannelUsed ) { |
|
release_data.frame = recvd_frame; |
|
} else { |
|
release_data.data = raw_mem; |
|
} |
|
rc = sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE, |
|
raw_mem, |
|
0, |
|
NULL, |
|
&release_data); |
|
} else { |
|
raw_mem->release(raw_mem); |
|
} |
|
} else { |
|
LOGE("Cannot get raw mem"); |
|
rc = UNKNOWN_ERROR; |
|
} |
|
|
|
return rc; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : dataSaveRoutine |
|
* |
|
* DESCRIPTION: data saving routine |
|
* |
|
* PARAMETERS : |
|
* @data : user data ptr (QCameraPostProcessor) |
|
* |
|
* RETURN : None |
|
*==========================================================================*/ |
|
void *QCameraPostProcessor::dataSaveRoutine(void *data) |
|
{ |
|
int running = 1; |
|
int ret; |
|
uint8_t is_active = FALSE; |
|
QCameraPostProcessor *pme = (QCameraPostProcessor *)data; |
|
QCameraCmdThread *cmdThread = &pme->m_saveProcTh; |
|
cmdThread->setName("CAM_JpegSave"); |
|
char saveName[PROPERTY_VALUE_MAX]; |
|
|
|
LOGH("E"); |
|
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); |
|
|
|
// we got notified about new cmd avail in cmd queue |
|
camera_cmd_type_t cmd = cmdThread->getCmd(); |
|
switch (cmd) { |
|
case CAMERA_CMD_TYPE_START_DATA_PROC: |
|
LOGH("start data proc"); |
|
is_active = TRUE; |
|
pme->m_inputSaveQ.init(); |
|
break; |
|
case CAMERA_CMD_TYPE_STOP_DATA_PROC: |
|
{ |
|
LOGH("stop data proc"); |
|
is_active = FALSE; |
|
|
|
// flush input save Queue |
|
pme->m_inputSaveQ.flush(); |
|
|
|
// signal cmd is completed |
|
cam_sem_post(&cmdThread->sync_sem); |
|
} |
|
break; |
|
case CAMERA_CMD_TYPE_DO_NEXT_JOB: |
|
{ |
|
LOGH("Do next job, active is %d", is_active); |
|
|
|
qcamera_jpeg_evt_payload_t *job_data = (qcamera_jpeg_evt_payload_t *) pme->m_inputSaveQ.dequeue(); |
|
if (job_data == NULL) { |
|
LOGE("Invalid jpeg event data"); |
|
continue; |
|
} |
|
//qcamera_jpeg_data_t *jpeg_job = |
|
// (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue(false); |
|
//uint32_t frame_idx = jpeg_job->src_frame->bufs[0]->frame_idx; |
|
uint32_t frame_idx = 75; |
|
|
|
pme->m_ongoingJpegQ.flushNodes(matchJobId, (void*)&job_data->jobId); |
|
|
|
LOGH("[KPI Perf] : jpeg job %d", job_data->jobId); |
|
|
|
if (is_active == TRUE) { |
|
memset(saveName, '\0', sizeof(saveName)); |
|
snprintf(saveName, |
|
sizeof(saveName), |
|
QCameraPostProcessor::STORE_LOCATION, |
|
pme->mSaveFrmCnt); |
|
|
|
int file_fd = open(saveName, O_RDWR | O_CREAT, 0655); |
|
if (file_fd >= 0) { |
|
ssize_t written_len = write(file_fd, job_data->out_data.buf_vaddr, |
|
job_data->out_data.buf_filled_len); |
|
if ((ssize_t)job_data->out_data.buf_filled_len != written_len) { |
|
LOGE("Failed save complete data %d bytes " |
|
"written instead of %d bytes!", |
|
written_len, |
|
job_data->out_data.buf_filled_len); |
|
} else { |
|
LOGH("written number of bytes %d\n", |
|
written_len); |
|
} |
|
|
|
close(file_fd); |
|
} else { |
|
LOGE("fail t open file for saving"); |
|
} |
|
pme->mSaveFrmCnt++; |
|
|
|
camera_memory_t* jpeg_mem = pme->m_parent->mGetMemory(-1, |
|
strlen(saveName), |
|
1, |
|
pme->m_parent->mCallbackCookie); |
|
if (NULL == jpeg_mem) { |
|
ret = NO_MEMORY; |
|
LOGE("getMemory for jpeg, ret = NO_MEMORY"); |
|
goto end; |
|
} |
|
memcpy(jpeg_mem->data, saveName, strlen(saveName)); |
|
|
|
LOGH("Calling upperlayer callback to store JPEG image"); |
|
qcamera_release_data_t release_data; |
|
memset(&release_data, 0, sizeof(qcamera_release_data_t)); |
|
release_data.data = jpeg_mem; |
|
release_data.unlinkFile = true; |
|
LOGI("[KPI Perf]: PROFILE_JPEG_CB "); |
|
ret = pme->sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE, |
|
jpeg_mem, |
|
0, |
|
NULL, |
|
&release_data, |
|
frame_idx); |
|
} |
|
|
|
end: |
|
free(job_data); |
|
} |
|
break; |
|
case CAMERA_CMD_TYPE_EXIT: |
|
LOGH("save thread exit"); |
|
running = 0; |
|
break; |
|
default: |
|
break; |
|
} |
|
} while (running); |
|
LOGH("X"); |
|
return NULL; |
|
} |
|
|
|
/*=========================================================================== |
|
* 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 (QCameraPostProcessor) |
|
* |
|
* RETURN : None |
|
*==========================================================================*/ |
|
void *QCameraPostProcessor::dataProcessRoutine(void *data) |
|
{ |
|
int running = 1; |
|
int ret; |
|
uint8_t is_active = FALSE; |
|
QCameraPostProcessor *pme = (QCameraPostProcessor *)data; |
|
QCameraCmdThread *cmdThread = &pme->m_dataProcTh; |
|
cmdThread->setName("CAM_DataProc"); |
|
|
|
LOGH("E"); |
|
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); |
|
|
|
// we got notified about new cmd avail in cmd queue |
|
camera_cmd_type_t cmd = cmdThread->getCmd(); |
|
switch (cmd) { |
|
case CAMERA_CMD_TYPE_START_DATA_PROC: |
|
LOGH("start data proc"); |
|
is_active = TRUE; |
|
|
|
pme->m_ongoingPPQ.init(); |
|
pme->m_inputJpegQ.init(); |
|
pme->m_inputPPQ.init(); |
|
pme->m_inputRawQ.init(); |
|
if (pme->m_halPP != NULL) { |
|
pme->m_halPP->initQ(); |
|
} |
|
pme->m_saveProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, |
|
FALSE, |
|
FALSE); |
|
|
|
// signal cmd is completed |
|
cam_sem_post(&cmdThread->sync_sem); |
|
|
|
break; |
|
case CAMERA_CMD_TYPE_STOP_DATA_PROC: |
|
{ |
|
LOGH("stop data proc"); |
|
is_active = FALSE; |
|
|
|
pme->m_saveProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, |
|
TRUE, |
|
TRUE); |
|
// cancel all ongoing jpeg jobs |
|
qcamera_jpeg_data_t *jpeg_job = |
|
(qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue(); |
|
while (jpeg_job != NULL) { |
|
pme->mJpegHandle.abort_job(jpeg_job->jobId); |
|
|
|
pme->releaseJpegJobData(jpeg_job); |
|
free(jpeg_job); |
|
|
|
jpeg_job = (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue(); |
|
} |
|
|
|
// destroy jpeg encoding session |
|
if ( 0 < pme->mJpegSessionId ) { |
|
pme->mJpegHandle.destroy_session(pme->mJpegSessionId); |
|
pme->mJpegSessionId = 0; |
|
} |
|
|
|
// free jpeg out buf and exif obj |
|
{FREE_JPEG_OUTPUT_BUFFER(pme->m_pJpegOutputMem, |
|
pme->m_JpegOutputMemCount);} |
|
|
|
// destroy hal pp jpeg encoding session |
|
if ( 0 < pme->mJpegSessionIdHalPP) { |
|
LOGE("destroying hal pp jpeg session:%d", pme->mJpegSessionIdHalPP); |
|
pme->mJpegHandle.destroy_session(pme->mJpegSessionIdHalPP); |
|
pme->mJpegSessionIdHalPP = 0; |
|
} |
|
|
|
{FREE_JPEG_OUTPUT_BUFFER(pme->m_pJpegOutputMemHalPP, |
|
pme->m_JpegOutputMemCountHALPP);} |
|
|
|
if (pme->m_pJpegExifObj != NULL) { |
|
delete pme->m_pJpegExifObj; |
|
pme->m_pJpegExifObj = NULL; |
|
} |
|
|
|
// flush ongoing postproc Queue |
|
pme->m_ongoingPPQ.flush(); |
|
|
|
// flush input jpeg Queue |
|
pme->m_inputJpegQ.flush(); |
|
|
|
// flush input Postproc Queue |
|
pme->m_inputPPQ.flush(); |
|
|
|
// flush input raw Queue |
|
pme->m_inputRawQ.flush(); |
|
|
|
// flush m_halPP |
|
if (pme->m_halPP != NULL) { |
|
pme->m_halPP->flushQ(); |
|
} |
|
// signal cmd is completed |
|
cam_sem_post(&cmdThread->sync_sem); |
|
|
|
pme->pJpegSrcStream = NULL; |
|
pme->mNewJpegSessionNeeded = true; |
|
pme->mNewJpegSessionNeededHalPP = true; |
|
} |
|
break; |
|
case CAMERA_CMD_TYPE_DO_NEXT_JOB: |
|
{ |
|
LOGH("Do next job, active is %d", is_active); |
|
if (is_active == TRUE) { |
|
qcamera_jpeg_data_t *jpeg_job = NULL; |
|
|
|
if ((!pme->m_parent->isDualCamera()) || |
|
(pme->m_ongoingJpegQ.isEmpty())) { |
|
jpeg_job = (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue(); |
|
} |
|
|
|
if (NULL != jpeg_job) { |
|
// To avoid any race conditions, |
|
// sync any stream specific parameters here. |
|
if (pme->m_parent->mParameters.isAdvCamFeaturesEnabled()) { |
|
// Sync stream params, only if advanced features configured |
|
// Reduces the latency for normal snapshot. |
|
pme->syncStreamParams(jpeg_job->src_frame, NULL); |
|
} |
|
|
|
// add into ongoing jpeg job Q |
|
if (pme->m_ongoingJpegQ.enqueue((void *)jpeg_job)) { |
|
if (jpeg_job->halPPAllocatedBuf) { |
|
LOGD("buffer is allcoated from HAL PP."); |
|
ret = pme->encodeData(jpeg_job, pme->mNewJpegSessionNeededHalPP); |
|
} else { |
|
ret = pme->encodeData(jpeg_job, pme->mNewJpegSessionNeeded); |
|
} |
|
if (NO_ERROR != ret) { |
|
// dequeue the last one |
|
pme->m_ongoingJpegQ.dequeue(false); |
|
pme->releaseJpegJobData(jpeg_job); |
|
free(jpeg_job); |
|
jpeg_job = NULL; |
|
pme->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); |
|
} |
|
} else { |
|
LOGW("m_ongoingJpegQ is not active!!!"); |
|
pme->releaseJpegJobData(jpeg_job); |
|
free(jpeg_job); |
|
jpeg_job = NULL; |
|
} |
|
} |
|
|
|
// Process HAL PP data if ready |
|
if (pme->m_halPP != NULL) { |
|
pme->m_halPP->process(); |
|
} |
|
|
|
// process raw data if any |
|
mm_camera_super_buf_t *super_buf = |
|
(mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue(); |
|
|
|
if (NULL != super_buf) { |
|
//play shutter sound |
|
pme->m_parent->playShutter(); |
|
ret = pme->processRawImageImpl(super_buf); |
|
if (NO_ERROR != ret) { |
|
pme->releaseSuperBuf(super_buf); |
|
free(super_buf); |
|
pme->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); |
|
} |
|
} |
|
|
|
ret = pme->doReprocess(); |
|
if (NO_ERROR != ret) { |
|
pme->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); |
|
} else { |
|
ret = pme->stopCapture(); |
|
} |
|
|
|
} else { |
|
// not active, simply return buf and do no op |
|
qcamera_jpeg_data_t *jpeg_data = |
|
(qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue(); |
|
if (NULL != jpeg_data) { |
|
pme->releaseJpegJobData(jpeg_data); |
|
free(jpeg_data); |
|
} |
|
mm_camera_super_buf_t *super_buf = |
|
(mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue(); |
|
if (NULL != super_buf) { |
|
pme->releaseSuperBuf(super_buf); |
|
free(super_buf); |
|
} |
|
|
|
// flush input Postproc Queue |
|
pme->m_inputPPQ.flush(); |
|
} |
|
} |
|
break; |
|
case CAMERA_CMD_TYPE_EXIT: |
|
running = 0; |
|
break; |
|
default: |
|
break; |
|
} |
|
} while (running); |
|
LOGH("X"); |
|
return NULL; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : doReprocess |
|
* |
|
* DESCRIPTION: Trigger channel reprocessing |
|
* |
|
* PARAMETERS :None |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::doReprocess() |
|
{ |
|
int32_t ret = NO_ERROR; |
|
QCameraChannel *m_pSrcChannel = NULL; |
|
QCameraStream *pMetaStream = NULL; |
|
uint8_t meta_buf_index = 0; |
|
mm_camera_buf_def_t *meta_buf = NULL; |
|
mm_camera_super_buf_t *ppInputFrame = NULL; |
|
|
|
qcamera_pp_data_t *ppreq_job = (qcamera_pp_data_t *)m_inputPPQ.peek(); |
|
if ((ppreq_job == NULL) || (ppreq_job->src_frame == NULL)) { |
|
return ret; |
|
} |
|
|
|
if (!validatePostProcess(ppreq_job->src_frame)) { |
|
return ret; |
|
} |
|
|
|
ppreq_job = (qcamera_pp_data_t *)m_inputPPQ.dequeue(); |
|
if (ppreq_job == NULL || ppreq_job->src_frame == NULL || |
|
ppreq_job->src_reproc_frame == NULL) { |
|
return ret; |
|
} |
|
|
|
mm_camera_super_buf_t *src_frame = ppreq_job->src_frame; |
|
mm_camera_super_buf_t *src_reproc_frame = ppreq_job->src_reproc_frame; |
|
int8_t mCurReprocCount = ppreq_job->reprocCount; |
|
int8_t mCurChannelIdx = ppreq_job->ppChannelIndex; |
|
|
|
LOGD("frame = %p src_frame = %p mCurReprocCount = %d mCurChannelIdx = %d", |
|
src_frame,src_reproc_frame,mCurReprocCount, mCurChannelIdx); |
|
|
|
if ((m_parent->mParameters.getManualCaptureMode() >= |
|
CAM_MANUAL_CAPTURE_TYPE_3) && (mCurChannelIdx == 0)) { |
|
ppInputFrame = src_reproc_frame; |
|
} else { |
|
ppInputFrame = src_frame; |
|
} |
|
|
|
if (mPPChannelCount >= CAM_PP_CHANNEL_MAX) { |
|
LOGE("invalid channel count"); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
// find meta data stream and index of meta data frame in the superbuf |
|
for (int8_t j = 0; j < mPPChannelCount; j++) { |
|
/*First search in src buffer for any offline metadata */ |
|
for (uint32_t i = 0; i < src_frame->num_bufs; i++) { |
|
QCameraStream *pStream = mPPChannels[j]->getStreamByHandle( |
|
src_frame->bufs[i]->stream_id); |
|
if (pStream != NULL && pStream->isOrignalTypeOf(CAM_STREAM_TYPE_METADATA)) { |
|
meta_buf_index = (uint8_t) src_frame->bufs[i]->buf_idx; |
|
pMetaStream = pStream; |
|
meta_buf = src_frame->bufs[i]; |
|
break; |
|
} |
|
} |
|
|
|
if ((pMetaStream != NULL) && (meta_buf != NULL)) { |
|
LOGD("Found Offline stream metadata = %d", |
|
(int)meta_buf_index); |
|
break; |
|
} |
|
} |
|
|
|
if ((pMetaStream == NULL) && (meta_buf == NULL)) { |
|
for (int8_t j = 0; j < mPPChannelCount; j++) { |
|
m_pSrcChannel = mPPChannels[j]->getSrcChannel(); |
|
if (m_pSrcChannel == NULL) |
|
continue; |
|
for (uint32_t i = 0; i < src_reproc_frame->num_bufs; i++) { |
|
QCameraStream *pStream = |
|
m_pSrcChannel->getStreamByHandle( |
|
src_reproc_frame->bufs[i]->stream_id); |
|
if (pStream != NULL && pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) { |
|
meta_buf_index = (uint8_t) src_reproc_frame->bufs[i]->buf_idx; |
|
pMetaStream = pStream; |
|
meta_buf = src_reproc_frame->bufs[i]; |
|
break; |
|
} |
|
} |
|
if ((pMetaStream != NULL) && (meta_buf != NULL)) { |
|
LOGD("Found Meta data info for reprocessing index = %d", |
|
(int)meta_buf_index); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (m_parent->mParameters.isAdvCamFeaturesEnabled()) { |
|
// No need to sync stream params, if none of the advanced features configured |
|
// Reduces the latency for normal snapshot. |
|
syncStreamParams(src_frame, src_reproc_frame); |
|
} |
|
|
|
if (mPPChannels[mCurChannelIdx] != NULL) { |
|
// add into ongoing PP job Q |
|
ppreq_job->reprocCount = (int8_t) (mCurReprocCount + 1); |
|
|
|
if ((m_parent->needOfflineReprocessing()) || (ppreq_job->offline_buffer)) { |
|
m_bufCountPPQ++; |
|
if (m_ongoingPPQ.enqueue((void *)ppreq_job)) { |
|
pthread_mutex_lock(&m_reprocess_lock); |
|
ret = mPPChannels[mCurChannelIdx]->doReprocessOffline(ppInputFrame, |
|
meta_buf, m_parent->mParameters); |
|
if (ret != NO_ERROR) { |
|
pthread_mutex_unlock(&m_reprocess_lock); |
|
goto end; |
|
} |
|
|
|
if ((ppreq_job->offline_buffer) && |
|
(ppreq_job->offline_reproc_buf)) { |
|
mPPChannels[mCurChannelIdx]->doReprocessOffline( |
|
ppreq_job->offline_reproc_buf, meta_buf); |
|
} |
|
pthread_mutex_unlock(&m_reprocess_lock); |
|
} else { |
|
LOGW("m_ongoingPPQ is not active!!!"); |
|
ret = UNKNOWN_ERROR; |
|
goto end; |
|
} |
|
} else { |
|
m_bufCountPPQ++; |
|
if (!m_ongoingPPQ.enqueue((void *)ppreq_job)) { |
|
LOGW("m_ongoingJpegQ is not active!!!"); |
|
ret = UNKNOWN_ERROR; |
|
goto end; |
|
} |
|
|
|
int32_t numRequiredPPQBufsForSingleOutput = (int32_t) |
|
m_parent->mParameters.getNumberInBufsForSingleShot(); |
|
|
|
if (m_bufCountPPQ % numRequiredPPQBufsForSingleOutput == 0) { |
|
int32_t extra_pp_job_count = |
|
m_parent->mParameters.getNumberOutBufsForSingleShot() - |
|
m_parent->mParameters.getNumberInBufsForSingleShot(); |
|
|
|
for (int32_t i = 0; i < extra_pp_job_count; i++) { |
|
qcamera_pp_data_t *extra_pp_job = |
|
(qcamera_pp_data_t *)calloc(1, sizeof(qcamera_pp_data_t)); |
|
if (!extra_pp_job) { |
|
LOGE("no mem for qcamera_pp_data_t"); |
|
ret = NO_MEMORY; |
|
break; |
|
} |
|
extra_pp_job->reprocCount = ppreq_job->reprocCount; |
|
if (!m_ongoingPPQ.enqueue((void *)extra_pp_job)) { |
|
LOGW("m_ongoingJpegQ is not active!!!"); |
|
releaseOngoingPPData(extra_pp_job, this); |
|
free(extra_pp_job); |
|
extra_pp_job = NULL; |
|
goto end; |
|
} |
|
} |
|
} |
|
|
|
ret = mPPChannels[mCurChannelIdx]->doReprocess(ppInputFrame, |
|
m_parent->mParameters, pMetaStream, meta_buf_index); |
|
} |
|
} else { |
|
LOGE("Reprocess channel is NULL"); |
|
ret = UNKNOWN_ERROR; |
|
} |
|
|
|
end: |
|
if (ret != NO_ERROR) { |
|
releaseOngoingPPData(ppreq_job, this); |
|
if (ppreq_job != NULL) { |
|
free(ppreq_job); |
|
ppreq_job = NULL; |
|
} |
|
} |
|
return ret; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : getReprocChannel |
|
* |
|
* DESCRIPTION: Returns reprocessing channel handle |
|
* |
|
* PARAMETERS : index for reprocessing array |
|
* |
|
* RETURN : QCameraReprocessChannel * type of pointer |
|
NULL if no reprocessing channel |
|
*==========================================================================*/ |
|
QCameraReprocessChannel * QCameraPostProcessor::getReprocChannel(uint8_t index) |
|
{ |
|
if (index >= mPPChannelCount) { |
|
LOGE("Invalid index value"); |
|
return NULL; |
|
} |
|
return mPPChannels[index]; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : stopCapture |
|
* |
|
* DESCRIPTION: Trigger image capture stop |
|
* |
|
* PARAMETERS : |
|
* None |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::stopCapture() |
|
{ |
|
int rc = NO_ERROR; |
|
|
|
if (m_parent->isRegularCapture()) { |
|
rc = m_parent->processAPI( |
|
QCAMERA_SM_EVT_STOP_CAPTURE_CHANNEL, |
|
NULL); |
|
} |
|
return rc; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : getJpegPaddingReq |
|
* |
|
* DESCRIPTION: function to add an entry to exif data |
|
* |
|
* PARAMETERS : |
|
* @padding_info : jpeg specific padding requirement |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::getJpegPaddingReq(cam_padding_info_t &padding_info) |
|
{ |
|
// TODO: hardcode for now, needs to query from mm-jpeg-interface |
|
padding_info.width_padding = CAM_PAD_NONE; |
|
padding_info.height_padding = CAM_PAD_TO_16; |
|
padding_info.plane_padding = CAM_PAD_TO_WORD; |
|
padding_info.offset_info.offset_x = 0; |
|
padding_info.offset_info.offset_y = 0; |
|
return NO_ERROR; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : setYUVFrameInfo |
|
* |
|
* DESCRIPTION: set Raw YUV frame data info for up-layer |
|
* |
|
* PARAMETERS : |
|
* @frame : process frame received from mm-camera-interface |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
* |
|
* NOTE : currently we return frame len, y offset, cbcr offset and frame format |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::setYUVFrameInfo(mm_camera_super_buf_t *recvd_frame) |
|
{ |
|
QCameraChannel *pChannel = m_parent->getChannelByHandle(recvd_frame->ch_id); |
|
// check reprocess channel if not found |
|
if (pChannel == NULL) { |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
if ((mPPChannels[i] != NULL) && |
|
(validate_handle(mPPChannels[i]->getMyHandle(), recvd_frame->ch_id))) { |
|
pChannel = mPPChannels[i]; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (pChannel == NULL) { |
|
LOGE("No corresponding channel (ch_id = %d) exist, return here", |
|
recvd_frame->ch_id); |
|
return BAD_VALUE; |
|
} |
|
|
|
// find snapshot frame |
|
for (uint32_t i = 0; i < recvd_frame->num_bufs; i++) { |
|
QCameraStream *pStream = |
|
pChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id); |
|
if (pStream != NULL) { |
|
if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) || |
|
pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT)) { |
|
//get the main frame, use stream info |
|
cam_frame_len_offset_t frame_offset; |
|
cam_dimension_t frame_dim; |
|
cam_format_t frame_fmt; |
|
const char *fmt_string; |
|
pStream->getFrameDimension(frame_dim); |
|
pStream->getFrameOffset(frame_offset); |
|
pStream->getFormat(frame_fmt); |
|
fmt_string = m_parent->mParameters.getFrameFmtString(frame_fmt); |
|
|
|
int cbcr_offset = (int32_t)frame_offset.mp[0].len - |
|
frame_dim.width * frame_dim.height; |
|
|
|
LOGH("frame width=%d, height=%d, yoff=%d, cbcroff=%d, fmt_string=%s", |
|
frame_dim.width, frame_dim.height, frame_offset.mp[0].offset, cbcr_offset, fmt_string); |
|
return NO_ERROR; |
|
} |
|
} |
|
} |
|
|
|
return BAD_VALUE; |
|
} |
|
|
|
bool QCameraPostProcessor::matchJobId(void *data, void *, void *match_data) |
|
{ |
|
qcamera_jpeg_data_t * job = (qcamera_jpeg_data_t *) data; |
|
uint32_t job_id = *((uint32_t *) match_data); |
|
return job->jobId == job_id; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : getJpegMemory |
|
* |
|
* DESCRIPTION: buffer allocation function |
|
* to pass to jpeg interface |
|
* |
|
* PARAMETERS : |
|
* @out_buf : buffer descriptor struct |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int QCameraPostProcessor::getJpegMemory(omx_jpeg_ouput_buf_t *out_buf) |
|
{ |
|
LOGH("Allocating jpeg out buffer of size: %d", out_buf->size); |
|
QCameraPostProcessor *procInst = (QCameraPostProcessor *) out_buf->handle; |
|
camera_memory_t *cam_mem = procInst->m_parent->mGetMemory(out_buf->fd, out_buf->size, 1U, |
|
procInst->m_parent->mCallbackCookie); |
|
out_buf->mem_hdl = cam_mem; |
|
out_buf->vaddr = cam_mem->data; |
|
|
|
return 0; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : releaseJpegMemory |
|
* |
|
* DESCRIPTION: release jpeg memory function |
|
* to pass to jpeg interface, in case of abort |
|
* |
|
* PARAMETERS : |
|
* @out_buf : buffer descriptor struct |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int QCameraPostProcessor::releaseJpegMemory(omx_jpeg_ouput_buf_t *out_buf) |
|
{ |
|
if (out_buf && out_buf->mem_hdl) { |
|
LOGD("releasing jpeg out buffer of size: %d", out_buf->size); |
|
camera_memory_t *cam_mem = (camera_memory_t*)out_buf->mem_hdl; |
|
cam_mem->release(cam_mem); |
|
out_buf->mem_hdl = NULL; |
|
out_buf->vaddr = NULL; |
|
return NO_ERROR; |
|
} |
|
return -1; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : QCameraExif |
|
* |
|
* DESCRIPTION: constructor of QCameraExif |
|
* |
|
* PARAMETERS : None |
|
* |
|
* RETURN : None |
|
*==========================================================================*/ |
|
QCameraExif::QCameraExif() |
|
: m_nNumEntries(0) |
|
{ |
|
memset(m_Entries, 0, sizeof(m_Entries)); |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : ~QCameraExif |
|
* |
|
* DESCRIPTION: deconstructor of QCameraExif. Will release internal memory ptr. |
|
* |
|
* PARAMETERS : None |
|
* |
|
* RETURN : None |
|
*==========================================================================*/ |
|
QCameraExif::~QCameraExif() |
|
{ |
|
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; |
|
} |
|
} |
|
} |
|
|
|
/*=========================================================================== |
|
* 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 QCameraExif::addEntry(exif_tag_id_t tagid, |
|
exif_tag_type_t type, |
|
uint32_t count, |
|
void *data) |
|
{ |
|
int32_t rc = NO_ERROR; |
|
if(m_nNumEntries >= MAX_EXIF_TABLE_ENTRIES) { |
|
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: |
|
{ |
|
uint32_t *exif_data = (uint32_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 signed 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; |
|
} |
|
|
|
// Increase number of entries |
|
m_nNumEntries++; |
|
return rc; |
|
} |
|
|
|
/*=========================================================================== |
|
* 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 QCameraPostProcessor::processHalPPDataCB(qcamera_hal_pp_data_t *pOutput, void* pUserData) |
|
{ |
|
QCameraPostProcessor *pme = (QCameraPostProcessor *)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 QCameraPostProcessor::processHalPPData(qcamera_hal_pp_data_t *pData) |
|
{ |
|
int32_t rc = NO_ERROR; |
|
LOGD("E"); |
|
if (m_bInited == FALSE) { |
|
LOGE("postproc not initialized yet"); |
|
return UNKNOWN_ERROR; |
|
} |
|
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_jpeg_data_t *jpeg_job = |
|
(qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t)); |
|
if (jpeg_job == NULL) { |
|
LOGE("No memory for jpeg job"); |
|
return NO_MEMORY; |
|
} |
|
|
|
memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t)); |
|
jpeg_job->src_frame = frame; |
|
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; |
|
jpeg_job->src_reproc_frame = pData->src_reproc_frame; |
|
jpeg_job->src_reproc_bufs = pData->src_reproc_bufs; |
|
jpeg_job->reproc_frame_release = pData->reproc_frame_release; |
|
jpeg_job->offline_reproc_buf = pData->offline_reproc_buf; |
|
jpeg_job->offline_buffer = pData->offline_buffer; |
|
LOGD("halPPAllocatedBuf = %d", pData->halPPAllocatedBuf); |
|
LOGD("src_reproc_frame:%p", jpeg_job->src_reproc_frame); |
|
|
|
if (!jpeg_job->halPPAllocatedBuf) { |
|
// check if to encode hal pp input buffer |
|
char prop[PROPERTY_VALUE_MAX]; |
|
memset(prop, 0, sizeof(prop)); |
|
property_get("persist.camera.dualfov.jpegnum", prop, "1"); |
|
int dualfov_snap_num = atoi(prop); |
|
if (dualfov_snap_num == 1) { |
|
LOGE("No need to encode input buffer, just release it."); |
|
releaseJpegJobData(jpeg_job); |
|
free(jpeg_job); |
|
jpeg_job = NULL; |
|
return NO_ERROR; |
|
} |
|
} |
|
|
|
// find meta data frame |
|
mm_camera_buf_def_t *meta_frame = NULL; |
|
// look through reprocess superbuf |
|
for (uint32_t i = 0; i < frame->num_bufs; i++) { |
|
if (frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) { |
|
meta_frame = frame->bufs[i]; |
|
break; |
|
} |
|
} |
|
if (meta_frame != NULL) { |
|
// fill in meta data frame ptr |
|
jpeg_job->metadata = (metadata_buffer_t *)meta_frame->buffer; |
|
} |
|
// 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 |
|
m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
|
LOGD("X"); |
|
return rc; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : getHalPPOutputBufferCB |
|
* |
|
* DESCRIPTION: callback function to request output buffer |
|
* |
|
* PARAMETERS : |
|
* @frameIndex : frameIndex needs to be appended in the output data |
|
* @pUserData : user data ptr (QCameraReprocessor) |
|
* |
|
* RETURN : None |
|
*==========================================================================*/ |
|
void QCameraPostProcessor::getHalPPOutputBufferCB(uint32_t frameIndex, void* pUserData) |
|
{ |
|
QCameraPostProcessor *pme = (QCameraPostProcessor *)pUserData; |
|
pme->getHalPPOutputBuffer(frameIndex); |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : getHalPPOutputBuffer |
|
* |
|
* DESCRIPTION: function to send HAL PP output buffer |
|
* PARAMETERS : |
|
* @frameIndex : frameIndex needs to be appended in the output data |
|
* RETURN : None |
|
*==========================================================================*/ |
|
void QCameraPostProcessor::getHalPPOutputBuffer(uint32_t frameIndex) |
|
{ |
|
LOGD("E. Allocate HAL PP Output buffer"); |
|
qcamera_hal_pp_data_t *output_data = |
|
(qcamera_hal_pp_data_t*) malloc(sizeof(qcamera_hal_pp_data_t)); |
|
if (output_data == NULL) { |
|
LOGE("No memory for qcamera_hal_pp_data_t output data"); |
|
return; |
|
} |
|
memset(output_data, 0, sizeof(qcamera_hal_pp_data_t)); |
|
mm_camera_super_buf_t* output_frame = |
|
(mm_camera_super_buf_t *)malloc(sizeof(mm_camera_super_buf_t)); |
|
if (output_frame == NULL) { |
|
LOGE("No memory for mm_camera_super_buf_t frame"); |
|
free(output_data); |
|
return; |
|
} |
|
memset(output_frame, 0, sizeof(mm_camera_super_buf_t)); |
|
output_data->frame = output_frame; |
|
output_data->bufs = |
|
(mm_camera_buf_def_t *)malloc(HAL_PP_NUM_BUFS * sizeof(mm_camera_buf_def_t)); |
|
if (output_data->bufs == NULL) { |
|
LOGE("No memory for output_data->bufs"); |
|
free(output_frame); |
|
free(output_data); |
|
return; |
|
} |
|
memset(output_data->bufs, 0, HAL_PP_NUM_BUFS * sizeof(mm_camera_buf_def_t)); |
|
output_data->halPPAllocatedBuf = true; |
|
output_data->snapshot_heap = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE); |
|
if (output_data->snapshot_heap == NULL) { |
|
LOGE("Unable to new heap memory obj for image buf"); |
|
free(output_frame); |
|
free(output_data->bufs); |
|
free(output_data); |
|
return; |
|
} |
|
output_data->metadata_heap = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE); |
|
if (output_data->metadata_heap == NULL) { |
|
LOGE("Unable to new heap memory obj for metadata buf"); |
|
delete output_data->snapshot_heap; |
|
free(output_frame); |
|
free(output_data->bufs); |
|
free(output_data); |
|
return; |
|
} |
|
output_data->frameIndex = frameIndex; |
|
m_halPP->feedOutput(output_data); |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : getChannelByHandle |
|
* |
|
* DESCRIPTION: function to get channel by handle |
|
* PARAMETERS : |
|
* @channelHandle : channel handle |
|
* RETURN : QCameraChannel |
|
*==========================================================================*/ |
|
QCameraChannel *QCameraPostProcessor::getChannelByHandle(uint32_t channelHandle) |
|
{ |
|
QCameraChannel *pChannel = m_parent->getChannelByHandle(channelHandle); |
|
// check reprocess channel if not found |
|
if (pChannel == NULL) { |
|
for (int8_t i = 0; i < mPPChannelCount; i++) { |
|
if ((mPPChannels[i] != NULL) && |
|
(validate_handle(mPPChannels[i]->getMyHandle(), channelHandle))) { |
|
pChannel = mPPChannels[i]; |
|
break; |
|
} |
|
} |
|
} |
|
return pChannel; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : initHALPP |
|
* |
|
* DESCRIPTION: function to create and init HALPP block |
|
* RETURN : None |
|
*==========================================================================*/ |
|
int32_t QCameraPostProcessor::initHALPP() |
|
{ |
|
int32_t rc = NO_ERROR; |
|
void *staticParam = NULL; |
|
|
|
LOGD("E. m_halPPType:%d", m_halPPType); |
|
|
|
switch (m_halPPType) { |
|
case QCAMERA_HAL_PP_TYPE_DUAL_FOV: |
|
m_halPP = new QCameraDualFOVPP(); |
|
staticParam = (void*)m_parent->getCamHalCapabilities(); |
|
break; |
|
case QCAMERA_HAL_PP_TYPE_BOKEH: |
|
case QCAMERA_HAL_PP_TYPE_CLEARSIGHT: |
|
break; |
|
default: |
|
break; |
|
} |
|
|
|
if (m_halPP != NULL) { |
|
rc = m_halPP->init(QCameraPostProcessor::processHalPPDataCB, |
|
QCameraPostProcessor::getHalPPOutputBufferCB, this, staticParam); |
|
if (rc != NO_ERROR) { |
|
LOGE("HAL PP type %d init failed, rc = %d", m_halPPType, rc); |
|
} |
|
} |
|
|
|
return rc; |
|
} |
|
}; // namespace qcamera
|
|
|