diff options
Diffstat (limited to '')
-rw-r--r-- | camera/QCamera2/HAL3/QCamera3Stream.cpp | 1527 |
1 files changed, 1527 insertions, 0 deletions
diff --git a/camera/QCamera2/HAL3/QCamera3Stream.cpp b/camera/QCamera2/HAL3/QCamera3Stream.cpp new file mode 100644 index 0000000..71935e8 --- /dev/null +++ b/camera/QCamera2/HAL3/QCamera3Stream.cpp @@ -0,0 +1,1527 @@ +/* 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 "QCamera3Stream" + +// Camera dependencies +#include "QCamera3HWI.h" +#include "QCamera3Stream.h" + +extern "C" { +#include "mm_camera_dbg.h" +} + +using namespace android; + +namespace qcamera { +#define MAX_BATCH_SIZE 32 + +const char* QCamera3Stream::mStreamNames[] = { + "CAM_DEFAULT", + "CAM_PREVIEW", + "CAM_POSTVIEW", + "CAM_SNAPSHOT", + "CAM_VIDEO", + "CAM_CALLBACK", + "CAM_IMPL_DEFINED", + "CAM_METADATA", + "CAM_RAW", + "CAM_OFFLINE_PROC", + "CAM_PARM", + "CAM_ANALYSIS" + "CAM_MAX" }; + +/*=========================================================================== + * FUNCTION : get_bufs + * + * DESCRIPTION: static function entry to allocate stream buffers + * + * PARAMETERS : + * @offset : offset info of stream buffers + * @num_bufs : number of buffers allocated + * @initial_reg_flag: flag to indicate if buffer needs to be registered + * at kernel initially + * @bufs : output of allocated buffers + * @ops_tbl : ptr to buf mapping/unmapping ops + * @user_data : user data ptr of ops_tbl + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::get_bufs( + cam_frame_len_offset_t *offset, + uint8_t *num_bufs, + uint8_t **initial_reg_flag, + mm_camera_buf_def_t **bufs, + mm_camera_map_unmap_ops_tbl_t *ops_tbl, + void *user_data) +{ + int32_t rc = NO_ERROR; + QCamera3Stream *stream = reinterpret_cast<QCamera3Stream *>(user_data); + if (!stream) { + LOGE("getBufs invalid stream pointer"); + return NO_MEMORY; + } + rc = stream->getBufs(offset, num_bufs, initial_reg_flag, bufs, ops_tbl); + if (NO_ERROR != rc) { + LOGE("stream->getBufs failed"); + return NO_MEMORY; + } + if (stream->mBatchSize) { + //Allocate batch buffers if mBatchSize is non-zero. All the output + //arguments correspond to batch containers and not image buffers + rc = stream->getBatchBufs(num_bufs, initial_reg_flag, + bufs, ops_tbl); + } + return rc; +} + +/*=========================================================================== + * FUNCTION : put_bufs + * + * DESCRIPTION: static function entry to deallocate stream buffers + * + * PARAMETERS : + * @ops_tbl : ptr to buf mapping/unmapping ops + * @user_data : user data ptr of ops_tbl + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::put_bufs( + mm_camera_map_unmap_ops_tbl_t *ops_tbl, + void *user_data) +{ + int32_t rc = NO_ERROR; + QCamera3Stream *stream = reinterpret_cast<QCamera3Stream *>(user_data); + if (!stream) { + LOGE("putBufs invalid stream pointer"); + return NO_MEMORY; + } + + if (stream->mBatchSize) { + rc = stream->putBatchBufs(ops_tbl); + if (NO_ERROR != rc) { + LOGE("stream->putBatchBufs failed"); + } + } + rc = stream->putBufs(ops_tbl); + return rc; +} + +/*=========================================================================== + * FUNCTION : invalidate_buf + * + * DESCRIPTION: static function entry to invalidate a specific stream buffer + * + * PARAMETERS : + * @index : index of the stream buffer to invalidate + * @user_data : user data ptr of ops_tbl + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::invalidate_buf(uint32_t index, void *user_data) +{ + int32_t rc = NO_ERROR; + + QCamera3Stream *stream = reinterpret_cast<QCamera3Stream *>(user_data); + if (!stream) { + LOGE("invalid stream pointer"); + return NO_MEMORY; + } + if (stream->mBatchSize) { + int32_t retVal = NO_ERROR; + for (size_t i = 0; + i < stream->mBatchBufDefs[index].user_buf.bufs_used; i++) { + uint32_t buf_idx = stream->mBatchBufDefs[index].user_buf.buf_idx[i]; + retVal = stream->invalidateBuf(buf_idx); + if (NO_ERROR != retVal) { + LOGE("invalidateBuf failed for buf_idx: %d err: %d", + buf_idx, retVal); + } + rc |= retVal; + } + } else { + rc = stream->invalidateBuf(index); + } + return rc; +} + +/*=========================================================================== + * FUNCTION : clean_invalidate_buf + * + * DESCRIPTION: static function entry to clean and invalidate a specific stream buffer + * + * PARAMETERS : + * @index : index of the stream buffer to invalidate + * @user_data : user data ptr of ops_tbl + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::clean_invalidate_buf(uint32_t index, void *user_data) +{ + int32_t rc = NO_ERROR; + + QCamera3Stream *stream = reinterpret_cast<QCamera3Stream *>(user_data); + if (!stream) { + LOGE("invalid stream pointer"); + return NO_MEMORY; + } + if (stream->mBatchSize) { + int32_t retVal = NO_ERROR; + for (size_t i = 0; + i < stream->mBatchBufDefs[index].user_buf.bufs_used; i++) { + uint32_t buf_idx = stream->mBatchBufDefs[index].user_buf.buf_idx[i]; + retVal = stream->cleanInvalidateBuf(buf_idx); + if (NO_ERROR != retVal) { + LOGE("invalidateBuf failed for buf_idx: %d err: %d", + buf_idx, retVal); + } + rc |= retVal; + } + } else { + rc = stream->cleanInvalidateBuf(index); + } + return rc; +} + +/*=========================================================================== + * FUNCTION : QCamera3Stream + * + * DESCRIPTION: constructor of QCamera3Stream + * + * PARAMETERS : + * @allocator : memory allocator obj + * @camHandle : camera handle + * @chId : channel handle + * @camOps : ptr to camera ops table + * @paddingInfo: ptr to padding info + * + * RETURN : None + *==========================================================================*/ +QCamera3Stream::QCamera3Stream(uint32_t camHandle, + uint32_t chId, + mm_camera_ops_t *camOps, + cam_padding_info_t *paddingInfo, + QCamera3Channel *channel) : + mCamHandle(camHandle), + mChannelHandle(chId), + mHandle(0), + mCamOps(camOps), + mStreamInfo(NULL), + mMemOps(NULL), + mNumBufs(0), + mDataCB(NULL), + mUserData(NULL), + mDataQ(releaseFrameData, this), + mStreamInfoBuf(NULL), + mStreamBufs(NULL), + mBufDefs(NULL), + mChannel(channel), + mBatchSize(0), + mNumBatchBufs(0), + mStreamBatchBufs(NULL), + mBatchBufDefs(NULL), + mCurrentBatchBufDef(NULL), + mBufsStaged(0), + mFreeBatchBufQ(NULL, this) +{ + mMemVtbl.user_data = this; + mMemVtbl.get_bufs = get_bufs; + mMemVtbl.put_bufs = put_bufs; + mMemVtbl.invalidate_buf = invalidate_buf; + mMemVtbl.clean_invalidate_buf = clean_invalidate_buf; + mMemVtbl.set_config_ops = NULL; + memset(&mFrameLenOffset, 0, sizeof(mFrameLenOffset)); + memcpy(&mPaddingInfo, paddingInfo, sizeof(cam_padding_info_t)); +} + +/*=========================================================================== + * FUNCTION : ~QCamera3Stream + * + * DESCRIPTION: deconstructor of QCamera3Stream + * + * PARAMETERS : None + * + * RETURN : None + *==========================================================================*/ +QCamera3Stream::~QCamera3Stream() +{ + if (mStreamInfoBuf != NULL) { + int rc = mCamOps->unmap_stream_buf(mCamHandle, + mChannelHandle, mHandle, CAM_MAPPING_BUF_TYPE_STREAM_INFO, 0, -1); + if (rc < 0) { + LOGE("Failed to un-map stream info buffer"); + } + mStreamInfoBuf->deallocate(); + delete mStreamInfoBuf; + mStreamInfoBuf = NULL; + } + // delete stream + if (mHandle > 0) { + mCamOps->delete_stream(mCamHandle, mChannelHandle, mHandle); + mHandle = 0; + } +} + +/*=========================================================================== + * FUNCTION : init + * + * DESCRIPTION: initialize stream obj + * + * PARAMETERS : + * @streamType : stream type + * @streamFormat : stream format + * @streamDim : stream dimension + * @reprocess_config: reprocess stream input configuration + * @minNumBuffers : minimal buffer count for particular stream type + * @postprocess_mask: PP mask + * @is_type : Image stabilization type, cam_is_type_t + * @batchSize : Number of image buffers in a batch. + * 0: No batch. N: container with N image buffers + * @stream_cb : callback handle + * @userdata : user data + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::init(cam_stream_type_t streamType, + cam_format_t streamFormat, + cam_dimension_t streamDim, + cam_rotation_t streamRotation, + cam_stream_reproc_config_t* reprocess_config, + uint8_t minNumBuffers, + cam_feature_mask_t postprocess_mask, + cam_is_type_t is_type, + uint32_t batchSize, + hal3_stream_cb_routine stream_cb, + void *userdata) +{ + int32_t rc = OK; + ssize_t bufSize = BAD_INDEX; + mm_camera_stream_config_t stream_config; + LOGD("batch size is %d", batchSize); + + mHandle = mCamOps->add_stream(mCamHandle, mChannelHandle); + if (!mHandle) { + LOGE("add_stream failed"); + rc = UNKNOWN_ERROR; + goto done; + } + + // allocate and map stream info memory + mStreamInfoBuf = new QCamera3HeapMemory(1); + if (mStreamInfoBuf == NULL) { + LOGE("no memory for stream info buf obj"); + rc = -ENOMEM; + goto err1; + } + rc = mStreamInfoBuf->allocate(sizeof(cam_stream_info_t)); + if (rc < 0) { + LOGE("no memory for stream info"); + rc = -ENOMEM; + goto err2; + } + + mStreamInfo = + reinterpret_cast<cam_stream_info_t *>(mStreamInfoBuf->getPtr(0)); + memset(mStreamInfo, 0, sizeof(cam_stream_info_t)); + mStreamInfo->stream_type = streamType; + mStreamInfo->fmt = streamFormat; + mStreamInfo->dim = streamDim; + mStreamInfo->num_bufs = minNumBuffers; + mStreamInfo->pp_config.feature_mask = postprocess_mask; + mStreamInfo->is_type = is_type; + mStreamInfo->pp_config.rotation = streamRotation; + LOGD("stream_type is %d, feature_mask is %Ld", + mStreamInfo->stream_type, mStreamInfo->pp_config.feature_mask); + + bufSize = mStreamInfoBuf->getSize(0); + if (BAD_INDEX != bufSize) { + rc = mCamOps->map_stream_buf(mCamHandle, + mChannelHandle, mHandle, CAM_MAPPING_BUF_TYPE_STREAM_INFO, + 0, -1, mStreamInfoBuf->getFd(0), (size_t)bufSize); + if (rc < 0) { + LOGE("Failed to map stream info buffer"); + goto err3; + } + } else { + LOGE("Failed to retrieve buffer size (bad index)"); + goto err3; + } + + mNumBufs = minNumBuffers; + if (reprocess_config != NULL) { + mStreamInfo->reprocess_config = *reprocess_config; + mStreamInfo->streaming_mode = CAM_STREAMING_MODE_BURST; + //mStreamInfo->num_of_burst = reprocess_config->offline.num_of_bufs; + mStreamInfo->num_of_burst = 1; + } else if (batchSize) { + if (batchSize > MAX_BATCH_SIZE) { + LOGE("batchSize:%d is very large", batchSize); + rc = BAD_VALUE; + goto err4; + } + else { + mNumBatchBufs = MAX_INFLIGHT_HFR_REQUESTS / batchSize; + mStreamInfo->streaming_mode = CAM_STREAMING_MODE_BATCH; + mStreamInfo->user_buf_info.frame_buf_cnt = batchSize; + mStreamInfo->user_buf_info.size = + (uint32_t)(sizeof(msm_camera_user_buf_cont_t)); + mStreamInfo->num_bufs = mNumBatchBufs; + //Frame interval is irrelavent since time stamp calculation is not + //required from the mCamOps + mStreamInfo->user_buf_info.frameInterval = 0; + LOGD("batch size is %d", batchSize); + } + } else { + mStreamInfo->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS; + } + + // Configure the stream + stream_config.stream_info = mStreamInfo; + stream_config.mem_vtbl = mMemVtbl; + stream_config.padding_info = mPaddingInfo; + stream_config.userdata = this; + stream_config.stream_cb = dataNotifyCB; + stream_config.stream_cb_sync = NULL; + + rc = mCamOps->config_stream(mCamHandle, + mChannelHandle, mHandle, &stream_config); + if (rc < 0) { + LOGE("Failed to config stream, rc = %d", rc); + goto err4; + } + + mDataCB = stream_cb; + mUserData = userdata; + mBatchSize = batchSize; + return 0; + +err4: + mCamOps->unmap_stream_buf(mCamHandle, + mChannelHandle, mHandle, CAM_MAPPING_BUF_TYPE_STREAM_INFO, 0, -1); +err3: + mStreamInfoBuf->deallocate(); +err2: + delete mStreamInfoBuf; + mStreamInfoBuf = NULL; + mStreamInfo = NULL; +err1: + mCamOps->delete_stream(mCamHandle, mChannelHandle, mHandle); + mHandle = 0; + mNumBufs = 0; +done: + return rc; +} + +/*=========================================================================== + * FUNCTION : start + * + * DESCRIPTION: start stream. Will start main stream thread to handle stream + * related ops. + * + * PARAMETERS : none + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::start() +{ + int32_t rc = 0; + + mDataQ.init(); + if (mBatchSize) + mFreeBatchBufQ.init(); + rc = mProcTh.launch(dataProcRoutine, this); + return rc; +} + +/*=========================================================================== + * FUNCTION : stop + * + * DESCRIPTION: stop stream. Will stop main stream thread + * + * PARAMETERS : none + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::stop() +{ + int32_t rc = 0; + rc = mProcTh.exit(); + return rc; +} + +/*=========================================================================== + * FUNCTION : processDataNotify + * + * DESCRIPTION: process stream data notify + * + * PARAMETERS : + * @frame : stream frame received + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::processDataNotify(mm_camera_super_buf_t *frame) +{ + LOGD("E\n"); + int32_t rc; + if (mDataQ.enqueue((void *)frame)) { + rc = mProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); + } else { + LOGD("Stream thread is not active, no ops here"); + bufDone(frame->bufs[0]->buf_idx); + free(frame); + rc = NO_ERROR; + } + LOGD("X\n"); + return rc; +} + +/*=========================================================================== + * FUNCTION : dataNotifyCB + * + * DESCRIPTION: callback for data notify. This function is registered with + * mm-camera-interface to handle data notify + * + * PARAMETERS : + * @recvd_frame : stream frame received + * userdata : user data ptr + * + * RETURN : none + *==========================================================================*/ +void QCamera3Stream::dataNotifyCB(mm_camera_super_buf_t *recvd_frame, + void *userdata) +{ + LOGD("E\n"); + QCamera3Stream* stream = (QCamera3Stream *)userdata; + if (stream == NULL || + recvd_frame == NULL || + recvd_frame->bufs[0] == NULL || + recvd_frame->bufs[0]->stream_id != stream->getMyHandle()) { + LOGE("Not a valid stream to handle buf"); + return; + } + + mm_camera_super_buf_t *frame = + (mm_camera_super_buf_t *)malloc(sizeof(mm_camera_super_buf_t)); + if (frame == NULL) { + LOGE("No mem for mm_camera_buf_def_t"); + stream->bufDone(recvd_frame->bufs[0]->buf_idx); + return; + } + *frame = *recvd_frame; + stream->processDataNotify(frame); + return; +} + +/*=========================================================================== + * FUNCTION : dataProcRoutine + * + * DESCRIPTION: function to process data in the main stream thread + * + * PARAMETERS : + * @data : user data ptr + * + * RETURN : none + *==========================================================================*/ +void *QCamera3Stream::dataProcRoutine(void *data) +{ + int running = 1; + int ret; + QCamera3Stream *pme = (QCamera3Stream *)data; + QCameraCmdThread *cmdThread = &pme->mProcTh; + + cmdThread->setName(mStreamNames[pme->mStreamInfo->stream_type]); + + LOGD("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_DO_NEXT_JOB: + { + LOGD("Do next job"); + mm_camera_super_buf_t *frame = + (mm_camera_super_buf_t *)pme->mDataQ.dequeue(); + if (NULL != frame) { + if (UNLIKELY(frame->bufs[0]->buf_type == + CAM_STREAM_BUF_TYPE_USERPTR)) { + pme->handleBatchBuffer(frame); + } else if (pme->mDataCB != NULL) { + pme->mDataCB(frame, pme, pme->mUserData); + } else { + // no data cb routine, return buf here + pme->bufDone(frame->bufs[0]->buf_idx); + } + } + } + break; + case CAMERA_CMD_TYPE_EXIT: + LOGH("Exit"); + /* flush data buf queue */ + pme->mDataQ.flush(); + pme->flushFreeBatchBufQ(); + running = 0; + break; + default: + break; + } + } while (running); + LOGD("X"); + return NULL; +} + +/*=========================================================================== + * FUNCTION : bufDone + * + * DESCRIPTION: return stream buffer to kernel + * + * PARAMETERS : + * @index : index of buffer to be returned + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::bufDone(uint32_t index) +{ + int32_t rc = NO_ERROR; + Mutex::Autolock lock(mLock); + + if ((index >= mNumBufs) || (mBufDefs == NULL)) { + LOGE("index; %d, mNumBufs: %d", index, mNumBufs); + return BAD_INDEX; + } + if (mStreamBufs == NULL) + { + LOGE("putBufs already called"); + return INVALID_OPERATION; + } + + if( NULL == mBufDefs[index].mem_info) { + if (NULL == mMemOps) { + LOGE("Camera operations not initialized"); + return NO_INIT; + } + + ssize_t bufSize = mStreamBufs->getSize(index); + + if (BAD_INDEX != bufSize) { + LOGD("Map streamBufIdx: %d", index); + rc = mMemOps->map_ops(index, -1, mStreamBufs->getFd(index), + (size_t)bufSize, CAM_MAPPING_BUF_TYPE_STREAM_BUF, mMemOps->userdata); + if (rc < 0) { + LOGE("Failed to map camera buffer %d", index); + return rc; + } + + rc = mStreamBufs->getBufDef(mFrameLenOffset, mBufDefs[index], index); + if (NO_ERROR != rc) { + LOGE("Couldn't find camera buffer definition"); + mMemOps->unmap_ops(index, -1, CAM_MAPPING_BUF_TYPE_STREAM_BUF, mMemOps->userdata); + return rc; + } + } else { + LOGE("Failed to retrieve buffer size (bad index)"); + return INVALID_OPERATION; + } + } + + if (UNLIKELY(mBatchSize)) { + rc = aggregateBufToBatch(mBufDefs[index]); + } else { + rc = mCamOps->qbuf(mCamHandle, mChannelHandle, &mBufDefs[index]); + if (rc < 0) { + return FAILED_TRANSACTION; + } + } + + return rc; +} + +/*=========================================================================== + * FUNCTION : bufRelease + * + * DESCRIPTION: release all resources associated with this buffer + * + * PARAMETERS : + * @index : index of buffer to be released + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::bufRelease(int32_t index) +{ + int32_t rc = NO_ERROR; + Mutex::Autolock lock(mLock); + + if ((index >= mNumBufs) || (mBufDefs == NULL)) { + return BAD_INDEX; + } + + if (NULL != mBufDefs[index].mem_info) { + if (NULL == mMemOps) { + LOGE("Camera operations not initialized"); + return NO_INIT; + } + + rc = mMemOps->unmap_ops(index, -1, CAM_MAPPING_BUF_TYPE_STREAM_BUF, + mMemOps->userdata); + if (rc < 0) { + LOGE("Failed to un-map camera buffer %d", index); + return rc; + } + + mBufDefs[index].mem_info = NULL; + } else { + LOGE("Buffer at index %d not registered"); + return BAD_INDEX; + } + + return rc; +} + +/*=========================================================================== + * FUNCTION : getBufs + * + * DESCRIPTION: allocate stream buffers + * + * PARAMETERS : + * @offset : offset info of stream buffers + * @num_bufs : number of buffers allocated + * @initial_reg_flag: flag to indicate if buffer needs to be registered + * at kernel initially + * @bufs : output of allocated buffers + * @ops_tbl : ptr to buf mapping/unmapping ops + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::getBufs(cam_frame_len_offset_t *offset, + uint8_t *num_bufs, + uint8_t **initial_reg_flag, + mm_camera_buf_def_t **bufs, + mm_camera_map_unmap_ops_tbl_t *ops_tbl) +{ + int rc = NO_ERROR; + uint8_t *regFlags; + Mutex::Autolock lock(mLock); + + if (!ops_tbl) { + LOGE("ops_tbl is NULL"); + return INVALID_OPERATION; + } + + mFrameLenOffset = *offset; + mMemOps = ops_tbl; + + if (mStreamBufs != NULL) { + LOGE("Failed getBufs being called twice in a row without a putBufs call"); + return INVALID_OPERATION; + } + mStreamBufs = mChannel->getStreamBufs(mFrameLenOffset.frame_len); + if (!mStreamBufs) { + LOGE("Failed to allocate stream buffers"); + return NO_MEMORY; + } + + for (uint32_t i = 0; i < mNumBufs; i++) { + if (mStreamBufs->valid(i)) { + ssize_t bufSize = mStreamBufs->getSize(i); + if (BAD_INDEX != bufSize) { + rc = ops_tbl->map_ops(i, -1, mStreamBufs->getFd(i), + (size_t)bufSize, CAM_MAPPING_BUF_TYPE_STREAM_BUF, + ops_tbl->userdata); + if (rc < 0) { + LOGE("map_stream_buf failed: %d", rc); + for (uint32_t j = 0; j < i; j++) { + if (mStreamBufs->valid(j)) { + ops_tbl->unmap_ops(j, -1, + CAM_MAPPING_BUF_TYPE_STREAM_BUF, + ops_tbl->userdata); + } + } + return INVALID_OPERATION; + } + } else { + LOGE("Failed to retrieve buffer size (bad index)"); + return INVALID_OPERATION; + } + } + } + + //regFlags array is allocated by us, but consumed and freed by mm-camera-interface + regFlags = (uint8_t *)malloc(sizeof(uint8_t) * mNumBufs); + if (!regFlags) { + LOGE("Out of memory"); + for (uint32_t i = 0; i < mNumBufs; i++) { + if (mStreamBufs->valid(i)) { + ops_tbl->unmap_ops(i, -1, CAM_MAPPING_BUF_TYPE_STREAM_BUF, + ops_tbl->userdata); + } + } + return NO_MEMORY; + } + memset(regFlags, 0, sizeof(uint8_t) * mNumBufs); + + mBufDefs = (mm_camera_buf_def_t *)malloc(mNumBufs * sizeof(mm_camera_buf_def_t)); + if (mBufDefs == NULL) { + LOGE("Failed to allocate mm_camera_buf_def_t %d", rc); + for (uint32_t i = 0; i < mNumBufs; i++) { + if (mStreamBufs->valid(i)) { + ops_tbl->unmap_ops(i, -1, CAM_MAPPING_BUF_TYPE_STREAM_BUF, + ops_tbl->userdata); + } + } + free(regFlags); + regFlags = NULL; + return INVALID_OPERATION; + } + memset(mBufDefs, 0, mNumBufs * sizeof(mm_camera_buf_def_t)); + for (uint32_t i = 0; i < mNumBufs; i++) { + if (mStreamBufs->valid(i)) { + mStreamBufs->getBufDef(mFrameLenOffset, mBufDefs[i], i); + } + } + + rc = mStreamBufs->getRegFlags(regFlags); + if (rc < 0) { + LOGE("getRegFlags failed %d", rc); + for (uint32_t i = 0; i < mNumBufs; i++) { + if (mStreamBufs->valid(i)) { + ops_tbl->unmap_ops(i, -1, CAM_MAPPING_BUF_TYPE_STREAM_BUF, + ops_tbl->userdata); + } + } + free(mBufDefs); + mBufDefs = NULL; + free(regFlags); + regFlags = NULL; + return INVALID_OPERATION; + } + + *num_bufs = mNumBufs; + *initial_reg_flag = regFlags; + *bufs = mBufDefs; + return NO_ERROR; +} + +/*=========================================================================== + * FUNCTION : putBufs + * + * DESCRIPTION: deallocate stream buffers + * + * PARAMETERS : + * @ops_tbl : ptr to buf mapping/unmapping ops + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::putBufs(mm_camera_map_unmap_ops_tbl_t *ops_tbl) +{ + int rc = NO_ERROR; + Mutex::Autolock lock(mLock); + + for (uint32_t i = 0; i < mNumBufs; i++) { + if (mStreamBufs->valid(i) && NULL != mBufDefs[i].mem_info) { + rc = ops_tbl->unmap_ops(i, -1, CAM_MAPPING_BUF_TYPE_STREAM_BUF, ops_tbl->userdata); + if (rc < 0) { + LOGE("un-map stream buf failed: %d", rc); + } + } + } + mBufDefs = NULL; // mBufDefs just keep a ptr to the buffer + // mm-camera-interface own the buffer, so no need to free + memset(&mFrameLenOffset, 0, sizeof(mFrameLenOffset)); + + if (mStreamBufs == NULL) { + LOGE("getBuf failed previously, or calling putBufs twice"); + } + + mChannel->putStreamBufs(); + + //need to set mStreamBufs to null because putStreamBufs deletes that memory + mStreamBufs = NULL; + + return rc; +} + +/*=========================================================================== + * FUNCTION : invalidateBuf + * + * DESCRIPTION: invalidate a specific stream buffer + * + * PARAMETERS : + * @index : index of the buffer to invalidate + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::invalidateBuf(uint32_t index) +{ + if (mStreamBufs == NULL) { + LOGE("putBufs already called"); + return INVALID_OPERATION; + } else + return mStreamBufs->invalidateCache(index); +} + +/*=========================================================================== + * FUNCTION : cleanInvalidateBuf + * + * DESCRIPTION: clean and invalidate a specific stream buffer + * + * PARAMETERS : + * @index : index of the buffer to invalidate + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::cleanInvalidateBuf(uint32_t index) +{ + if (mStreamBufs == NULL) { + LOGE("putBufs already called"); + return INVALID_OPERATION; + } else + return mStreamBufs->cleanInvalidateCache(index); +} + +/*=========================================================================== + * FUNCTION : getFrameOffset + * + * DESCRIPTION: query stream buffer frame offset info + * + * PARAMETERS : + * @offset : reference to struct to store the queried frame offset info + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::getFrameOffset(cam_frame_len_offset_t &offset) +{ + offset = mFrameLenOffset; + return 0; +} + +/*=========================================================================== + * FUNCTION : getFrameDimension + * + * DESCRIPTION: query stream frame dimension info + * + * PARAMETERS : + * @dim : reference to struct to store the queried frame dimension + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::getFrameDimension(cam_dimension_t &dim) +{ + if (mStreamInfo != NULL) { + dim = mStreamInfo->dim; + return 0; + } + return -1; +} + +/*=========================================================================== + * FUNCTION : getFormat + * + * DESCRIPTION: query stream format + * + * PARAMETERS : + * @fmt : reference to stream format + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::getFormat(cam_format_t &fmt) +{ + if (mStreamInfo != NULL) { + fmt = mStreamInfo->fmt; + return 0; + } + return -1; +} + +/*=========================================================================== + * FUNCTION : getMyServerID + * + * DESCRIPTION: query server stream ID + * + * PARAMETERS : None + * + * RETURN : stream ID from server + *==========================================================================*/ +uint32_t QCamera3Stream::getMyServerID() { + if (mStreamInfo != NULL) { + return mStreamInfo->stream_svr_id; + } else { + return 0; + } +} + +/*=========================================================================== + * FUNCTION : getMyType + * + * DESCRIPTION: query stream type + * + * PARAMETERS : None + * + * RETURN : type of stream + *==========================================================================*/ +cam_stream_type_t QCamera3Stream::getMyType() const +{ + if (mStreamInfo != NULL) { + return mStreamInfo->stream_type; + } else { + return CAM_STREAM_TYPE_MAX; + } +} + +/*=========================================================================== + * FUNCTION : mapBuf + * + * DESCRIPTION: map stream related buffer to backend server + * + * PARAMETERS : + * @buf_type : mapping type of buffer + * @buf_idx : index of buffer + * @plane_idx: plane index + * @fd : fd of the buffer + * @size : lenght of the buffer + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::mapBuf(uint8_t buf_type, uint32_t buf_idx, + int32_t plane_idx, int fd, size_t size) +{ + return mCamOps->map_stream_buf(mCamHandle, mChannelHandle, + mHandle, buf_type, + buf_idx, plane_idx, + fd, size); + +} + +/*=========================================================================== + * FUNCTION : unmapBuf + * + * DESCRIPTION: unmap stream related buffer to backend server + * + * PARAMETERS : + * @buf_type : mapping type of buffer + * @buf_idx : index of buffer + * @plane_idx: plane index + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::unmapBuf(uint8_t buf_type, uint32_t buf_idx, int32_t plane_idx) +{ + return mCamOps->unmap_stream_buf(mCamHandle, mChannelHandle, + mHandle, buf_type, + buf_idx, plane_idx); +} + +/*=========================================================================== + * FUNCTION : setParameter + * + * DESCRIPTION: set stream based parameters + * + * PARAMETERS : + * @param : ptr to parameters to be set + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::setParameter(cam_stream_parm_buffer_t ¶m) +{ + int32_t rc = NO_ERROR; + mStreamInfo->parm_buf = param; + rc = mCamOps->set_stream_parms(mCamHandle, + mChannelHandle, + mHandle, + &mStreamInfo->parm_buf); + if (rc == NO_ERROR) { + param = mStreamInfo->parm_buf; + } + return rc; +} + +/*=========================================================================== + * FUNCTION : releaseFrameData + * + * DESCRIPTION: callback function to release frame data node + * + * PARAMETERS : + * @data : ptr to post process input data + * @user_data : user data ptr (QCameraReprocessor) + * + * RETURN : None + *==========================================================================*/ +void QCamera3Stream::releaseFrameData(void *data, void *user_data) +{ + QCamera3Stream *pme = (QCamera3Stream *)user_data; + mm_camera_super_buf_t *frame = (mm_camera_super_buf_t *)data; + if (NULL != pme) { + if (UNLIKELY(pme->mBatchSize)) { + /* For batch mode, the batch buffer is added to empty list */ + if(!pme->mFreeBatchBufQ.enqueue((void*) frame->bufs[0])) { + LOGE("batchBuf.buf_idx: %d enqueue failed", + frame->bufs[0]->buf_idx); + } + } else { + pme->bufDone(frame->bufs[0]->buf_idx); + } + } +} + +/*=========================================================================== + * FUNCTION : getBatchBufs + * + * DESCRIPTION: allocate batch containers for the stream + * + * PARAMETERS : + * @num_bufs : number of buffers allocated + * @initial_reg_flag: flag to indicate if buffer needs to be registered + * at kernel initially + * @bufs : output of allocated buffers + * @ops_tbl : ptr to buf mapping/unmapping ops + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::getBatchBufs( + uint8_t *num_bufs, uint8_t **initial_reg_flag, + mm_camera_buf_def_t **bufs, + mm_camera_map_unmap_ops_tbl_t *ops_tbl) +{ + int rc = NO_ERROR; + uint8_t *regFlags; + + if (!ops_tbl || !num_bufs || !initial_reg_flag || !bufs) { + LOGE("input args NULL"); + return INVALID_OPERATION; + } + LOGH("Batch container allocation stream type = %d", + getMyType()); + + Mutex::Autolock lock(mLock); + + mMemOps = ops_tbl; + + //Allocate batch containers + mStreamBatchBufs = new QCamera3HeapMemory(1); + if (!mStreamBatchBufs) { + LOGE("unable to create batch container memory"); + return NO_MEMORY; + } + // Allocating single buffer file-descriptor for all batch containers, + // mStreamBatchBufs considers all the container bufs as a single buffer. But + // QCamera3Stream manages that single buffer as multiple batch buffers + LOGD("Allocating batch container memory. numBatch: %d size: %d", + mNumBatchBufs, mStreamInfo->user_buf_info.size); + rc = mStreamBatchBufs->allocate( + mNumBatchBufs * mStreamInfo->user_buf_info.size); + if (rc < 0) { + LOGE("unable to allocate batch container memory"); + rc = NO_MEMORY; + goto err1; + } + + /* map batch buffers. getCnt here returns 1 because of single FD across + * batch bufs */ + for (uint32_t i = 0; i < mStreamBatchBufs->getCnt(); i++) { + if (mNumBatchBufs) { + //For USER_BUF, size = number_of_container bufs instead of the total + //buf size + rc = ops_tbl->map_ops(i, -1, mStreamBatchBufs->getFd(i), + (size_t)mNumBatchBufs, CAM_MAPPING_BUF_TYPE_STREAM_USER_BUF, + ops_tbl->userdata); + if (rc < 0) { + LOGE("Failed to map stream container buffer: %d", + rc); + //Unmap all the buffers that were successfully mapped before + //this buffer mapping failed + for (size_t j = 0; j < i; j++) { + ops_tbl->unmap_ops(j, -1, + CAM_MAPPING_BUF_TYPE_STREAM_USER_BUF, + ops_tbl->userdata); + } + goto err2; + } + } else { + LOGE("Failed to retrieve buffer size (bad index)"); + return INVALID_OPERATION; + } + } + + LOGD("batch bufs successfully mmapped = %d", + mNumBatchBufs); + + /* regFlags array is allocated here, but consumed and freed by + * mm-camera-interface */ + regFlags = (uint8_t *)malloc(sizeof(uint8_t) * mNumBatchBufs); + if (!regFlags) { + LOGE("Out of memory"); + rc = NO_MEMORY; + goto err3; + } + memset(regFlags, 0, sizeof(uint8_t) * mNumBatchBufs); + /* Do not queue the container buffers as the image buffers are not yet + * queued. mStreamBatchBufs->getRegFlags is not called as mStreamBatchBufs + * considers single buffer is allocated */ + for (uint32_t i = 0; i < mNumBatchBufs; i++) { + regFlags[i] = 0; + } + + mBatchBufDefs = (mm_camera_buf_def_t *) + malloc(mNumBatchBufs * sizeof(mm_camera_buf_def_t)); + if (mBatchBufDefs == NULL) { + LOGE("mBatchBufDefs memory allocation failed"); + rc = INVALID_OPERATION; + goto err4; + } + memset(mBatchBufDefs, 0, mNumBatchBufs * sizeof(mm_camera_buf_def_t)); + + //Populate bufDef and queue to free batchBufQ + for (uint32_t i = 0; i < mNumBatchBufs; i++) { + getBatchBufDef(mBatchBufDefs[i], i); + if(mFreeBatchBufQ.enqueue((void*) &mBatchBufDefs[i])) { + LOGD("mBatchBufDefs[%d]: 0x%p", i, &mBatchBufDefs[i]); + } else { + LOGE("enqueue mBatchBufDefs[%d] failed", i); + } + } + + *num_bufs = mNumBatchBufs; + *initial_reg_flag = regFlags; + *bufs = mBatchBufDefs; + LOGH("stream type: %d, numBufs(batch): %d", + mStreamInfo->stream_type, mNumBatchBufs); + + return NO_ERROR; +err4: + free(regFlags); +err3: + for (size_t i = 0; i < mStreamBatchBufs->getCnt(); i++) { + ops_tbl->unmap_ops(i, -1, CAM_MAPPING_BUF_TYPE_STREAM_USER_BUF, + ops_tbl->userdata); + } +err2: + mStreamBatchBufs->deallocate(); +err1: + delete mStreamBatchBufs; + mStreamBatchBufs = NULL; + return rc; +} + +/*=========================================================================== + * FUNCTION : putBatchBufs + * + * DESCRIPTION: deallocate stream batch buffers + * + * PARAMETERS : + * @ops_tbl : ptr to buf mapping/unmapping ops + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::putBatchBufs(mm_camera_map_unmap_ops_tbl_t *ops_tbl) +{ + int rc = NO_ERROR; + Mutex::Autolock lock(mLock); + + if (mStreamBatchBufs) { + for (uint32_t i = 0; i < mStreamBatchBufs->getCnt(); i++) { + rc = ops_tbl->unmap_ops(i, -1, CAM_MAPPING_BUF_TYPE_STREAM_USER_BUF, + ops_tbl->userdata); + if (rc < 0) { + LOGE("un-map batch buf failed: %d", rc); + } + } + mStreamBatchBufs->deallocate(); + delete mStreamBatchBufs; + mStreamBatchBufs = NULL; + } + // mm-camera-interface frees bufDefs even though bufDefs are allocated by + // QCamera3Stream. Don't free here + mBatchBufDefs = NULL; + + return rc; +} + +/*=========================================================================== + * FUNCTION : getBatchBufDef + * + * DESCRIPTION: query detailed buffer information of batch buffer + * + * PARAMETERS : + * @bufDef : [output] reference to struct to store buffer definition + * @@index : [input] index of the buffer + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::getBatchBufDef(mm_camera_buf_def_t& batchBufDef, + int32_t index) +{ + int rc = NO_ERROR; + memset(&batchBufDef, 0, sizeof(mm_camera_buf_def_t)); + if (mStreamBatchBufs) { + //Single file descriptor for all batch buffers + batchBufDef.fd = mStreamBatchBufs->getFd(0); + batchBufDef.buf_type = CAM_STREAM_BUF_TYPE_USERPTR; + batchBufDef.frame_len = mStreamInfo->user_buf_info.size; + batchBufDef.mem_info = mStreamBatchBufs; + batchBufDef.buffer = (uint8_t *)mStreamBatchBufs->getPtr(0) + + (index * mStreamInfo->user_buf_info.size); + batchBufDef.buf_idx = index; + batchBufDef.user_buf.num_buffers = mBatchSize; + batchBufDef.user_buf.bufs_used = 0; + batchBufDef.user_buf.plane_buf = mBufDefs; + } + + return rc; +} + +/*=========================================================================== + * FUNCTION : aggregateBufToBatch + * + * DESCRIPTION: queue batch container to downstream. + * + * PARAMETERS : + * @bufDef : image buffer to be aggregated into batch + * + * RETURN : int32_t type of status + * NO_ERROR -- success always + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::aggregateBufToBatch(mm_camera_buf_def_t& bufDef) +{ + int32_t rc = NO_ERROR; + + if (UNLIKELY(!mBatchSize)) { + LOGE("Batch mod is not enabled"); + return INVALID_OPERATION; + } + if (!mCurrentBatchBufDef) { + mCurrentBatchBufDef = (mm_camera_buf_def_t *)mFreeBatchBufQ.dequeue(); + if (!mCurrentBatchBufDef) { + LOGE("No empty batch buffers is available"); + return NO_MEMORY; + } + LOGD("batch buffer: %d dequeued from empty buffer list", + mCurrentBatchBufDef->buf_idx); + } + if (mBufsStaged == mCurrentBatchBufDef->user_buf.num_buffers) { + LOGE("batch buffer is already full"); + return NO_MEMORY; + } + + mCurrentBatchBufDef->user_buf.buf_idx[mBufsStaged] = bufDef.buf_idx; + mBufsStaged++; + LOGD("buffer id: %d aggregated into batch buffer id: %d", + bufDef.buf_idx, mCurrentBatchBufDef->buf_idx); + return rc; +} + +/*=========================================================================== + * FUNCTION : queueBatchBuf + * + * DESCRIPTION: queue batch container to downstream. + * + * PARAMETERS : None + * + * RETURN : int32_t type of status + * NO_ERROR -- success always + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::queueBatchBuf() +{ + int32_t rc = NO_ERROR; + + if (!mCurrentBatchBufDef) { + LOGE("No buffers were queued into batch"); + return INVALID_OPERATION; + } + //bufs_used: number of valid buffers in the batch buffers + mCurrentBatchBufDef->user_buf.bufs_used = mBufsStaged; + + //if mBufsStaged < num_buffers, initialize the buf_idx to -1 for rest of the + //buffers + for (size_t i = mBufsStaged; i < mCurrentBatchBufDef->user_buf.num_buffers; + i++) { + mCurrentBatchBufDef->user_buf.buf_idx[i] = -1; + } + + rc = mCamOps->qbuf(mCamHandle, mChannelHandle, mCurrentBatchBufDef); + if (rc < 0) { + LOGE("queueing of batch buffer: %d failed with err: %d", + mCurrentBatchBufDef->buf_idx, rc); + return FAILED_TRANSACTION; + } + LOGD("Batch buf id: %d queued. bufs_used: %d", + mCurrentBatchBufDef->buf_idx, + mCurrentBatchBufDef->user_buf.bufs_used); + + mCurrentBatchBufDef = NULL; + mBufsStaged = 0; + + return rc; +} + +/*=========================================================================== + * FUNCTION : handleBatchBuffer + * + * DESCRIPTION: separate individual buffers from the batch and issue callback + * + * PARAMETERS : + * @superBuf : Received superbuf containing batch buffer + * + * RETURN : int32_t type of status + * NO_ERROR -- success always + * none-zero failure code + *==========================================================================*/ +int32_t QCamera3Stream::handleBatchBuffer(mm_camera_super_buf_t *superBuf) +{ + int32_t rc = NO_ERROR; + mm_camera_super_buf_t *frame; + mm_camera_buf_def_t batchBuf; + + if (LIKELY(!mBatchSize)) { + LOGE("Stream: %d not in batch mode, but batch buffer received", + getMyType()); + return INVALID_OPERATION; + } + if (!mDataCB) { + LOGE("Data callback not set for batch mode"); + return BAD_VALUE; + } + if (!superBuf->bufs[0]) { + LOGE("superBuf->bufs[0] is NULL!!"); + return BAD_VALUE; + } + + /* Copy the batch buffer to local and queue the batch buffer to empty queue + * to handle the new requests received while callbacks are in progress */ + batchBuf = *superBuf->bufs[0]; + if (!mFreeBatchBufQ.enqueue((void*) superBuf->bufs[0])) { + LOGE("batchBuf.buf_idx: %d enqueue failed", + batchBuf.buf_idx); + free(superBuf); + return NO_MEMORY; + } + LOGD("Received batch buffer: %d bufs_used: %d", + batchBuf.buf_idx, batchBuf.user_buf.bufs_used); + //dummy local bufDef to issue multiple callbacks + mm_camera_buf_def_t buf; + memset(&buf, 0, sizeof(mm_camera_buf_def_t)); + + for (size_t i = 0; i < batchBuf.user_buf.bufs_used; i++) { + int32_t buf_idx = batchBuf.user_buf.buf_idx[i]; + buf = mBufDefs[buf_idx]; + + /* this memory is freed inside dataCB. Should not be freed here */ + frame = (mm_camera_super_buf_t *)malloc(sizeof(mm_camera_super_buf_t)); + if (!frame) { + LOGE("malloc failed. Buffers will be dropped"); + break; + } else { + memcpy(frame, superBuf, sizeof(mm_camera_super_buf_t)); + frame->bufs[0] = &buf; + + mDataCB(frame, this, mUserData); + } + } + LOGD("batch buffer: %d callbacks done", + batchBuf.buf_idx); + + free(superBuf); + return rc; +} + +/*=========================================================================== + * FUNCTION : flushFreeBatchBufQ + * + * DESCRIPTION: dequeue all the entries of mFreeBatchBufQ and call flush. + * QCameraQueue::flush calls 'free(node->data)' which should be + * avoided for mFreeBatchBufQ as the entries are not allocated + * during each enqueue + * + * PARAMETERS : None + * + * RETURN : None + *==========================================================================*/ +void QCamera3Stream::flushFreeBatchBufQ() +{ + while (!mFreeBatchBufQ.isEmpty()) { + mFreeBatchBufQ.dequeue(); + } + mFreeBatchBufQ.flush(); +} + +}; // namespace qcamera |