/* 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 "QCameraChannel" // System dependencies #include // Camera dependencies #include "QCamera2HWI.h" extern "C" { #include "mm_camera_dbg.h" } using namespace android; namespace qcamera { /*=========================================================================== * FUNCTION : QCameraChannel * * DESCRIPTION: constrcutor of QCameraChannel * * PARAMETERS : * @cam_handle : camera handle * @cam_ops : ptr to camera ops table * * RETURN : none *==========================================================================*/ QCameraChannel::QCameraChannel(uint32_t cam_handle, mm_camera_ops_t *cam_ops) { m_camHandle = cam_handle; m_camOps = cam_ops; m_bIsActive = false; m_bAllowDynBufAlloc = false; m_handle = 0; } /*=========================================================================== * FUNCTION : QCameraChannel * * DESCRIPTION: default constrcutor of QCameraChannel * * PARAMETERS : none * * RETURN : none *==========================================================================*/ QCameraChannel::QCameraChannel() { m_camHandle = 0; m_camOps = NULL; m_bIsActive = false; m_handle = 0; } /*=========================================================================== * FUNCTION : ~QCameraChannel * * DESCRIPTION: destructor of QCameraChannel * * PARAMETERS : none * * RETURN : none *==========================================================================*/ QCameraChannel::~QCameraChannel() { if (m_bIsActive) { stop(); } for (size_t i = 0; i < mStreams.size(); i++) { if (mStreams[i] != NULL) { if (m_handle == mStreams[i]->getChannelHandle()) { delete mStreams[i]; } } } mStreams.clear(); m_camOps->delete_channel(m_camHandle, m_handle); m_handle = 0; } /*=========================================================================== * FUNCTION : deleteChannel * * DESCRIPTION: deletes a camera channel * * PARAMETERS : none * * RETURN : none *==========================================================================*/ void QCameraChannel::deleteChannel() { if (m_bIsActive) { stop(); } for (size_t i = 0; i < mStreams.size(); i++) { if ((mStreams[i] != NULL) && (m_handle == mStreams[i]->getChannelHandle())) { mStreams[i]->deleteStream(); } } m_camOps->delete_channel(m_camHandle, m_handle); } /*=========================================================================== * FUNCTION : setStreamSyncCB * * DESCRIPTION: reg callback function to stream of stream type * * PARAMETERS : * @stream_type : Stream type for which callback needs to be registered. * @stream_cb : Callback function * RETURN : int32_t type of status * NO_ERROR -- success * non-zero failure code *==========================================================================*/ int32_t QCameraChannel::setStreamSyncCB (cam_stream_type_t stream_type, stream_cb_routine stream_cb) { int32_t rc = UNKNOWN_ERROR; for (size_t i = 0; i < mStreams.size(); i++) { if ((mStreams[i] != NULL) && (stream_type == mStreams[i]->getMyType())) { rc = mStreams[i]->setSyncDataCB(stream_cb); break; } } return rc; } /*=========================================================================== * FUNCTION : init * * DESCRIPTION: initialization of channel * * PARAMETERS : * @attr : channel bundle attribute setting * @dataCB : data notify callback * @userData: user data ptr * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraChannel::init(mm_camera_channel_attr_t *attr, mm_camera_buf_notify_t dataCB, void *userData) { m_handle = m_camOps->add_channel(m_camHandle, attr, dataCB, userData); if (m_handle == 0) { LOGE("Add channel failed"); return UNKNOWN_ERROR; } return NO_ERROR; } /*=========================================================================== * FUNCTION : addStream * * DESCRIPTION: add a stream into channel * * PARAMETERS : * @allocator : stream related buffer allocator * @streamInfoBuf : ptr to buf that contains stream info * @miscBuf : ptr to buf that contains misc buffers * @minStreamBufNum: number of stream buffers needed * @paddingInfo : padding information * @stream_cb : stream data notify callback * @userdata : user data ptr * @bDynAllocBuf : flag indicating if allow allocate buffers in 2 steps * @online_rotation: rotation applied online * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraChannel::addStream(QCameraAllocator &allocator, QCameraHeapMemory *streamInfoBuf, QCameraHeapMemory *miscBuf, uint8_t minStreamBufNum, cam_padding_info_t *paddingInfo, stream_cb_routine stream_cb, void *userdata, bool bDynAllocBuf, bool bDeffAlloc, cam_rotation_t online_rotation) { int32_t rc = NO_ERROR; if (mStreams.size() >= MAX_STREAM_NUM_IN_BUNDLE) { LOGE("stream number (%zu) exceeds max limit (%d)", mStreams.size(), MAX_STREAM_NUM_IN_BUNDLE); if (streamInfoBuf != NULL) { streamInfoBuf->deallocate(); delete streamInfoBuf; streamInfoBuf = NULL; } return BAD_VALUE; } QCameraStream *pStream = new QCameraStream(allocator, m_camHandle, m_handle, m_camOps, paddingInfo, bDeffAlloc, online_rotation); if (pStream == NULL) { LOGE("No mem for Stream"); if (streamInfoBuf != NULL) { streamInfoBuf->deallocate(); delete streamInfoBuf; streamInfoBuf = NULL; } return NO_MEMORY; } rc = pStream->init(streamInfoBuf, miscBuf, minStreamBufNum, stream_cb, userdata, bDynAllocBuf); if (rc == 0) { mStreams.add(pStream); } else { delete pStream; } return rc; } /*=========================================================================== * FUNCTION : linkStream * * DESCRIPTION: link a stream into channel * * PARAMETERS : * @ch : Channel which the stream belongs to * @stream : Stream which needs to be linked * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraChannel::linkStream(QCameraChannel *ch, QCameraStream *stream) { int32_t rc = NO_ERROR; if ((0 == m_handle) || (NULL == ch) || (NULL == stream)) { return NO_INIT; } int32_t handle = m_camOps->link_stream(m_camHandle, ch->getMyHandle(), stream->getMyHandle(), m_handle); if (0 == handle) { LOGE("Linking of stream failed"); rc = INVALID_OPERATION; } else { mStreams.add(stream); } return rc; } /*=========================================================================== * FUNCTION : start * * DESCRIPTION: start channel, which will start all streams belong to this channel * * PARAMETERS : None * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraChannel::start() { int32_t rc = NO_ERROR; if (mStreams.size() > 1) { // there is more than one stream in the channel // we need to notify mctl that all streams in this channel need to be bundled cam_bundle_config_t bundleInfo; memset(&bundleInfo, 0, sizeof(bundleInfo)); rc = m_camOps->get_bundle_info(m_camHandle, m_handle, &bundleInfo); if (rc != NO_ERROR) { LOGE("get_bundle_info failed"); return rc; } if (bundleInfo.num_of_streams > 1) { for (int i = 0; i < bundleInfo.num_of_streams; i++) { QCameraStream *pStream = getStreamByServerID(bundleInfo.stream_ids[i]); if (pStream != NULL) { if ((pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) || (pStream->isTypeOf(CAM_STREAM_TYPE_OFFLINE_PROC))) { // Skip metadata for reprocess now because PP module cannot handle meta data // May need furthur discussion if Imaginglib need meta data continue; } cam_stream_parm_buffer_t param; memset(¶m, 0, sizeof(cam_stream_parm_buffer_t)); param.type = CAM_STREAM_PARAM_TYPE_SET_BUNDLE_INFO; param.bundleInfo = bundleInfo; rc = pStream->setParameter(param); if (rc != NO_ERROR) { LOGE("stream setParameter for set bundle failed"); return rc; } } } } } for (size_t i = 0; i < mStreams.size(); i++) { if ((mStreams[i] != NULL) && (m_handle == mStreams[i]->getChannelHandle())) { mStreams[i]->start(); } } rc = m_camOps->start_channel(m_camHandle, m_handle); if (rc != NO_ERROR) { for (size_t i = 0; i < mStreams.size(); i++) { if ((mStreams[i] != NULL) && (m_handle == mStreams[i]->getChannelHandle())) { mStreams[i]->stop(); } } } else { m_bIsActive = true; for (size_t i = 0; i < mStreams.size(); i++) { if (mStreams[i] != NULL) { mStreams[i]->cond_signal(); } } } return rc; } /*=========================================================================== * FUNCTION : stop * * DESCRIPTION: stop a channel, which will stop all streams belong to this channel * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraChannel::stop() { int32_t rc = NO_ERROR; ssize_t linkedIdx = -1; if (!m_bIsActive) { return NO_INIT; } for (size_t i = 0; i < mStreams.size(); i++) { if (mStreams[i] != NULL) { if (m_handle == mStreams[i]->getChannelHandle()) { mStreams[i]->stop(); } else { // Remove linked stream from stream list linkedIdx = (ssize_t)i; } } } if (linkedIdx > 0) { mStreams.removeAt((size_t)linkedIdx); } rc = m_camOps->stop_channel(m_camHandle, m_handle); m_bIsActive = false; return rc; } /*=========================================================================== * FUNCTION : bufDone * * DESCRIPTION: return a stream buf back to kernel * * PARAMETERS : * @recvd_frame : stream buf frame to be returned * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraChannel::bufDone(mm_camera_super_buf_t *recvd_frame) { int32_t rc = NO_ERROR; for (uint32_t i = 0; i < recvd_frame->num_bufs; i++) { if (recvd_frame->bufs[i] != NULL) { for (size_t j = 0; j < mStreams.size(); j++) { if (mStreams[j] != NULL && mStreams[j]->getMyHandle() == recvd_frame->bufs[i]->stream_id) { rc = mStreams[j]->bufDone(recvd_frame->bufs[i]->buf_idx); break; // break loop j } } } } return rc; } /*=========================================================================== * FUNCTION : bufDone * * DESCRIPTION: return specified buffer from super buffer to kernel * * PARAMETERS : * @recvd_frame : stream buf frame to be returned * @stream_id : stream ID of the buffer to be released * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraChannel::bufDone(mm_camera_super_buf_t *recvd_frame, uint32_t stream_id) { int32_t rc = NO_ERROR; int32_t index; for (int32_t i = 0; i < (int32_t)recvd_frame->num_bufs; i++) { index = -1; if ((recvd_frame->bufs[i] != NULL) && (recvd_frame->bufs[i]->stream_id == stream_id)) { for (size_t j = 0; j < mStreams.size(); j++) { if ((mStreams[j] != NULL) && (mStreams[j]->getMyHandle() == stream_id)) { rc = mStreams[j]->bufDone(recvd_frame->bufs[i]->buf_idx); index = i; break; // break loop j } } if ((index >= 0) && (index < (int32_t)recvd_frame->num_bufs)) { for (int32_t j = index; j < (int32_t)(recvd_frame->num_bufs - 1); j++) { recvd_frame->bufs[j] = recvd_frame->bufs[j + 1]; } recvd_frame->num_bufs--; i--; } } } return rc; } /*=========================================================================== * FUNCTION : processZoomDone * * DESCRIPTION: process zoom done event * * PARAMETERS : * @previewWindoe : ptr to preview window ops table, needed to set preview * crop information * @crop_info : crop info as a result of zoom operation * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraChannel::processZoomDone(preview_stream_ops_t *previewWindow, cam_crop_data_t &crop_info) { int32_t rc = NO_ERROR; for (size_t i = 0; i < mStreams.size(); i++) { if ((mStreams[i] != NULL) && (m_handle == mStreams[i]->getChannelHandle())) { rc = mStreams[i]->processZoomDone(previewWindow, crop_info); } } return rc; } /*=========================================================================== * FUNCTION : getStreamByHandle * * DESCRIPTION: return stream object by stream handle * * PARAMETERS : * @streamHandle : stream handle * * RETURN : stream object. NULL if not found *==========================================================================*/ QCameraStream *QCameraChannel::getStreamByHandle(uint32_t streamHandle) { for (size_t i = 0; i < mStreams.size(); i++) { if (mStreams[i] != NULL && mStreams[i]->getMyHandle() == streamHandle) { return mStreams[i]; } } return NULL; } /*=========================================================================== * FUNCTION : getStreamByServerID * * DESCRIPTION: return stream object by stream server ID from daemon * * PARAMETERS : * @serverID : stream server ID * * RETURN : stream object. NULL if not found *==========================================================================*/ QCameraStream *QCameraChannel::getStreamByServerID(uint32_t serverID) { for (size_t i = 0; i < mStreams.size(); i++) { if (mStreams[i] != NULL && mStreams[i]->getMyServerID() == serverID) { return mStreams[i]; } } return NULL; } /*=========================================================================== * FUNCTION : getStreamByIndex * * DESCRIPTION: return stream object by index of streams in the channel * * PARAMETERS : * @index : index of stream in the channel * * RETURN : stream object. NULL if not found *==========================================================================*/ QCameraStream *QCameraChannel::getStreamByIndex(uint32_t index) { if (index >= MAX_STREAM_NUM_IN_BUNDLE) { return NULL; } if (index < mStreams.size()) { return mStreams[index]; } return NULL; } /*=========================================================================== * FUNCTION : UpdateStreamBasedParameters * * DESCRIPTION: update any stream based settings from parameters * * PARAMETERS : * @param : reference to parameters object * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraChannel::UpdateStreamBasedParameters(QCameraParametersIntf ¶m) { int32_t rc = NO_ERROR; if (param.isPreviewFlipChanged()) { // try to find preview stream for (size_t i = 0; i < mStreams.size(); i++) { if ((mStreams[i] != NULL) && (m_handle == mStreams[i]->getChannelHandle()) && (mStreams[i]->isTypeOf(CAM_STREAM_TYPE_PREVIEW) || (mStreams[i]->isOrignalTypeOf(CAM_STREAM_TYPE_PREVIEW))) ) { cam_stream_parm_buffer_t param_buf; memset(¶m_buf, 0, sizeof(cam_stream_parm_buffer_t)); param_buf.type = CAM_STREAM_PARAM_TYPE_SET_FLIP; param_buf.flipInfo.flip_mask = (uint32_t)param.getFlipMode(CAM_STREAM_TYPE_PREVIEW); rc = mStreams[i]->setParameter(param_buf); if (rc != NO_ERROR) { LOGW("set preview stream flip failed"); } } } } if (param.isVideoFlipChanged()) { // try to find video stream for (size_t i = 0; i < mStreams.size(); i++) { if ((mStreams[i] != NULL) && (m_handle == mStreams[i]->getChannelHandle()) && (mStreams[i]->isTypeOf(CAM_STREAM_TYPE_VIDEO) || (mStreams[i]->isOrignalTypeOf(CAM_STREAM_TYPE_VIDEO))) ) { cam_stream_parm_buffer_t param_buf; memset(¶m_buf, 0, sizeof(cam_stream_parm_buffer_t)); param_buf.type = CAM_STREAM_PARAM_TYPE_SET_FLIP; param_buf.flipInfo.flip_mask = (uint32_t)param.getFlipMode(CAM_STREAM_TYPE_VIDEO); rc = mStreams[i]->setParameter(param_buf); if (rc != NO_ERROR) { LOGW("set video stream flip failed"); } } } } if (param.isSnapshotFlipChanged()) { // try to find snapshot/postview stream for (size_t i = 0; i < mStreams.size(); i++) { if (mStreams[i] != NULL && (m_handle == mStreams[i]->getChannelHandle()) && (mStreams[i]->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) || mStreams[i]->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT) || mStreams[i]->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) || mStreams[i]->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW) ) ) { cam_stream_parm_buffer_t param_buf; memset(¶m_buf, 0, sizeof(cam_stream_parm_buffer_t)); param_buf.type = CAM_STREAM_PARAM_TYPE_SET_FLIP; param_buf.flipInfo.flip_mask = (uint32_t)param.getFlipMode(CAM_STREAM_TYPE_SNAPSHOT); rc = mStreams[i]->setParameter(param_buf); if (rc != NO_ERROR) { LOGW("set snapshot stream flip failed"); } } } } return rc; } /*=========================================================================== * FUNCTION : QCameraPicChannel * * DESCRIPTION: constructor of QCameraPicChannel * * PARAMETERS : * @cam_handle : camera handle * @cam_ops : ptr to camera ops table * * RETURN : none *==========================================================================*/ QCameraPicChannel::QCameraPicChannel(uint32_t cam_handle, mm_camera_ops_t *cam_ops) : QCameraChannel(cam_handle, cam_ops) { m_bAllowDynBufAlloc = true; } /*=========================================================================== * FUNCTION : QCameraPicChannel * * DESCRIPTION: default constructor of QCameraPicChannel * * PARAMETERS : none * * RETURN : none *==========================================================================*/ QCameraPicChannel::QCameraPicChannel() { m_bAllowDynBufAlloc = true; } /*=========================================================================== * FUNCTION : ~QCameraPicChannel * * DESCRIPTION: destructor of QCameraPicChannel * * PARAMETERS : none * * RETURN : none *==========================================================================*/ QCameraPicChannel::~QCameraPicChannel() { } /*=========================================================================== * FUNCTION : takePicture * * DESCRIPTION: send request for queued snapshot frames * * PARAMETERS : * @buf : request buf info * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraPicChannel::takePicture (mm_camera_req_buf_t *buf) { int32_t rc = m_camOps->request_super_buf(m_camHandle, m_handle, buf); return rc; } /*=========================================================================== * FUNCTION : cancelPicture * * DESCRIPTION: cancel request for queued snapshot frames * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraPicChannel::cancelPicture() { int32_t rc = m_camOps->cancel_super_buf_request(m_camHandle, m_handle); return rc; } /*=========================================================================== * FUNCTION : stopAdvancedCapture * * DESCRIPTION: stop advanced capture based on advanced capture type. * * PARAMETERS : * @type : advanced capture type. * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraPicChannel::stopAdvancedCapture(mm_camera_advanced_capture_t type) { int32_t rc = m_camOps->process_advanced_capture(m_camHandle, m_handle, type, 0, NULL); return rc; } /*=========================================================================== * FUNCTION : startAdvancedCapture * * DESCRIPTION: start advanced capture based on advanced capture type. * * PARAMETERS : * @type : advanced capture type. * @config: advance capture config * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraPicChannel::startAdvancedCapture(mm_camera_advanced_capture_t type, cam_capture_frame_config_t *config) { int32_t rc = NO_ERROR; rc = m_camOps->process_advanced_capture(m_camHandle, m_handle, type, 1, config); return rc; } /*=========================================================================== * FUNCTION : flushSuperbuffer * * DESCRIPTION: flush the all superbuffer frames. * * PARAMETERS : * @frame_idx : frame index of focused frame * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraPicChannel::flushSuperbuffer(uint32_t frame_idx) { int32_t rc = m_camOps->flush_super_buf_queue(m_camHandle, m_handle, frame_idx); return rc; } /*=========================================================================== * FUNCTION : QCameraVideoChannel * * DESCRIPTION: constructor of QCameraVideoChannel * * PARAMETERS : * @cam_handle : camera handle * @cam_ops : ptr to camera ops table * * RETURN : none *==========================================================================*/ QCameraVideoChannel::QCameraVideoChannel(uint32_t cam_handle, mm_camera_ops_t *cam_ops) : QCameraChannel(cam_handle, cam_ops) { } /*=========================================================================== * FUNCTION : QCameraVideoChannel * * DESCRIPTION: default constructor of QCameraVideoChannel * * PARAMETERS : none * * RETURN : none *==========================================================================*/ QCameraVideoChannel::QCameraVideoChannel() { } /*=========================================================================== * FUNCTION : ~QCameraVideoChannel * * DESCRIPTION: destructor of QCameraVideoChannel * * PARAMETERS : none * * RETURN : none *==========================================================================*/ QCameraVideoChannel::~QCameraVideoChannel() { } /*=========================================================================== * FUNCTION : takePicture * * DESCRIPTION: send request for queued snapshot frames * * PARAMETERS : * @mm_camera_req_buf_t : request buf info * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraVideoChannel::takePicture(mm_camera_req_buf_t *buf) { int32_t rc = m_camOps->request_super_buf(m_camHandle, m_handle, buf); return rc; } /*=========================================================================== * FUNCTION : cancelPicture * * DESCRIPTION: cancel request for queued snapshot frames * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraVideoChannel::cancelPicture() { int32_t rc = m_camOps->cancel_super_buf_request(m_camHandle, m_handle); return rc; } /*=========================================================================== * FUNCTION : releaseFrame * * DESCRIPTION: return video frame from app * * PARAMETERS : * @opaque : ptr to video frame to be returned * @isMetaData : if frame is a metadata or real frame * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraVideoChannel::releaseFrame(const void * opaque, bool isMetaData) { QCameraStream *pVideoStream = NULL; for (size_t i = 0; i < mStreams.size(); i++) { if (mStreams[i] != NULL && mStreams[i]->isTypeOf(CAM_STREAM_TYPE_VIDEO)) { pVideoStream = mStreams[i]; break; } } if (NULL == pVideoStream) { LOGE("No video stream in the channel"); return BAD_VALUE; } int32_t rc = pVideoStream->bufDone(opaque, isMetaData); return rc; } /*=========================================================================== * FUNCTION : QCameraReprocessChannel * * DESCRIPTION: constructor of QCameraReprocessChannel * * PARAMETERS : * @cam_handle : camera handle * @cam_ops : ptr to camera ops table * @pp_mask : post-proccess feature mask * * RETURN : none *==========================================================================*/ QCameraReprocessChannel::QCameraReprocessChannel(uint32_t cam_handle, mm_camera_ops_t *cam_ops) : QCameraChannel(cam_handle, cam_ops), m_pSrcChannel(NULL), mPassCount(0) { memset(mSrcStreamHandles, 0, sizeof(mSrcStreamHandles)); } /*=========================================================================== * FUNCTION : QCameraReprocessChannel * * DESCRIPTION: default constructor of QCameraReprocessChannel * * PARAMETERS : none * * RETURN : none *==========================================================================*/ QCameraReprocessChannel::QCameraReprocessChannel() : m_pSrcChannel(NULL), mPassCount(0) { } /*=========================================================================== * FUNCTION : ~QCameraReprocessChannel * * DESCRIPTION: destructor of QCameraReprocessChannel * * PARAMETERS : none * * RETURN : none *==========================================================================*/ QCameraReprocessChannel::~QCameraReprocessChannel() { } /*=========================================================================== * FUNCTION : addReprocStreamsFromSource * * DESCRIPTION: add reprocess streams from input source channel * * PARAMETERS : * @allocator : stream related buffer allocator * @featureConfig : pp feature configuration * @pSrcChannel : ptr to input source channel that needs reprocess * @minStreamBufNum: number of stream buffers needed * @burstNum : number of burst captures needed * @paddingInfo : padding information * @param : reference to parameters * @contStream : continous streaming mode or burst * @offline : configure for offline reprocessing * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraReprocessChannel::addReprocStreamsFromSource( QCameraAllocator& allocator, cam_pp_feature_config_t &featureConfig, QCameraChannel *pSrcChannel, uint8_t minStreamBufNum, uint8_t burstNum, cam_padding_info_t *paddingInfo, QCameraParametersIntf ¶m, bool contStream, bool offline) { int32_t rc = 0; QCameraStream *pStream = NULL; QCameraHeapMemory *pStreamInfoBuf = NULL; QCameraHeapMemory *pMiscBuf = NULL; cam_stream_info_t *streamInfo = NULL; cam_padding_info_t padding; memset(mSrcStreamHandles, 0, sizeof(mSrcStreamHandles)); if (NULL == paddingInfo) { return BAD_VALUE; } padding = *paddingInfo; //Use maximum padding so that the buffer //can be rotated padding.width_padding = MAX(padding.width_padding, padding.height_padding); padding.height_padding = padding.width_padding; padding.offset_info.offset_x = 0; padding.offset_info.offset_y = 0; LOGD("num of src stream = %d", pSrcChannel->getNumOfStreams()); for (uint32_t i = 0; i < pSrcChannel->getNumOfStreams(); i++) { cam_pp_feature_config_t pp_featuremask = featureConfig; pStream = pSrcChannel->getStreamByIndex(i); if (pStream != NULL) { if (param.getofflineRAW() && !((pStream->isTypeOf(CAM_STREAM_TYPE_RAW)) || (pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW)) || (pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) || (pStream->isOrignalTypeOf(CAM_STREAM_TYPE_RAW)))) { //Skip all the stream other than RAW and POSTVIEW incase of offline of RAW continue; } if (pStream->isTypeOf(CAM_STREAM_TYPE_RAW) && (!param.getofflineRAW())) { // Skip raw for reprocess now because PP module cannot handle // meta data&raw. May need furthur discussion if Imaginglib need meta data continue; } if (((pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) && !(param.getManualCaptureMode() >= CAM_MANUAL_CAPTURE_TYPE_3)) || (pStream->isTypeOf(CAM_STREAM_TYPE_ANALYSIS))) { // Skip metadata continue; } if (pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) || pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) || pStream->isOrignalTypeOf(CAM_STREAM_TYPE_PREVIEW) || pStream->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW)) { uint32_t feature_mask = featureConfig.feature_mask; // skip thumbnail reprocessing if not needed if (!param.needThumbnailReprocess(&feature_mask)) { continue; } // CAC, SHARPNESS, FLIP and WNR would have been already applied - // on preview/postview stream in realtime. // So, need not apply again. feature_mask &= ~(CAM_QCOM_FEATURE_DENOISE2D | CAM_QCOM_FEATURE_CAC | CAM_QCOM_FEATURE_SHARPNESS | CAM_QCOM_FEATURE_FLIP | CAM_QCOM_FEATURE_RAW_PROCESSING); if (!feature_mask) { // Skip thumbnail stream reprocessing since no other //reprocessing is enabled. continue; } } if (pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) { pp_featuremask.feature_mask = 0; pp_featuremask.feature_mask |= CAM_QCOM_FEATURE_METADATA_PROCESSING; } pStreamInfoBuf = allocator.allocateStreamInfoBuf(CAM_STREAM_TYPE_OFFLINE_PROC); if (pStreamInfoBuf == NULL) { LOGE("no mem for stream info buf"); rc = NO_MEMORY; break; } streamInfo = (cam_stream_info_t *)pStreamInfoBuf->getPtr(0); memset(streamInfo, 0, sizeof(cam_stream_info_t)); streamInfo->stream_type = CAM_STREAM_TYPE_OFFLINE_PROC; // Enable CPP high performance mode to put it in turbo frequency mode for // burst/longshot/HDR snapshot cases streamInfo->perf_mode = CAM_PERF_HIGH_PERFORMANCE; if (param.getofflineRAW() && pStream->isTypeOf(CAM_STREAM_TYPE_RAW)) { streamInfo->fmt = CAM_FORMAT_YUV_420_NV21; } else { rc = pStream->getFormat(streamInfo->fmt); } if (pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) || pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW)) { param.getThumbnailSize(&(streamInfo->dim.width), &(streamInfo->dim.height)); } else { if ((param.isPostProcScaling()) && (pp_featuremask.feature_mask & CAM_QCOM_FEATURE_SCALE)) { rc = param.getStreamDimension(CAM_STREAM_TYPE_OFFLINE_PROC, streamInfo->dim); } else if ((param.getofflineRAW()) && (pStream->isTypeOf(CAM_STREAM_TYPE_RAW))) { param.getStreamDimension(CAM_STREAM_TYPE_SNAPSHOT,streamInfo->dim); } else { rc = pStream->getFrameDimension(streamInfo->dim); } } if ( contStream ) { streamInfo->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS; streamInfo->num_of_burst = 0; } else { streamInfo->streaming_mode = CAM_STREAMING_MODE_BURST; streamInfo->num_of_burst = burstNum; } streamInfo->num_bufs = minStreamBufNum; cam_stream_reproc_config_t rp_cfg; memset(&rp_cfg, 0, sizeof(cam_stream_reproc_config_t)); if (offline) { cam_frame_len_offset_t offset; memset(&offset, 0, sizeof(cam_frame_len_offset_t)); rp_cfg.pp_type = CAM_OFFLINE_REPROCESS_TYPE; pStream->getFormat(rp_cfg.offline.input_fmt); pStream->getFrameDimension(rp_cfg.offline.input_dim); pStream->getFrameOffset(offset); rp_cfg.offline.input_buf_planes.plane_info = offset; rp_cfg.offline.input_type = pStream->getMyOriginalType(); //For input metadata + input buffer rp_cfg.offline.num_of_bufs = 2; } else { rp_cfg.pp_type = CAM_ONLINE_REPROCESS_TYPE; rp_cfg.online.input_stream_id = pStream->getMyServerID(); rp_cfg.online.input_stream_type = pStream->getMyOriginalType(); } param.getStreamRotation(streamInfo->stream_type, streamInfo->pp_config, streamInfo->dim); streamInfo->reprocess_config = rp_cfg; streamInfo->reprocess_config.pp_feature_config = pp_featuremask; if (!(pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) || pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT) || pStream->isTypeOf(CAM_STREAM_TYPE_RAW) || pStream->isOrignalTypeOf(CAM_STREAM_TYPE_RAW))) { // CAC, SHARPNESS, FLIP and WNR would have been already applied - // on preview/postview stream in realtime. Need not apply again. streamInfo->reprocess_config.pp_feature_config.feature_mask &= ~CAM_QCOM_FEATURE_CAC; streamInfo->reprocess_config.pp_feature_config.feature_mask &= ~CAM_QCOM_FEATURE_SHARPNESS; streamInfo->reprocess_config.pp_feature_config.feature_mask &= ~CAM_QCOM_FEATURE_FLIP; //Don't do WNR for thumbnail streamInfo->reprocess_config.pp_feature_config.feature_mask &= ~CAM_QCOM_FEATURE_DENOISE2D; streamInfo->reprocess_config.pp_feature_config.feature_mask &= ~CAM_QCOM_FEATURE_CDS; streamInfo->reprocess_config.pp_feature_config.feature_mask &= ~CAM_QCOM_FEATURE_DSDN; //No need of RAW processing for other than RAW streams streamInfo->reprocess_config.pp_feature_config.feature_mask &= ~CAM_QCOM_FEATURE_RAW_PROCESSING; if (param.isHDREnabled() && !param.isHDRThumbnailProcessNeeded()){ streamInfo->reprocess_config.pp_feature_config.feature_mask &= ~CAM_QCOM_FEATURE_HDR; } } cam_stream_type_t type = CAM_STREAM_TYPE_DEFAULT; if (offline) { type = streamInfo->reprocess_config.offline.input_type; } else { type = streamInfo->reprocess_config.online.input_stream_type; } if (type == CAM_STREAM_TYPE_SNAPSHOT) { int flipMode = param.getFlipMode(type); if (flipMode > 0) { streamInfo->reprocess_config.pp_feature_config.feature_mask |= CAM_QCOM_FEATURE_FLIP; streamInfo->reprocess_config.pp_feature_config.flip = (uint32_t)flipMode; } } if ((streamInfo->reprocess_config.pp_feature_config.feature_mask & CAM_QCOM_FEATURE_SCALE) && param.isReprocScaleEnabled() && param.isUnderReprocScaling()) { //we only Scale Snapshot frame if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT)) { streamInfo->dim.width = streamInfo->reprocess_config.pp_feature_config.scale_param.output_width; streamInfo->dim.height = streamInfo->reprocess_config.pp_feature_config.scale_param.output_height; } LOGH("stream width=%d, height=%d.", streamInfo->dim.width, streamInfo->dim.height); } // save source stream handler mSrcStreamHandles[mStreams.size()] = pStream->getMyHandle(); pMiscBuf = allocator.allocateMiscBuf(streamInfo); LOGH("Configure Reprocessing: stream = %d, res = %dX%d, fmt = %d, type = %d", pStream->getMyOriginalType(), streamInfo->dim.width, streamInfo->dim.height, streamInfo->fmt, type); // add reprocess stream if (streamInfo->reprocess_config.pp_feature_config.feature_mask & CAM_QCOM_FEATURE_ROTATION) { rc = addStream(allocator, pStreamInfoBuf, pMiscBuf, minStreamBufNum, &padding, NULL, NULL, false, false, streamInfo->reprocess_config.pp_feature_config.rotation); } else { rc = addStream(allocator, pStreamInfoBuf, pMiscBuf, minStreamBufNum, &padding, NULL, NULL, false, false); } if (rc != NO_ERROR) { LOGE("add reprocess stream failed, ret = %d", rc); break; } } } if (rc == NO_ERROR) { m_pSrcChannel = pSrcChannel; } return rc; } /*=========================================================================== * FUNCTION : getStreamBySrouceHandle * * DESCRIPTION: find reprocess stream by its source stream handle * * PARAMETERS : * @srcHandle : source stream handle * * RETURN : ptr to reprocess stream if found. NULL if not found *==========================================================================*/ QCameraStream * QCameraReprocessChannel::getStreamBySrouceHandle(uint32_t srcHandle) { QCameraStream *pStream = NULL; for (size_t i = 0; i < mStreams.size(); i++) { if (mSrcStreamHandles[i] == srcHandle) { pStream = mStreams[i]; break; } } return pStream; } /*=========================================================================== * FUNCTION : stop * * DESCRIPTION: stop channel and unmap offline buffers * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraReprocessChannel::stop() { int32_t rc = QCameraChannel::stop(); if (!mOfflineBuffers.empty()) { QCameraStream *stream = NULL; List::iterator it = mOfflineBuffers.begin(); int error = NO_ERROR; for( ; it != mOfflineBuffers.end(); it++) { stream = (*it).stream; if (NULL != stream) { error = stream->unmapBuf((*it).type, (*it).index, -1); if (NO_ERROR != error) { LOGE("Error during offline buffer unmap %d", error); } } } mOfflineBuffers.clear(); } return rc; } /*=========================================================================== * FUNCTION : doReprocessOffline * * DESCRIPTION: request to do offline reprocess on the frame * * PARAMETERS : * @frame : frame to be performed a reprocess * @meta_buf : Metadata buffer for reprocessing * @pStream : Actual reprocess stream * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraReprocessChannel::doReprocessOffline(mm_camera_buf_def_t *frame, mm_camera_buf_def_t *meta_buf, QCameraStream *pStream) { int32_t rc = 0; OfflineBuffer mappedBuffer; uint32_t buf_index = 0; uint32_t meta_buf_index = 0; if ((frame == NULL) || (meta_buf == NULL)) { LOGE("Invalid Input Paramters"); return INVALID_OPERATION; } if (pStream == NULL) { pStream = getStreamBySrouceHandle(frame->stream_id); if (pStream == NULL) { LOGE("Input validation failed."); return INVALID_OPERATION; } } if (!mOfflineBuffers.empty()) { List::iterator it = mOfflineBuffers.begin(); for( ; it != mOfflineBuffers.end(); it++) { buf_index = (buf_index < ((*it).index)) ? ((*it).index) : buf_index; } buf_index += 1; } meta_buf_index = buf_index; if (meta_buf != NULL) { rc = pStream->mapBuf(CAM_MAPPING_BUF_TYPE_OFFLINE_META_BUF, meta_buf_index, -1, meta_buf->fd, meta_buf->frame_len); if (NO_ERROR != rc ) { LOGE("Error during metadata buffer mapping"); rc = -1; return rc; } mappedBuffer.index = meta_buf_index; mappedBuffer.stream = pStream; mappedBuffer.type = CAM_MAPPING_BUF_TYPE_OFFLINE_META_BUF; mOfflineBuffers.push_back(mappedBuffer); buf_index += 1; } rc = pStream->mapBuf(CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF, buf_index, -1, frame->fd, frame->frame_len); if (NO_ERROR != rc ) { LOGE("Error during reprocess input buffer mapping"); rc = -1; return rc; } mappedBuffer.index = buf_index; mappedBuffer.stream = pStream; mappedBuffer.type = CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF; mOfflineBuffers.push_back(mappedBuffer); cam_stream_parm_buffer_t param; memset(¶m, 0, sizeof(cam_stream_parm_buffer_t)); param.type = CAM_STREAM_PARAM_TYPE_DO_REPROCESS; param.reprocess.buf_index = buf_index; param.reprocess.frame_idx = frame->frame_idx; if (meta_buf != NULL) { param.reprocess.meta_present = 1; param.reprocess.meta_buf_index = meta_buf_index; } LOGI("Offline reprocessing id = %d buf Id = %d meta index = %d type = %d", param.reprocess.frame_idx, param.reprocess.buf_index, param.reprocess.meta_buf_index, pStream->getMyOriginalType()); rc = pStream->setParameter(param); if (rc != NO_ERROR) { LOGE("stream setParameter for reprocess failed"); return rc; } return rc; } /*=========================================================================== * FUNCTION : doReprocessOffline * * DESCRIPTION: request to do offline reprocess on the frame * * PARAMETERS : * @frame : frame to be performed a reprocess * @meta_buf : Metadata buffer for reprocessing * @mParameter : camera parameters * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraReprocessChannel::doReprocessOffline(mm_camera_super_buf_t *frame, mm_camera_buf_def_t *meta_buf, QCameraParametersIntf &mParameter) { int32_t rc = 0; OfflineBuffer mappedBuffer; QCameraStream *pStream = NULL; if (mStreams.size() < 1) { LOGE("No reprocess streams"); return -1; } if (m_pSrcChannel == NULL) { LOGE("No source channel for reprocess"); return -1; } if (frame == NULL) { LOGE("Invalid source frame"); return BAD_VALUE; } for (uint32_t i = 0; i < frame->num_bufs; i++) { pStream = getStreamBySrouceHandle(frame->bufs[i]->stream_id); if ((pStream != NULL) && (m_handle == pStream->getChannelHandle())) { if (mParameter.getofflineRAW() && !((pStream->isOrignalTypeOf(CAM_STREAM_TYPE_RAW)) || (pStream->isOrignalTypeOf(CAM_STREAM_TYPE_METADATA)))) { continue; } if ((pStream->isOrignalTypeOf(CAM_STREAM_TYPE_METADATA) && (mParameter.getManualCaptureMode() < CAM_MANUAL_CAPTURE_TYPE_3)) || (pStream->isTypeOf(CAM_STREAM_TYPE_ANALYSIS))) { // Skip metadata for reprocess now because PP module cannot handle meta data // May need furthur discussion if Imaginglib need meta data continue; } // Update Metadata if (meta_buf != NULL) { uint32_t stream_id = frame->bufs[i]->stream_id; QCameraStream *srcStream = m_pSrcChannel->getStreamByHandle(stream_id); metadata_buffer_t *pMetaData = (metadata_buffer_t *)meta_buf->buffer; if ((NULL != pMetaData) && (NULL != srcStream)) { IF_META_AVAILABLE(cam_crop_data_t, crop, CAM_INTF_META_CROP_DATA, pMetaData) { if (MAX_NUM_STREAMS > crop->num_of_streams) { for (int j = 0; j < MAX_NUM_STREAMS; j++) { if (crop->crop_info[j].stream_id == srcStream->getMyServerID()) { // Store crop/roi information for offline reprocess // in the reprocess stream slot crop->crop_info[crop->num_of_streams].crop = crop->crop_info[j].crop; crop->crop_info[crop->num_of_streams].roi_map = crop->crop_info[j].roi_map; for (uint8_t k = 0; k < mStreams.size(); k++) { if (srcStream->getMyType() == mStreams[k]->getMyOriginalType()) { crop->crop_info[crop->num_of_streams].stream_id = mStreams[k]->getMyServerID(); break; } } crop->num_of_streams++; break; } } } else { LOGE("No space to add reprocess stream crop/roi information"); } } } } rc = doReprocessOffline (frame->bufs[i], meta_buf, pStream); } } return rc; } /*=========================================================================== * FUNCTION : doReprocess * * DESCRIPTION: request to do a reprocess on the frame * * PARAMETERS : * @frame : frame to be performed a reprocess * @mParameter : camera parameters * @pMetaStream: Metadata stream handle * @meta_buf_index : Metadata buffer index * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraReprocessChannel::doReprocess(mm_camera_super_buf_t *frame, QCameraParametersIntf &mParameter, QCameraStream *pMetaStream, uint8_t meta_buf_index) { int32_t rc = 0; if (mStreams.size() < 1) { LOGE("No reprocess streams"); return -1; } if (m_pSrcChannel == NULL) { LOGE("No source channel for reprocess"); return -1; } if (pMetaStream == NULL) { LOGW("Null Metadata buffer for processing"); } for (uint32_t i = 0; i < frame->num_bufs; i++) { QCameraStream *pStream = getStreamBySrouceHandle(frame->bufs[i]->stream_id); if ((pStream != NULL) && (m_handle == pStream->getChannelHandle())) { if (mParameter.getofflineRAW() && !((pStream->isOrignalTypeOf(CAM_STREAM_TYPE_RAW)) || (pStream->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW)) || (pStream->isOrignalTypeOf(CAM_STREAM_TYPE_METADATA)))) { //Skip all the stream other than RAW and POSTVIEW incase of offline of RAW continue; } if ((pStream->isOrignalTypeOf(CAM_STREAM_TYPE_METADATA) && (mParameter.getManualCaptureMode() < CAM_MANUAL_CAPTURE_TYPE_3)) || (pStream->isTypeOf(CAM_STREAM_TYPE_ANALYSIS))) { // Skip metadata for reprocess now because PP module cannot handle meta data // May need furthur discussion if Imaginglib need meta data continue; } cam_stream_parm_buffer_t param; memset(¶m, 0, sizeof(cam_stream_parm_buffer_t)); param.type = CAM_STREAM_PARAM_TYPE_DO_REPROCESS; param.reprocess.buf_index = frame->bufs[i]->buf_idx; param.reprocess.frame_idx = frame->bufs[i]->frame_idx; if (pMetaStream != NULL) { // we have meta data frame bundled, sent together with reprocess frame param.reprocess.meta_present = 1; param.reprocess.meta_stream_handle = pMetaStream->getMyServerID(); param.reprocess.meta_buf_index = meta_buf_index; } LOGI("Online reprocessing id = %d buf Id = %d meta index = %d type = %d", param.reprocess.frame_idx, param.reprocess.buf_index, param.reprocess.meta_buf_index, pStream->getMyOriginalType()); rc = pStream->setParameter(param); if (rc != NO_ERROR) { LOGE("stream setParameter for reprocess failed"); break; } } } return rc; } /*=========================================================================== * FUNCTION : doReprocess * * DESCRIPTION: request to do a reprocess on the frame * * PARAMETERS : * @buf_fd : fd to the input buffer that needs reprocess * @buf_lenght : length of the input buffer * @ret_val : result of reprocess. * Example: Could be faceID in case of register face image. * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCameraReprocessChannel::doReprocess(int buf_fd, size_t buf_length, int32_t &ret_val) { int32_t rc = 0; if (mStreams.size() < 1) { LOGE("No reprocess streams"); return -1; } uint32_t buf_idx = 0; for (size_t i = 0; i < mStreams.size(); i++) { if ((mStreams[i] != NULL) && (m_handle != mStreams[i]->getChannelHandle())) { continue; } rc = mStreams[i]->mapBuf(CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF, buf_idx, -1, buf_fd, buf_length); if (rc == NO_ERROR) { cam_stream_parm_buffer_t param; memset(¶m, 0, sizeof(cam_stream_parm_buffer_t)); param.type = CAM_STREAM_PARAM_TYPE_DO_REPROCESS; param.reprocess.buf_index = buf_idx; rc = mStreams[i]->setParameter(param); if (rc == NO_ERROR) { ret_val = param.reprocess.ret_val; } mStreams[i]->unmapBuf(CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF, buf_idx, -1); } } return rc; } }; // namespace qcamera