| /* 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" |
| #include <cutils/properties.h> |
| #include "QCameraTrace.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 : clean_buf |
| * |
| * DESCRIPTION: static function entry to clean 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_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->cleanBuf(buf_idx); |
| if (NO_ERROR != retVal) { |
| LOGE("invalidateBuf failed for buf_idx: %d err: %d", |
| buf_idx, retVal); |
| } |
| rc |= retVal; |
| } |
| } else { |
| rc = stream->cleanBuf(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, |
| bool mapStreamBuffers) : |
| 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), |
| mNRMode(0), |
| mMapStreamBuffers(mapStreamBuffers) |
| { |
| 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.clean_buf = clean_buf; |
| mMemVtbl.set_config_ops = NULL; |
| memset(&mFrameLenOffset, 0, sizeof(mFrameLenOffset)); |
| memcpy(&mPaddingInfo, paddingInfo, sizeof(cam_padding_info_t)); |
| if (nullptr != channel) { |
| mNRMode = channel->getNRMode(); |
| } |
| } |
| |
| /*=========================================================================== |
| * 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; |
| char value[PROPERTY_VALUE_MAX]; |
| uint32_t bOptimizeCacheOps = 0; |
| 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; |
| mStreamInfo->nr_mode = mNRMode; |
| |
| memset(value, 0, sizeof(value)); |
| property_get("persist.camera.cache.optimize", value, "1"); |
| bOptimizeCacheOps = atoi(value); |
| |
| if (bOptimizeCacheOps) { |
| mStreamInfo->cache_ops = CAM_STREAM_CACHE_OPS_HONOUR_FLAGS; |
| } else { |
| mStreamInfo->cache_ops = CAM_STREAM_CACHE_OPS_DISABLED; |
| } |
| 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, |
| mStreamInfoBuf->getPtr(0)); |
| 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(); |
| mTimeoutFrameQ.clear(); |
| 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 : timeoutFrame |
| * |
| * DESCRIPTION: Function to issue timeout on frame |
| * |
| * PARAMETERS : |
| * @bufIdx : buffer index of the frame to be timed out |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCamera3Stream::timeoutFrame(int32_t bufIdx) |
| { |
| LOGD("E\n"); |
| int32_t rc; |
| { |
| Mutex::Autolock lock(mTimeoutFrameQLock); |
| mTimeoutFrameQ.push_back(bufIdx); |
| } |
| rc = mProcTh.sendCmd(CAMERA_CMD_TYPE_TIMEOUT, FALSE, FALSE); |
| LOGD("X\n"); |
| 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_TIMEOUT: |
| { |
| int32_t bufIdx; |
| { |
| Mutex::Autolock lock(pme->mTimeoutFrameQLock); |
| if (pme->mTimeoutFrameQ.size()) { |
| auto itr = pme->mTimeoutFrameQ.begin(); |
| bufIdx = *itr; |
| itr = pme->mTimeoutFrameQ.erase(itr); |
| } else { |
| LOGE("Timeout command received but Q is empty"); |
| break; |
| } |
| } |
| pme->cancelBuffer(bufIdx); |
| break; |
| } |
| 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"); |
| pme->flushFreeBatchBufQ(); |
| /* flush data buf queue */ |
| pme->mDataQ.flush(); |
| pme->mTimeoutFrameQ.clear(); |
| 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) |
| { |
| Mutex::Autolock lock(mLock); |
| return bufDoneLocked(index); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : bufDoneLocked |
| * |
| * DESCRIPTION: return stream buffer to kernel while holding the lock |
| * |
| * PARAMETERS : |
| * @index : index of buffer to be returned |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCamera3Stream::bufDoneLocked(uint32_t index) |
| { |
| int32_t rc = NO_ERROR; |
| |
| 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); |
| void* buffer = (mMapStreamBuffers ? |
| mStreamBufs->getPtr(index) : NULL); |
| rc = mMemOps->map_ops(index, -1, mStreamBufs->getFd(index), |
| (size_t)bufSize, buffer, |
| 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, mMapStreamBuffers); |
| 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 { |
| // Cache invalidation should happen in lockNextBuffer or during |
| // reprocessing. No need to invalidate every buffer without knowing |
| // which buffer is accessed by CPU. |
| rc = mCamOps->qbuf(mCamHandle, mChannelHandle, &mBufDefs[index]); |
| if (rc < 0) { |
| return FAILED_TRANSACTION; |
| } |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : cancelBuffer |
| * |
| * DESCRIPTION: Issue cancel buffer request to kernel |
| * |
| * PARAMETERS : |
| * @index : index of buffer to be cancelled |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCamera3Stream::cancelBuffer(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 (UNLIKELY(mBatchSize)) { |
| FIXME |
| } else */{ |
| LOGE("Calling cancel buf on idx:%d for stream type:%d",index, getMyType()); |
| rc = mCamOps->cancel_buffer(mCamHandle, mChannelHandle, mHandle, 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) { |
| void* buffer = (mMapStreamBuffers ? |
| mStreamBufs->getPtr(i) : NULL); |
| rc = ops_tbl->map_ops(i, -1, mStreamBufs->getFd(i), |
| (size_t)bufSize, buffer, |
| 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, mMapStreamBuffers); |
| } |
| } |
| |
| 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 : cleanBuf |
| * |
| * DESCRIPTION: clean 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::cleanBuf(uint32_t index) |
| { |
| if (mStreamBufs == NULL) { |
| LOGE("putBufs already called"); |
| return INVALID_OPERATION; |
| } else |
| return mStreamBufs->cleanCache(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 |
| * @buffer : buffer ptr |
| * @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, void *buffer, size_t size) |
| { |
| ATRACE_CALL(); |
| return mCamOps->map_stream_buf(mCamHandle, mChannelHandle, |
| mHandle, buf_type, |
| buf_idx, plane_idx, |
| fd, size, buffer); |
| |
| } |
| |
| /*=========================================================================== |
| * 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) |
| { |
| ATRACE_CALL(); |
| 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; |
| ATRACE_CALL(); |
| 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 |
| void* buffer = (mMapStreamBuffers ? mStreamBufs->getPtr(i) : NULL); |
| rc = ops_tbl->map_ops(i, -1, mStreamBatchBufs->getFd(i), |
| (size_t)mNumBatchBufs, buffer, |
| 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); |
| } |
| } |
| |
| rc = aggregateStartingBufs(*initial_reg_flag); |
| if (rc != NO_ERROR) { |
| LOGE("Failed to aggregate starting buffers to the batch %d", rc); |
| goto err4; |
| } |
| |
| *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 : aggregateStartingBuffers |
| * |
| * DESCRIPTION: Aggregate initial buffers to the first batch before stream_on |
| * |
| * PARAMETERS : |
| * @initial_reg_flag: flag to indicate if buffer needs to be registered |
| * at kernel initially |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success always |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCamera3Stream::aggregateStartingBufs(const uint8_t *initial_reg_flag) |
| { |
| int32_t rc = NO_ERROR; |
| |
| for (uint8_t i = 0; i < mBatchSize; i++) { |
| if (initial_reg_flag[i]) { |
| rc = bufDoneLocked(i); |
| if (rc != NO_ERROR) { |
| LOGE("Failed to aggregate buffer %d to batch", i); |
| break; |
| } |
| } |
| } |
| 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 |