| /* 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 "QCameraStream" |
| |
| // System dependencies |
| #include <utils/Errors.h> |
| |
| // Camera dependencies |
| #include "QCameraBufferMaps.h" |
| #include "QCamera2HWI.h" |
| #include "QCameraStream.h" |
| |
| extern "C" { |
| #include "mm_camera_dbg.h" |
| } |
| |
| #define CAMERA_MIN_ALLOCATED_BUFFERS 3 |
| |
| namespace qcamera { |
| |
| /*=========================================================================== |
| * 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 QCameraStream::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) |
| { |
| QCameraStream *stream = reinterpret_cast<QCameraStream *>(user_data); |
| if (!stream) { |
| LOGE("getBufs invalid stream pointer"); |
| return NO_MEMORY; |
| } |
| |
| if (stream->mStreamInfo != NULL |
| && stream->mStreamInfo->streaming_mode == CAM_STREAMING_MODE_BATCH) { |
| //Batch Mode. Allocate Butch buffers |
| return stream->allocateBatchBufs(offset, num_bufs, |
| initial_reg_flag, bufs, ops_tbl); |
| } else { |
| // Plane Buffer. Allocate plane buffer |
| return stream->getBufs(offset, num_bufs, |
| initial_reg_flag, bufs, ops_tbl); |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : get_bufs_deffered |
| * |
| * DESCRIPTION: static function entry to allocate deffered 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 QCameraStream::get_bufs_deffered( |
| 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) |
| { |
| QCameraStream *stream = reinterpret_cast<QCameraStream *>(user_data); |
| |
| if (!stream) { |
| LOGE("getBufs invalid stream pointer"); |
| return NO_MEMORY; |
| } |
| |
| return stream->getBufsDeferred(NULL /*offset*/, num_bufs, initial_reg_flag, bufs, |
| ops_tbl); |
| } |
| |
| /*=========================================================================== |
| * 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 QCameraStream::put_bufs( |
| mm_camera_map_unmap_ops_tbl_t *ops_tbl, |
| void *user_data) |
| { |
| QCameraStream *stream = reinterpret_cast<QCameraStream *>(user_data); |
| if (!stream) { |
| LOGE("putBufs invalid stream pointer"); |
| return NO_MEMORY; |
| } |
| |
| if (stream->mStreamInfo != NULL |
| && stream->mStreamInfo->streaming_mode == CAM_STREAMING_MODE_BATCH) { |
| //Batch Mode. release Butch buffers |
| return stream->releaseBatchBufs(ops_tbl); |
| } else { |
| // Plane Buffer. release plane buffer |
| return stream->putBufs(ops_tbl); |
| } |
| |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : put_bufs_deffered |
| * |
| * DESCRIPTION: static function entry to deallocate deffered 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 QCameraStream::put_bufs_deffered( |
| mm_camera_map_unmap_ops_tbl_t * /*ops_tbl */, |
| void * user_data ) |
| { |
| QCameraStream *stream = reinterpret_cast<QCameraStream *>(user_data); |
| |
| if (!stream) { |
| LOGE("put_bufs_deffered invalid stream pointer"); |
| return NO_MEMORY; |
| } |
| |
| return stream->putBufsDeffered(); |
| } |
| |
| /*=========================================================================== |
| * 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 QCameraStream::invalidate_buf(uint32_t index, void *user_data) |
| { |
| QCameraStream *stream = reinterpret_cast<QCameraStream *>(user_data); |
| if (!stream) { |
| LOGE("invalid stream pointer"); |
| return NO_MEMORY; |
| } |
| |
| if (stream->mStreamInfo->is_secure == SECURE){ |
| return 0; |
| } |
| |
| if (stream->mStreamInfo->streaming_mode == CAM_STREAMING_MODE_BATCH) { |
| for (int i = 0; i < stream->mBufDefs[index].user_buf.bufs_used; i++) { |
| uint32_t buf_idx = stream->mBufDefs[index].user_buf.buf_idx[i]; |
| stream->invalidateBuf(buf_idx); |
| } |
| } else { |
| return stream->invalidateBuf(index); |
| } |
| |
| return 0; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : clean_invalidate_buf |
| * |
| * DESCRIPTION: static function entry to clean invalidate a specific stream buffer |
| * |
| * PARAMETERS : |
| * @index : index of the stream buffer to clean invalidate |
| * @user_data : user data ptr of ops_tbl |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::clean_invalidate_buf(uint32_t index, void *user_data) |
| { |
| QCameraStream *stream = reinterpret_cast<QCameraStream *>(user_data); |
| if (!stream) { |
| LOGE("invalid stream pointer"); |
| return NO_MEMORY; |
| } |
| |
| if (stream->mStreamInfo->is_secure == SECURE){ |
| return 0; |
| } |
| |
| if (stream->mStreamInfo->streaming_mode == CAM_STREAMING_MODE_BATCH) { |
| for (int i = 0; i < stream->mBufDefs[index].user_buf.bufs_used; i++) { |
| uint32_t buf_idx = stream->mBufDefs[index].user_buf.buf_idx[i]; |
| stream->cleanInvalidateBuf(buf_idx); |
| } |
| } else { |
| return stream->cleanInvalidateBuf(index); |
| } |
| |
| return 0; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : set_config_ops |
| * |
| * DESCRIPTION: static function update mm-interface ops functions |
| * |
| * 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 QCameraStream::set_config_ops(mm_camera_map_unmap_ops_tbl_t *ops_tbl, |
| void *user_data) |
| { |
| QCameraStream *stream = reinterpret_cast<QCameraStream *>(user_data); |
| if (!stream) { |
| LOGE("Stream invalid"); |
| return NO_MEMORY; |
| } |
| |
| stream->m_MemOpsTbl = *ops_tbl; |
| return 0; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : QCameraStream |
| * |
| * DESCRIPTION: constructor of QCameraStream |
| * |
| * PARAMETERS : |
| * @allocator : memory allocator obj |
| * @camHandle : camera handle |
| * @chId : channel handle |
| * @camOps : ptr to camera ops table |
| * @paddingInfo: ptr to padding info |
| * @deffered : deferred stream |
| * @online_rotation: rotation applied online |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| QCameraStream::QCameraStream(QCameraAllocator &allocator, |
| uint32_t camHandle, uint32_t chId, |
| mm_camera_ops_t *camOps, cam_padding_info_t *paddingInfo, |
| bool deffered, cam_rotation_t online_rotation): |
| mDumpFrame(0), |
| mDumpMetaFrame(0), |
| mDumpSkipCnt(0), |
| mStreamTimestamp(0), |
| mCamHandle(camHandle), |
| mChannelHandle(chId), |
| mHandle(0), |
| mCamOps(camOps), |
| mStreamInfo(NULL), |
| mNumBufs(0), |
| mNumPlaneBufs(0), |
| mNumBufsNeedAlloc(0), |
| mRegFlags(NULL), |
| mDataCB(NULL), |
| mSYNCDataCB(NULL), |
| mUserData(NULL), |
| mDataQ(releaseFrameData, this), |
| mStreamInfoBuf(NULL), |
| mMiscBuf(NULL), |
| mStreamBufs(NULL), |
| mStreamBatchBufs(NULL), |
| mAllocator(allocator), |
| mBufDefs(NULL), |
| mPlaneBufDefs(NULL), |
| mOnlineRotation(online_rotation), |
| mStreamBufsAcquired(false), |
| m_bActive(false), |
| mDynBufAlloc(false), |
| mBufAllocPid(0), |
| mDefferedAllocation(deffered), |
| wait_for_cond(false), |
| mAllocTaskId(0), |
| mMapTaskId(0), |
| mSyncCBEnabled(false) |
| { |
| mMemVtbl.user_data = this; |
| if ( !deffered ) { |
| mMemVtbl.get_bufs = get_bufs; |
| mMemVtbl.put_bufs = put_bufs; |
| } else { |
| mMemVtbl.get_bufs = get_bufs_deffered; |
| mMemVtbl.put_bufs = put_bufs_deffered; |
| } |
| mMemVtbl.invalidate_buf = invalidate_buf; |
| mMemVtbl.clean_invalidate_buf = clean_invalidate_buf; |
| mMemVtbl.set_config_ops = set_config_ops; |
| memset(&mFrameLenOffset, 0, sizeof(mFrameLenOffset)); |
| memcpy(&mPaddingInfo, paddingInfo, sizeof(cam_padding_info_t)); |
| memset(&mCropInfo, 0, sizeof(cam_rect_t)); |
| memset(&m_MemOpsTbl, 0, sizeof(mm_camera_map_unmap_ops_tbl_t)); |
| memset(&m_OutputCrop, 0, sizeof(cam_stream_parm_buffer_t)); |
| memset(&m_ImgProp, 0, sizeof(cam_stream_parm_buffer_t)); |
| memset(&mAllocTask, 0, sizeof(mAllocTask)); |
| memset(&mMapTask, 0, sizeof(mMapTask)); |
| pthread_mutex_init(&mCropLock, NULL); |
| pthread_mutex_init(&mParameterLock, NULL); |
| mCurMetaMemory = NULL; |
| mCurBufIndex = -1; |
| mCurMetaIndex = -1; |
| mFirstTimeStamp = 0; |
| memset (&mStreamMetaMemory, 0, |
| (sizeof(MetaMemory) * CAMERA_MIN_VIDEO_BATCH_BUFFERS)); |
| pthread_mutex_init(&m_lock, NULL); |
| pthread_cond_init(&m_cond, NULL); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : ~QCameraStream |
| * |
| * DESCRIPTION: deconstructor of QCameraStream |
| * |
| * PARAMETERS : None |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| QCameraStream::~QCameraStream() |
| { |
| pthread_mutex_destroy(&mCropLock); |
| pthread_mutex_destroy(&mParameterLock); |
| |
| mAllocator.waitForBackgroundTask(mAllocTaskId); |
| mAllocator.waitForBackgroundTask(mMapTaskId); |
| if (mBufAllocPid != 0) { |
| cond_signal(true); |
| LOGL("Wait for buf allocation thread dead"); |
| // Wait for the allocation of additional stream buffers |
| pthread_join(mBufAllocPid, NULL); |
| mBufAllocPid = 0; |
| } |
| |
| if (mDefferedAllocation) { |
| mStreamBufsAcquired = false; |
| releaseBuffs(); |
| } |
| |
| unmapStreamInfoBuf(); |
| releaseStreamInfoBuf(); |
| |
| if (mMiscBuf) { |
| unMapBuf(mMiscBuf, CAM_MAPPING_BUF_TYPE_MISC_BUF, NULL); |
| releaseMiscBuf(); |
| } |
| |
| // delete stream |
| if (mHandle > 0) { |
| mCamOps->delete_stream(mCamHandle, mChannelHandle, mHandle); |
| mHandle = 0; |
| } |
| pthread_mutex_destroy(&m_lock); |
| pthread_cond_destroy(&m_cond); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : unmapStreamInfoBuf |
| * |
| * DESCRIPTION: Unmap stream info buffer |
| * |
| * PARAMETERS : |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::unmapStreamInfoBuf() |
| { |
| int rc = NO_ERROR; |
| |
| if (mStreamInfoBuf != NULL) { |
| rc = mCamOps->unmap_stream_buf(mCamHandle, |
| mChannelHandle, |
| mHandle, |
| CAM_MAPPING_BUF_TYPE_STREAM_INFO, |
| 0, |
| -1); |
| |
| if (rc < 0) { |
| LOGE("Failed to unmap stream info buffer"); |
| } |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : releaseMiscBuf |
| * |
| * DESCRIPTION: Release misc buffers |
| * |
| * PARAMETERS : |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::releaseMiscBuf() |
| { |
| int rc = NO_ERROR; |
| |
| if (mMiscBuf != NULL) { |
| mMiscBuf->deallocate(); |
| delete mMiscBuf; |
| mMiscBuf = NULL; |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : releaseStreamInfoBuf |
| * |
| * DESCRIPTION: Release stream info buffer |
| * |
| * PARAMETERS : |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::releaseStreamInfoBuf() |
| { |
| int rc = NO_ERROR; |
| |
| if (mStreamInfoBuf != NULL) { |
| mStreamInfoBuf->deallocate(); |
| delete mStreamInfoBuf; |
| mStreamInfoBuf = NULL; |
| mStreamInfo = NULL; |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : deleteStream |
| * |
| * DESCRIPTION: Deletes a camera stream |
| * |
| * PARAMETERS : None |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void QCameraStream::deleteStream() |
| { |
| if (mHandle > 0) { |
| acquireStreamBufs(); |
| releaseBuffs(); |
| unmapStreamInfoBuf(); |
| mCamOps->delete_stream(mCamHandle, mChannelHandle, mHandle); |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : unMapBuf |
| * |
| * DESCRIPTION: unmaps buffers |
| * |
| * PARAMETERS : |
| * @heapBuf : heap buffer handler |
| * @bufType : buffer type |
| * @ops_tbl : ptr to buf mapping/unmapping ops |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::unMapBuf(QCameraMemory *Buf, |
| cam_mapping_buf_type bufType, __unused mm_camera_map_unmap_ops_tbl_t *ops_tbl) |
| { |
| int32_t rc = NO_ERROR; |
| uint8_t cnt; |
| ssize_t bufSize = BAD_INDEX; |
| uint32_t i; |
| |
| cnt = Buf->getCnt(); |
| for (i = 0; i < cnt; i++) { |
| bufSize = Buf->getSize(i); |
| if (BAD_INDEX != bufSize) { |
| if (m_MemOpsTbl.unmap_ops == NULL ) { |
| rc = mCamOps->unmap_stream_buf(mCamHandle, mChannelHandle, mHandle, |
| bufType, i, -1); |
| } else { |
| rc = m_MemOpsTbl.unmap_ops(i, -1, bufType, m_MemOpsTbl.userdata); |
| } |
| if (rc < 0) { |
| LOGE("Failed to unmap buffer"); |
| break; |
| } |
| } else { |
| LOGE("Failed to retrieve buffer size (bad index)"); |
| rc = BAD_INDEX; |
| break; |
| } |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mapBufs |
| * |
| * DESCRIPTION: maps buffers |
| * |
| * PARAMETERS : |
| * @heapBuf : heap buffer handler |
| * @bufType : buffer type |
| * @ops_tbl : ptr to buf mapping/unmapping ops |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::mapBufs(QCameraMemory *Buf, |
| cam_mapping_buf_type bufType, __unused mm_camera_map_unmap_ops_tbl_t *ops_tbl) |
| { |
| int32_t rc = NO_ERROR; |
| uint32_t i = 0; |
| |
| QCameraBufferMaps bufferMaps; |
| for (i = 0; i < Buf->getCnt(); i++) { |
| ssize_t bufSize = Buf->getSize(i); |
| if (BAD_INDEX == bufSize) { |
| LOGE("Failed to retrieve buffer size (bad index)"); |
| return BAD_INDEX; |
| } |
| |
| rc = bufferMaps.enqueue(bufType, mHandle, i /*buf index*/, -1 /*plane index*/, |
| 0 /*cookie*/, Buf->getFd(i), bufSize, Buf->getPtr(i)); |
| |
| if (rc < 0) { |
| LOGE("Failed to map buffers"); |
| return BAD_INDEX; |
| } |
| } |
| |
| cam_buf_map_type_list bufMapList; |
| rc = bufferMaps.getCamBufMapList(bufMapList); |
| if (rc < 0) { |
| LOGE("Failed to map buffers"); |
| return BAD_INDEX; |
| } |
| |
| if (m_MemOpsTbl.bundled_map_ops == NULL) { |
| rc = mCamOps->map_stream_bufs(mCamHandle, mChannelHandle, &bufMapList); |
| } else { |
| rc = m_MemOpsTbl.bundled_map_ops(&bufMapList, m_MemOpsTbl.userdata); |
| } |
| |
| if (rc < 0) { |
| LOGE("Failed to map buffer"); |
| rc = BAD_INDEX; |
| } |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : backgroundAllocate |
| * |
| * DESCRIPTION: schedule buffers to be allocated in the background |
| * |
| * PARAMETERS : |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::backgroundAllocate(void *data) { |
| QCameraStream *stream = (QCameraStream*)data; |
| int32_t rc = stream->allocateBuffers(); |
| if (rc != NO_ERROR) { |
| LOGE("Error allocating buffers !!!"); |
| } |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : backgroundMap |
| * |
| * DESCRIPTION: map buffers in the background |
| * |
| * PARAMETERS : |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::backgroundMap(void *data) { |
| QCameraStream *stream = (QCameraStream*)data; |
| int32_t rc = stream->mapBuffers(); |
| if (rc != NO_ERROR) { |
| LOGE("Error mapping buffers !!!"); |
| } |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : init |
| * |
| * DESCRIPTION: initialize stream obj |
| * |
| * PARAMETERS : |
| * @streamInfoBuf: ptr to buf that contains stream info |
| * @miscBuf : ptr to buf that contains misc bufs |
| * @stream_cb : stream data notify callback. Can be NULL if not needed |
| * @userdata : user data ptr |
| * @bDynallocBuf : flag to indicate if buffer allocation can be in 2 steps |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::init(QCameraHeapMemory *streamInfoBuf, |
| QCameraHeapMemory *miscBuf, |
| uint8_t minNumBuffers, |
| stream_cb_routine stream_cb, |
| void *userdata, |
| bool bDynallocBuf) |
| { |
| int32_t rc = OK; |
| |
| // assign and map stream info memory |
| mStreamInfoBuf = streamInfoBuf; |
| mStreamInfo = reinterpret_cast<cam_stream_info_t *>(mStreamInfoBuf->getPtr(0)); |
| mNumBufs = minNumBuffers; |
| mDynBufAlloc = bDynallocBuf; |
| |
| // Calculate buffer size for deffered allocation |
| if (mDefferedAllocation) { |
| rc = calcOffset(mStreamInfo); |
| if (rc < 0) { |
| LOGE("Failed to calculate stream offset"); |
| goto done; |
| } |
| |
| mAllocTask.bgFunction = backgroundAllocate; |
| mAllocTask.bgArgs = this; |
| mAllocTaskId = mAllocator.scheduleBackgroundTask(&mAllocTask); |
| if (mAllocTaskId == 0) { |
| LOGE("Failed to schedule buffer alloction"); |
| rc = -ENOMEM; |
| goto done; |
| } |
| } |
| |
| mHandle = mCamOps->add_stream(mCamHandle, mChannelHandle); |
| if (!mHandle) { |
| LOGE("add_stream failed"); |
| rc = UNKNOWN_ERROR; |
| goto done; |
| } |
| |
| rc = mapBufs(mStreamInfoBuf, CAM_MAPPING_BUF_TYPE_STREAM_INFO, NULL); |
| if (rc < 0) { |
| LOGE("Failed to map stream info buffer"); |
| goto err1; |
| } |
| |
| mMiscBuf = miscBuf; |
| if (miscBuf) { |
| rc = mapBufs(mMiscBuf, CAM_MAPPING_BUF_TYPE_MISC_BUF, NULL); |
| if (rc < 0) { |
| LOGE("Failed to map miscellaneous buffer"); |
| releaseMiscBuf(); |
| goto err1; |
| } |
| } |
| |
| rc = configStream(); |
| if (rc < 0) { |
| LOGE("Failed to config stream "); |
| goto err1; |
| } |
| |
| if (mDefferedAllocation) { |
| mMapTask.bgFunction = backgroundMap; |
| mMapTask.bgArgs = this; |
| mMapTaskId = mAllocator.scheduleBackgroundTask(&mMapTask); |
| if (mMapTaskId == 0) { |
| LOGE("Failed to schedule buffer alloction"); |
| rc = -ENOMEM; |
| goto err1; |
| } |
| } |
| |
| mDataCB = stream_cb; |
| mUserData = userdata; |
| return 0; |
| |
| err1: |
| mCamOps->delete_stream(mCamHandle, mChannelHandle, mHandle); |
| mHandle = 0; |
| mNumBufs = 0; |
| done: |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : calcOffset |
| * |
| * DESCRIPTION: calculate frame offset based on format and padding information |
| * |
| * PARAMETERS : |
| * @streamInfo : stream information |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t QCameraStream::calcOffset(cam_stream_info_t *streamInfo) |
| { |
| int32_t rc = 0; |
| |
| cam_dimension_t dim = streamInfo->dim; |
| if (streamInfo->pp_config.feature_mask & CAM_QCOM_FEATURE_ROTATION && |
| streamInfo->stream_type != CAM_STREAM_TYPE_VIDEO) { |
| if (streamInfo->pp_config.rotation == ROTATE_90 || |
| streamInfo->pp_config.rotation == ROTATE_270) { |
| // rotated by 90 or 270, need to switch width and height |
| dim.width = streamInfo->dim.height; |
| dim.height = streamInfo->dim.width; |
| } |
| } |
| |
| switch (streamInfo->stream_type) { |
| case CAM_STREAM_TYPE_PREVIEW: |
| case CAM_STREAM_TYPE_CALLBACK: |
| rc = mm_stream_calc_offset_preview(streamInfo, |
| &dim, |
| &mPaddingInfo, |
| &streamInfo->buf_planes); |
| break; |
| case CAM_STREAM_TYPE_POSTVIEW: |
| rc = mm_stream_calc_offset_post_view(streamInfo->fmt, |
| &dim, |
| &streamInfo->buf_planes); |
| break; |
| case CAM_STREAM_TYPE_SNAPSHOT: |
| rc = mm_stream_calc_offset_snapshot(streamInfo->fmt, |
| &dim, |
| &mPaddingInfo, |
| &streamInfo->buf_planes); |
| break; |
| case CAM_STREAM_TYPE_OFFLINE_PROC: |
| rc = mm_stream_calc_offset_postproc(streamInfo, |
| &mPaddingInfo, |
| &streamInfo->buf_planes); |
| break; |
| case CAM_STREAM_TYPE_VIDEO: |
| rc = mm_stream_calc_offset_video(streamInfo->fmt, |
| &dim, &streamInfo->buf_planes); |
| break; |
| case CAM_STREAM_TYPE_RAW: |
| rc = mm_stream_calc_offset_raw(streamInfo->fmt, |
| &dim, |
| &mPaddingInfo, |
| &streamInfo->buf_planes); |
| break; |
| case CAM_STREAM_TYPE_ANALYSIS: |
| rc = mm_stream_calc_offset_analysis(streamInfo->fmt, |
| &dim, |
| &mPaddingInfo, |
| &streamInfo->buf_planes); |
| break; |
| case CAM_STREAM_TYPE_METADATA: |
| rc = mm_stream_calc_offset_metadata(&dim, |
| &mPaddingInfo, |
| &streamInfo->buf_planes); |
| break; |
| default: |
| LOGE("not supported for stream type %d", |
| streamInfo->stream_type); |
| rc = -1; |
| break; |
| } |
| 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 QCameraStream::start() |
| { |
| int32_t rc = 0; |
| mDataQ.init(); |
| rc = mProcTh.launch(dataProcRoutine, this); |
| if (rc == NO_ERROR) { |
| m_bActive = true; |
| } |
| |
| mCurMetaMemory = NULL; |
| mCurBufIndex = -1; |
| mCurMetaIndex = -1; |
| mFirstTimeStamp = 0; |
| memset (&mStreamMetaMemory, 0, |
| (sizeof(MetaMemory) * CAMERA_MIN_VIDEO_BATCH_BUFFERS)); |
| 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 QCameraStream::stop() |
| { |
| int32_t rc = 0; |
| m_bActive = false; |
| mAllocator.waitForBackgroundTask(mAllocTaskId); |
| mAllocator.waitForBackgroundTask(mMapTaskId); |
| rc = mProcTh.exit(); |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : syncRuntimeParams |
| * |
| * DESCRIPTION: query and sync runtime parameters like output crop |
| * buffer info etc. |
| * |
| * PARAMETERS : none |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::syncRuntimeParams() |
| { |
| int32_t ret = NO_ERROR; |
| |
| memset(&m_OutputCrop, 0, sizeof(cam_stream_parm_buffer_t)); |
| m_OutputCrop.type = CAM_STREAM_PARAM_TYPE_GET_OUTPUT_CROP; |
| |
| ret = getParameter(m_OutputCrop); |
| if (ret != NO_ERROR) { |
| LOGE("stream getParameter for output crop failed"); |
| return ret; |
| } |
| |
| memset(&m_ImgProp, 0, sizeof(cam_stream_parm_buffer_t)); |
| m_ImgProp.type = CAM_STREAM_PARAM_TYPE_GET_IMG_PROP; |
| |
| ret = getParameter(m_ImgProp); |
| if (ret != NO_ERROR) { |
| LOGE("stream getParameter for image prop failed"); |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : processZoomDone |
| * |
| * DESCRIPTION: process zoom done event |
| * |
| * PARAMETERS : |
| * @previewWindoe : preview window ops table to set preview crop window |
| * @crop_info : crop info |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::processZoomDone(preview_stream_ops_t *previewWindow, |
| cam_crop_data_t &crop_info) |
| { |
| int32_t rc = 0; |
| |
| if (!m_bActive) { |
| LOGL("Stream not active"); |
| return NO_ERROR; |
| } |
| |
| // get stream param for crop info |
| for (int i = 0; i < crop_info.num_of_streams; i++) { |
| if (crop_info.crop_info[i].stream_id == mStreamInfo->stream_svr_id) { |
| pthread_mutex_lock(&mCropLock); |
| mCropInfo = crop_info.crop_info[i].crop; |
| pthread_mutex_unlock(&mCropLock); |
| |
| // update preview window crop if it's preview/postview stream |
| if ( (previewWindow != NULL) && |
| (mStreamInfo->stream_type == CAM_STREAM_TYPE_PREVIEW || |
| mStreamInfo->stream_type == CAM_STREAM_TYPE_POSTVIEW) ) { |
| rc = previewWindow->set_crop(previewWindow, |
| mCropInfo.left, |
| mCropInfo.top, |
| mCropInfo.width, |
| mCropInfo.height); |
| } |
| break; |
| } |
| } |
| 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 QCameraStream::processDataNotify(mm_camera_super_buf_t *frame) |
| { |
| LOGD("\n"); |
| |
| if (mDataQ.enqueue((void *)frame)) { |
| return mProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); |
| } else { |
| if (!m_bActive) { |
| LOGW("Stream thread is not active, no ops here %d", getMyType()); |
| } else { |
| bufDone(frame->bufs[0]->buf_idx); |
| } |
| free(frame); |
| return NO_ERROR; |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : dataNotifySYNCCB |
| * |
| * DESCRIPTION: This function registered with interface for |
| * SYNC callback if SYNC callback registered. |
| * |
| * PARAMETERS : |
| * @recvd_frame : stream frame received |
| * @userdata : user data ptr |
| * |
| * RETURN : none |
| *==========================================================================*/ |
| void QCameraStream::dataNotifySYNCCB(mm_camera_super_buf_t *recvd_frame, |
| void *userdata) |
| { |
| LOGD("\n"); |
| QCameraStream* stream = (QCameraStream *)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; |
| } |
| if ((stream->mSyncCBEnabled) && (stream->mSYNCDataCB != NULL)) |
| stream->mSYNCDataCB(recvd_frame, stream, stream->mUserData); |
| return; |
| } |
| |
| |
| /*=========================================================================== |
| * 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 QCameraStream::dataNotifyCB(mm_camera_super_buf_t *recvd_frame, |
| void *userdata) |
| { |
| LOGD("\n"); |
| QCameraStream* stream = (QCameraStream *)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 *QCameraStream::dataProcRoutine(void *data) |
| { |
| int running = 1; |
| int ret; |
| QCameraStream *pme = (QCameraStream *)data; |
| QCameraCmdThread *cmdThread = &pme->mProcTh; |
| cmdThread->setName("CAM_strmDatProc"); |
| |
| 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: |
| { |
| LOGH("Do next job"); |
| mm_camera_super_buf_t *frame = |
| (mm_camera_super_buf_t *)pme->mDataQ.dequeue(); |
| if (NULL != frame) { |
| 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); |
| free(frame); |
| } |
| } |
| } |
| break; |
| case CAMERA_CMD_TYPE_EXIT: |
| LOGH("Exit"); |
| /* flush data buf queue */ |
| pme->mDataQ.flush(); |
| running = 0; |
| break; |
| default: |
| break; |
| } |
| } while (running); |
| LOGH("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 QCameraStream::bufDone(uint32_t index) |
| { |
| int32_t rc = NO_ERROR; |
| |
| if (index >= mNumBufs || mBufDefs == NULL) |
| return BAD_INDEX; |
| |
| rc = mCamOps->qbuf(mCamHandle, mChannelHandle, &mBufDefs[index]); |
| |
| if (rc < 0) |
| return rc; |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : bufDone |
| * |
| * DESCRIPTION: return stream buffer to kernel |
| * |
| * PARAMETERS : |
| * @opaque : stream frame/metadata buf to be returned |
| * @isMetaData: flag if returned opaque is a metadatabuf or the real frame ptr |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::bufDone(const void *opaque, bool isMetaData) |
| { |
| int32_t rc = NO_ERROR; |
| int index = -1; |
| |
| if ((mStreamInfo != NULL) |
| && (mStreamInfo->streaming_mode == CAM_STREAMING_MODE_BATCH) |
| && (mStreamBatchBufs != NULL)) { |
| index = mStreamBatchBufs->getMatchBufIndex(opaque, isMetaData); |
| } else if (mStreamBufs != NULL){ |
| index = mStreamBufs->getMatchBufIndex(opaque, isMetaData); |
| } |
| |
| if (index == -1 || index >= mNumBufs || mBufDefs == NULL) { |
| LOGE("Cannot find buf for opaque data = %p", opaque); |
| return BAD_INDEX; |
| } |
| |
| if ((CAMERA_MIN_VIDEO_BATCH_BUFFERS > index) |
| && mStreamMetaMemory[index].numBuffers > 0) { |
| for (int i= 0; i < mStreamMetaMemory[index].numBuffers; i++) { |
| uint8_t buf_idx = mStreamMetaMemory[index].buf_index[i]; |
| bufDone((uint32_t)buf_idx); |
| } |
| mStreamMetaMemory[index].consumerOwned = FALSE; |
| mStreamMetaMemory[index].numBuffers = 0; |
| } else { |
| LOGH("Buffer Index = %d, Frame Idx = %d", index, |
| mBufDefs[index].frame_idx); |
| rc = bufDone((uint32_t)index); |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : getNumQueuedBuf |
| * |
| * DESCRIPTION: return queued buffer count |
| * |
| * PARAMETERS : None |
| * |
| * RETURN : queued buffer count |
| *==========================================================================*/ |
| int32_t QCameraStream::getNumQueuedBuf() |
| { |
| int32_t rc = -1; |
| if (mHandle > 0) { |
| rc = mCamOps->get_queued_buf_count(mCamHandle, mChannelHandle, mHandle); |
| } |
| if (rc == -1) { |
| LOGE("stream is not in active state. Invalid operation"); |
| } |
| 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 QCameraStream::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; |
| |
| if (!ops_tbl) { |
| LOGE("ops_tbl is NULL"); |
| return INVALID_OPERATION; |
| } |
| |
| mFrameLenOffset = *offset; |
| |
| uint8_t numBufAlloc = mNumBufs; |
| mNumBufsNeedAlloc = 0; |
| if (mDynBufAlloc) { |
| numBufAlloc = CAMERA_MIN_ALLOCATED_BUFFERS; |
| if (numBufAlloc > mNumBufs) { |
| mDynBufAlloc = false; |
| numBufAlloc = mNumBufs; |
| } else { |
| mNumBufsNeedAlloc = (uint8_t)(mNumBufs - numBufAlloc); |
| } |
| } |
| |
| /* For some stream types, buffer allocation may have already begun |
| * preemptively. If this is the case, we need to wait for the |
| * preemptive allocation to complete before proceeding. */ |
| mAllocator.waitForDeferredAlloc(mStreamInfo->stream_type); |
| |
| //Allocate stream buffer |
| mStreamBufs = mAllocator.allocateStreamBuf(mStreamInfo->stream_type, |
| mFrameLenOffset.frame_len, mFrameLenOffset.mp[0].stride, |
| mFrameLenOffset.mp[0].scanline, numBufAlloc); |
| if (!mStreamBufs) { |
| LOGE("Failed to allocate stream buffers"); |
| return NO_MEMORY; |
| } |
| |
| mNumBufs = (uint8_t)(numBufAlloc + mNumBufsNeedAlloc); |
| uint8_t numBufsToMap = mStreamBufs->getMappable(); |
| |
| QCameraBufferMaps bufferMaps; |
| for (uint32_t i = 0; i < numBufsToMap; i++) { |
| ssize_t bufSize = mStreamBufs->getSize(i); |
| if (BAD_INDEX == bufSize) { |
| LOGE("Failed to retrieve buffer size (bad index)"); |
| return INVALID_OPERATION; |
| } |
| |
| rc = bufferMaps.enqueue(CAM_MAPPING_BUF_TYPE_STREAM_BUF, |
| 0 /*stream id*/, i /*buf index*/, -1 /*plane index*/, |
| 0 /*cookie*/, mStreamBufs->getFd(i), bufSize, |
| mStreamBufs->getPtr(i)); |
| |
| if (rc < 0) { |
| LOGE("Failed to map buffers"); |
| return BAD_INDEX; |
| } |
| } |
| |
| cam_buf_map_type_list bufMapList; |
| rc = bufferMaps.getCamBufMapList(bufMapList); |
| if (rc == NO_ERROR) { |
| rc = ops_tbl->bundled_map_ops(&bufMapList, ops_tbl->userdata); |
| } |
| if (rc < 0) { |
| LOGE("map_stream_buf failed: %d", rc); |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| 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 < numBufsToMap; i++) { |
| ops_tbl->unmap_ops(i, -1, CAM_MAPPING_BUF_TYPE_STREAM_BUF, ops_tbl->userdata); |
| } |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| 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("getRegFlags failed %d", rc); |
| for (uint32_t i = 0; i < numBufsToMap; i++) { |
| ops_tbl->unmap_ops(i, -1, CAM_MAPPING_BUF_TYPE_STREAM_BUF, ops_tbl->userdata); |
| } |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| free(regFlags); |
| regFlags = NULL; |
| return INVALID_OPERATION; |
| } |
| memset(mBufDefs, 0, mNumBufs * sizeof(mm_camera_buf_def_t)); |
| for (uint32_t i = 0; i < numBufsToMap; 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 < numBufsToMap; i++) { |
| ops_tbl->unmap_ops(i, -1, CAM_MAPPING_BUF_TYPE_STREAM_BUF, ops_tbl->userdata); |
| } |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| free(mBufDefs); |
| mBufDefs = NULL; |
| free(regFlags); |
| regFlags = NULL; |
| return INVALID_OPERATION; |
| } |
| |
| *num_bufs = mNumBufs; |
| *initial_reg_flag = regFlags; |
| *bufs = mBufDefs; |
| LOGH("stream type: %d, mRegFlags: 0x%x, numBufs: %d", |
| mStreamInfo->stream_type, regFlags, mNumBufs); |
| |
| if (mNumBufsNeedAlloc > 0) { |
| pthread_mutex_lock(&m_lock); |
| wait_for_cond = TRUE; |
| pthread_mutex_unlock(&m_lock); |
| LOGH("Still need to allocate %d buffers", |
| mNumBufsNeedAlloc); |
| // start another thread to allocate the rest of buffers |
| pthread_create(&mBufAllocPid, |
| NULL, |
| BufAllocRoutine, |
| this); |
| pthread_setname_np(mBufAllocPid, "CAM_strmBuf"); |
| } |
| |
| return NO_ERROR; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : getBufsDeferred |
| * |
| * DESCRIPTION: allocate deferred 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 QCameraStream::getBufsDeferred(__unused cam_frame_len_offset_t *offset, |
| uint8_t *num_bufs, |
| uint8_t **initial_reg_flag, |
| mm_camera_buf_def_t **bufs, |
| __unused mm_camera_map_unmap_ops_tbl_t *ops_tbl) |
| { |
| int32_t rc = NO_ERROR; |
| // wait for allocation |
| rc = mAllocator.waitForBackgroundTask(mAllocTaskId); |
| if (rc != NO_ERROR) { |
| LOGE("Allocation Failed"); |
| return NO_MEMORY; |
| } |
| |
| if (!mRegFlags || !mBufDefs) { |
| LOGE("reg flags or buf defs uninitialized"); |
| return NO_MEMORY; |
| } |
| |
| *initial_reg_flag = mRegFlags; |
| *num_bufs = mNumBufs; |
| *bufs = mBufDefs; |
| |
| LOGH("stream type: %d, mRegFlags: 0x%x, numBufs: %d", |
| getMyType(), mRegFlags, mNumBufs); |
| |
| return NO_ERROR; |
| } |
| /*=========================================================================== |
| * FUNCTION : mapNewBuffer |
| * |
| * DESCRIPTION: map a new stream buffer |
| * |
| * PARAMETERS : |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::mapNewBuffer(uint32_t index) |
| { |
| LOGH("E - index = %d", index); |
| |
| int rc = NO_ERROR; |
| |
| if (mStreamBufs == NULL) { |
| LOGE("Invalid Operation"); |
| return INVALID_OPERATION; |
| } |
| |
| ssize_t bufSize = mStreamBufs->getSize(index); |
| if (BAD_INDEX == bufSize) { |
| LOGE("Failed to retrieve buffer size (bad index)"); |
| return INVALID_OPERATION; |
| } |
| |
| cam_buf_map_type_list bufMapList; |
| rc = QCameraBufferMaps::makeSingletonBufMapList( |
| CAM_MAPPING_BUF_TYPE_STREAM_BUF, 0 /*stream id*/, index, |
| -1 /*plane index*/, 0 /*cookie*/, mStreamBufs->getFd(index), |
| bufSize, bufMapList, mStreamBufs->getPtr(index)); |
| |
| if (rc == NO_ERROR) { |
| rc = m_MemOpsTbl.bundled_map_ops(&bufMapList, m_MemOpsTbl.userdata); |
| } |
| if (rc < 0) { |
| LOGE("map_stream_buf failed: %d", rc); |
| rc = INVALID_OPERATION; |
| } else { |
| mStreamBufs->getBufDef(mFrameLenOffset, mBufDefs[index], index); |
| } |
| |
| LOGH("X - rc = %d", rc); |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : allocateBuffers |
| * |
| * DESCRIPTION: allocate stream buffers |
| * |
| * PARAMETERS : |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::allocateBuffers() |
| { |
| int32_t rc = NO_ERROR; |
| |
| mFrameLenOffset = mStreamInfo->buf_planes.plane_info; |
| |
| if (mStreamInfo->streaming_mode == CAM_STREAMING_MODE_BATCH) { |
| return allocateBatchBufs(&mFrameLenOffset, |
| &mNumBufs, &mRegFlags, |
| &mBufDefs, NULL); |
| } |
| |
| /* This allocation is running in the deferred context, so it |
| * is safe (and necessary) to assume any preemptive allocation |
| * is already complete. Therefore, no need to wait here. */ |
| |
| uint8_t numBufAlloc = mNumBufs; |
| mNumBufsNeedAlloc = 0; |
| if (mDynBufAlloc) { |
| numBufAlloc = CAMERA_MIN_ALLOCATED_BUFFERS; |
| if (numBufAlloc > mNumBufs) { |
| mDynBufAlloc = false; |
| numBufAlloc = mNumBufs; |
| } else { |
| mNumBufsNeedAlloc = (uint8_t)(mNumBufs - numBufAlloc); |
| } |
| } |
| |
| //Allocate and map stream info buffer |
| mStreamBufs = mAllocator.allocateStreamBuf(mStreamInfo->stream_type, |
| mFrameLenOffset.frame_len, |
| mFrameLenOffset.mp[0].stride, |
| mFrameLenOffset.mp[0].scanline, |
| numBufAlloc); |
| |
| if (!mStreamBufs) { |
| LOGE("Failed to allocate stream buffers"); |
| return NO_MEMORY; |
| } |
| |
| mNumBufs = (uint8_t)(numBufAlloc + mNumBufsNeedAlloc); |
| uint8_t numBufsToMap = mStreamBufs->getMappable(); |
| |
| //regFlags array is allocated by us, |
| // but consumed and freed by mm-camera-interface |
| mRegFlags = (uint8_t *)malloc(sizeof(uint8_t) * mNumBufs); |
| if (!mRegFlags) { |
| LOGE("Out of memory"); |
| for (uint32_t i = 0; i < numBufsToMap; i++) { |
| unmapBuf(CAM_MAPPING_BUF_TYPE_STREAM_BUF, i, -1, NULL); |
| } |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| return NO_MEMORY; |
| } |
| memset(mRegFlags, 0, sizeof(uint8_t) * mNumBufs); |
| |
| size_t bufDefsSize = mNumBufs * sizeof(mm_camera_buf_def_t); |
| mBufDefs = (mm_camera_buf_def_t *)malloc(bufDefsSize); |
| if (mBufDefs == NULL) { |
| LOGE("getRegFlags failed %d", rc); |
| for (uint32_t i = 0; i < numBufsToMap; i++) { |
| unmapBuf(CAM_MAPPING_BUF_TYPE_STREAM_BUF, i, -1, NULL); |
| } |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| free(mRegFlags); |
| mRegFlags = NULL; |
| return INVALID_OPERATION; |
| } |
| memset(mBufDefs, 0, bufDefsSize); |
| for (uint32_t i = 0; i < numBufsToMap; i++) { |
| mStreamBufs->getBufDef(mFrameLenOffset, mBufDefs[i], i); |
| } |
| |
| rc = mStreamBufs->getRegFlags(mRegFlags); |
| if (rc < 0) { |
| LOGE("getRegFlags failed %d", rc); |
| for (uint32_t i = 0; i < numBufsToMap; i++) { |
| unmapBuf(CAM_MAPPING_BUF_TYPE_STREAM_BUF, i, -1, NULL); |
| } |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| free(mBufDefs); |
| mBufDefs = NULL; |
| free(mRegFlags); |
| mRegFlags = NULL; |
| return INVALID_OPERATION; |
| } |
| |
| if (mNumBufsNeedAlloc > 0) { |
| pthread_mutex_lock(&m_lock); |
| wait_for_cond = TRUE; |
| pthread_mutex_unlock(&m_lock); |
| LOGH("Still need to allocate %d buffers", |
| mNumBufsNeedAlloc); |
| // start another thread to allocate the rest of buffers |
| pthread_create(&mBufAllocPid, |
| NULL, |
| BufAllocRoutine, |
| this); |
| pthread_setname_np(mBufAllocPid, "CAM_strmBufAlloc"); |
| } |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mapBuffers |
| * |
| * DESCRIPTION: map stream buffers |
| * |
| * PARAMETERS : |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::mapBuffers() |
| { |
| int32_t rc = NO_ERROR; |
| QCameraBufferMaps bufferMaps; |
| |
| rc = mAllocator.waitForBackgroundTask(mAllocTaskId); |
| if (rc != NO_ERROR) { |
| LOGE("Allocation Failed"); |
| return NO_MEMORY; |
| } |
| |
| if (mStreamBufs == NULL) { |
| LOGE("Stream buffers not allocated"); |
| return UNKNOWN_ERROR; |
| } |
| |
| uint8_t numBufsToMap = mStreamBufs->getMappable(); |
| for (uint32_t i = 0; i < numBufsToMap; i++) { |
| ssize_t bufSize = mStreamBufs->getSize(i); |
| if (BAD_INDEX != bufSize) { |
| rc = bufferMaps.enqueue(CAM_MAPPING_BUF_TYPE_STREAM_BUF, mHandle, |
| i /*buf index*/, -1 /*plane index*/, 0 /*cookie*/, |
| mStreamBufs->getFd(i), bufSize, |
| mStreamBufs->getPtr(i)); |
| |
| if (rc < 0) { |
| LOGE("Failed to map buffers"); |
| rc = BAD_INDEX; |
| break; |
| } |
| } else { |
| LOGE("Bad index %u", i); |
| rc = BAD_INDEX; |
| break; |
| } |
| } |
| |
| cam_buf_map_type_list bufMapList; |
| if (rc == NO_ERROR) { |
| rc = bufferMaps.getCamBufMapList(bufMapList); |
| } |
| if (rc == NO_ERROR) { |
| rc = mapBufs(bufMapList, NULL); |
| } |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : allocateBatchBufs |
| * |
| * DESCRIPTION: allocate stream batch buffers and 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 |
| * @plane_bufs : output of allocated plane buffers |
| * @ops_tbl : ptr to buf mapping/unmapping ops |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::allocateBatchBufs(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; |
| QCameraBufferMaps bufferMaps; |
| QCameraBufferMaps planeBufferMaps; |
| |
| mFrameLenOffset = *offset; |
| |
| LOGH("Batch Buffer allocation stream type = %d", getMyType()); |
| |
| //Allocate stream batch buffer |
| mStreamBatchBufs = mAllocator.allocateStreamUserBuf (mStreamInfo); |
| if (!mStreamBatchBufs) { |
| LOGE("Failed to allocate stream batch buffers"); |
| return NO_MEMORY; |
| } |
| |
| uint8_t numBufsToMap = mStreamBatchBufs->getMappable(); |
| |
| //map batch buffers |
| for (uint32_t i = 0; i < numBufsToMap; i++) { |
| rc = bufferMaps.enqueue(CAM_MAPPING_BUF_TYPE_STREAM_USER_BUF, |
| 0 /*stream id*/, i /*buf index*/, -1 /*plane index*/, |
| 0 /*cookie*/, mStreamBatchBufs->getFd(i), |
| mNumBufs, mStreamBatchBufs->getPtr(i)); |
| |
| if (rc < 0) { |
| LOGE("Failed to map buffers"); |
| rc = BAD_INDEX; |
| break; |
| } |
| } |
| |
| cam_buf_map_type_list bufMapList; |
| if (rc == NO_ERROR) { |
| rc = bufferMaps.getCamBufMapList(bufMapList); |
| } |
| if (rc == NO_ERROR) { |
| rc = mapBufs(bufMapList, ops_tbl); |
| } |
| if (rc < 0) { |
| LOGE("Failed to map stream batch buffers"); |
| mStreamBatchBufs->deallocate(); |
| delete mStreamBatchBufs; |
| mStreamBatchBufs = NULL; |
| return NO_MEMORY; |
| } |
| |
| /*calculate stream Buffer count*/ |
| mNumPlaneBufs = |
| (mNumBufs * mStreamInfo->user_buf_info.frame_buf_cnt); |
| |
| /* For some stream types, buffer allocation may have already begun |
| * preemptively. If this is the case, we need to wait for the |
| * preemptive allocation to complete before proceeding. */ |
| mAllocator.waitForDeferredAlloc(mStreamInfo->stream_type); |
| |
| //Allocate stream buffer |
| mStreamBufs = mAllocator.allocateStreamBuf(mStreamInfo->stream_type, |
| mFrameLenOffset.frame_len,mFrameLenOffset.mp[0].stride, |
| mFrameLenOffset.mp[0].scanline,mNumPlaneBufs); |
| if (!mStreamBufs) { |
| LOGE("Failed to allocate stream buffers"); |
| rc = NO_MEMORY; |
| goto err1; |
| } |
| |
| //Map plane stream buffers |
| for (uint32_t i = 0; i < mNumPlaneBufs; i++) { |
| ssize_t bufSize = mStreamBufs->getSize(i); |
| if (BAD_INDEX != bufSize) { |
| rc = planeBufferMaps.enqueue(CAM_MAPPING_BUF_TYPE_STREAM_BUF, |
| 0 /*stream id*/, i /*buf index*/, -1 /*plane index*/, |
| 0 /*cookie*/, mStreamBufs->getFd(i), bufSize, |
| mStreamBufs->getPtr(i)); |
| |
| if (rc < 0) { |
| LOGE("Failed to map buffers"); |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| rc = INVALID_OPERATION; |
| goto err1; |
| } |
| } else { |
| LOGE("Failed to retrieve buffer size (bad index)"); |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| rc = INVALID_OPERATION; |
| goto err1; |
| } |
| } |
| |
| cam_buf_map_type_list planeBufMapList; |
| rc = planeBufferMaps.getCamBufMapList(planeBufMapList); |
| if (rc == NO_ERROR) { |
| rc = mapBufs(planeBufMapList, ops_tbl); |
| } |
| |
| if (rc < 0) { |
| LOGE("map_stream_buf failed: %d", rc); |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| rc = INVALID_OPERATION; |
| goto err1; |
| } |
| |
| LOGD("BATCH Buf Count = %d, Plane Buf Cnt = %d", |
| mNumBufs, mNumPlaneBufs); |
| |
| //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 < mNumPlaneBufs; i++) { |
| unmapBuf(CAM_MAPPING_BUF_TYPE_STREAM_BUF, i, -1, ops_tbl); |
| } |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| rc = NO_MEMORY; |
| goto err1; |
| } |
| memset(regFlags, 0, sizeof(uint8_t) * mNumBufs); |
| for (uint32_t i = 0; i < mNumBufs; i++) { |
| regFlags[i] = 1; |
| } |
| |
| mBufDefs = (mm_camera_buf_def_t *)malloc(mNumBufs * sizeof(mm_camera_buf_def_t)); |
| if (mBufDefs == NULL) { |
| LOGE("getRegFlags failed %d", rc); |
| for (uint32_t i = 0; i < mNumPlaneBufs; i++) { |
| unmapBuf(CAM_MAPPING_BUF_TYPE_STREAM_BUF, i, -1, ops_tbl); |
| } |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| free(regFlags); |
| regFlags = NULL; |
| rc = INVALID_OPERATION; |
| goto err1; |
| } |
| memset(mBufDefs, 0, mNumBufs * sizeof(mm_camera_buf_def_t)); |
| |
| mPlaneBufDefs = (mm_camera_buf_def_t *) |
| malloc(mNumPlaneBufs * (sizeof(mm_camera_buf_def_t))); |
| if (mPlaneBufDefs == NULL) { |
| LOGE("No Memory"); |
| free(regFlags); |
| regFlags = NULL; |
| free(mBufDefs); |
| mBufDefs = NULL; |
| for (uint32_t i = 0; i < mNumPlaneBufs; i++) { |
| unmapBuf(CAM_MAPPING_BUF_TYPE_STREAM_BUF, i, -1, ops_tbl); |
| } |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| free(regFlags); |
| regFlags = NULL; |
| rc = INVALID_OPERATION; |
| goto err1; |
| } |
| memset(mPlaneBufDefs, 0, |
| mNumPlaneBufs * (sizeof(mm_camera_buf_def_t))); |
| |
| for (uint32_t i = 0; i < mStreamInfo->num_bufs; i++) { |
| mStreamBatchBufs->getUserBufDef(mStreamInfo->user_buf_info, |
| mBufDefs[i], i, mFrameLenOffset, mPlaneBufDefs, |
| mStreamBufs); |
| } |
| |
| *num_bufs = mNumBufs; |
| *initial_reg_flag = regFlags; |
| *bufs = mBufDefs; |
| LOGH("stream type: %d, numBufs: %d mNumPlaneBufs: %d", |
| mStreamInfo->stream_type, mNumBufs, mNumPlaneBufs); |
| |
| return NO_ERROR; |
| |
| err1: |
| mStreamBatchBufs->deallocate(); |
| delete mStreamBatchBufs; |
| mStreamBatchBufs = NULL; |
| return rc; |
| } |
| |
| |
| /*=========================================================================== |
| * FUNCTION : releaseBuffs |
| * |
| * DESCRIPTION: method to deallocate stream buffers |
| * |
| * PARAMETERS : |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::releaseBuffs() |
| { |
| int rc = NO_ERROR; |
| |
| if (mStreamInfo->streaming_mode == CAM_STREAMING_MODE_BATCH) { |
| return releaseBatchBufs(NULL); |
| } |
| |
| if ((NULL != mBufDefs) && (mStreamBufs != NULL)) { |
| uint8_t numBufsToUnmap = mStreamBufs->getMappable(); |
| for (uint32_t i = 0; i < numBufsToUnmap; i++) { |
| rc = unmapBuf(CAM_MAPPING_BUF_TYPE_STREAM_BUF, i, -1, NULL); |
| if (rc < 0) { |
| LOGE("map_stream_buf failed: %d", rc); |
| } |
| } |
| |
| // mBufDefs just keep a ptr to the buffer |
| // mm-camera-interface own the buffer, so no need to free |
| mBufDefs = NULL; |
| memset(&mFrameLenOffset, 0, sizeof(mFrameLenOffset)); |
| } |
| if (!mStreamBufsAcquired && (mStreamBufs != NULL)) { |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| } |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : releaseBatchBufs |
| * |
| * DESCRIPTION: method to deallocate stream buffers and 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 QCameraStream::releaseBatchBufs(mm_camera_map_unmap_ops_tbl_t *ops_tbl) |
| { |
| int rc = NO_ERROR; |
| |
| if (NULL != mPlaneBufDefs) { |
| for (uint32_t i = 0; i < mNumPlaneBufs; i++) { |
| rc = unmapBuf(CAM_MAPPING_BUF_TYPE_STREAM_BUF, i, -1, ops_tbl); |
| if (rc < 0) { |
| LOGE("map_stream_buf failed: %d", rc); |
| } |
| } |
| |
| // mBufDefs just keep a ptr to the buffer |
| // mm-camera-interface own the buffer, so no need to free |
| mPlaneBufDefs = NULL; |
| memset(&mFrameLenOffset, 0, sizeof(mFrameLenOffset)); |
| mNumPlaneBufs = 0; |
| } |
| |
| if (mStreamBufs != NULL) { |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| } |
| |
| mBufDefs = NULL; |
| |
| if (mStreamBatchBufs != NULL) { |
| for (uint8_t i = 0; i < mStreamBatchBufs->getCnt(); i++) { |
| unmapBuf(CAM_MAPPING_BUF_TYPE_STREAM_USER_BUF, i, -1, ops_tbl); |
| } |
| mStreamBatchBufs->deallocate(); |
| delete mStreamBatchBufs; |
| mStreamBatchBufs = NULL; |
| } |
| return rc; |
| |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : BufAllocRoutine |
| * |
| * DESCRIPTION: function to allocate additional stream buffers |
| * |
| * PARAMETERS : |
| * @data : user data ptr |
| * |
| * RETURN : none |
| *==========================================================================*/ |
| void *QCameraStream::BufAllocRoutine(void *data) |
| { |
| QCameraStream *pme = (QCameraStream *)data; |
| int32_t rc = NO_ERROR; |
| |
| LOGH("E"); |
| pme->cond_wait(); |
| if (pme->mNumBufsNeedAlloc > 0) { |
| uint8_t numBufAlloc = (uint8_t)(pme->mNumBufs - pme->mNumBufsNeedAlloc); |
| rc = pme->mAllocator.allocateMoreStreamBuf(pme->mStreamBufs, |
| pme->mFrameLenOffset.frame_len, |
| pme->mNumBufsNeedAlloc); |
| if (rc != NO_ERROR) { |
| LOGE("Failed to allocate buffers"); |
| pme->mNumBufsNeedAlloc = 0; |
| return NULL; |
| } |
| |
| pme->mNumBufsNeedAlloc = 0; |
| QCameraBufferMaps bufferMaps; |
| for (uint32_t i = numBufAlloc; i < pme->mNumBufs; i++) { |
| ssize_t bufSize = pme->mStreamBufs->getSize(i); |
| if (BAD_INDEX == bufSize) { |
| LOGE("Failed to retrieve buffer size (bad index)"); |
| return NULL; |
| } |
| |
| rc = bufferMaps.enqueue(CAM_MAPPING_BUF_TYPE_STREAM_BUF, |
| pme->mHandle, i /*buf index*/, -1 /*plane index*/, |
| 0 /*cookie*/, pme->mStreamBufs->getFd(i), bufSize, |
| pme->mStreamBufs->getPtr(i)); |
| |
| if (rc < 0) { |
| LOGE("Failed to map buffers"); |
| return NULL; |
| } |
| } |
| |
| cam_buf_map_type_list bufMapList; |
| rc = bufferMaps.getCamBufMapList(bufMapList); |
| if (rc == NO_ERROR) { |
| rc = pme->m_MemOpsTbl.bundled_map_ops(&bufMapList, pme->m_MemOpsTbl.userdata); |
| } |
| if (rc != 0) { |
| LOGE("Failed to map buffers with return code %d", rc); |
| return NULL; |
| } |
| |
| for (uint32_t i = numBufAlloc; i < pme->mNumBufs; i++) { |
| pme->mStreamBufs->getBufDef(pme->mFrameLenOffset, pme->mBufDefs[i], i); |
| pme->mCamOps->qbuf(pme->mCamHandle, pme->mChannelHandle, |
| &pme->mBufDefs[i]); |
| } |
| } |
| LOGH("X"); |
| return NULL; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : cond_signal |
| * |
| * DESCRIPTION: signal if flag "wait_for_cond" is set |
| * |
| *==========================================================================*/ |
| void QCameraStream::cond_signal(bool forceExit) |
| { |
| pthread_mutex_lock(&m_lock); |
| if(wait_for_cond == TRUE){ |
| wait_for_cond = FALSE; |
| if (forceExit) { |
| mNumBufsNeedAlloc = 0; |
| } |
| pthread_cond_signal(&m_cond); |
| } |
| pthread_mutex_unlock(&m_lock); |
| } |
| |
| |
| /*=========================================================================== |
| * FUNCTION : cond_wait |
| * |
| * DESCRIPTION: wait on if flag "wait_for_cond" is set |
| * |
| *==========================================================================*/ |
| void QCameraStream::cond_wait() |
| { |
| pthread_mutex_lock(&m_lock); |
| while (wait_for_cond == TRUE) { |
| pthread_cond_wait(&m_cond, &m_lock); |
| } |
| pthread_mutex_unlock(&m_lock); |
| } |
| |
| /*=========================================================================== |
| * 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 QCameraStream::putBufs(mm_camera_map_unmap_ops_tbl_t *ops_tbl) |
| { |
| int rc = NO_ERROR; |
| |
| if (mBufAllocPid != 0) { |
| cond_signal(true); |
| LOGL("wait for buf allocation thread dead"); |
| pthread_join(mBufAllocPid, NULL); |
| mBufAllocPid = 0; |
| LOGL("return from buf allocation thread"); |
| } |
| |
| uint8_t numBufsToUnmap = mStreamBufs->getMappable(); |
| for (uint32_t i = 0; i < numBufsToUnmap; i++) { |
| rc = ops_tbl->unmap_ops(i, -1, CAM_MAPPING_BUF_TYPE_STREAM_BUF, ops_tbl->userdata); |
| if (rc < 0) { |
| LOGE("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 ( !mStreamBufsAcquired ) { |
| mStreamBufs->deallocate(); |
| delete mStreamBufs; |
| mStreamBufs = NULL; |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : putBufsDeffered |
| * |
| * DESCRIPTION: function to deallocate deffered stream buffers |
| * |
| * PARAMETERS : none |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::putBufsDeffered() |
| { |
| if (mBufAllocPid != 0) { |
| cond_signal(true); |
| LOGH("%s: wait for buf allocation thread dead", __func__); |
| // Wait for the allocation of additional stream buffers |
| pthread_join(mBufAllocPid, NULL); |
| mBufAllocPid = 0; |
| LOGH("%s: return from buf allocation thread", __func__); |
| } |
| // Deallocation of the deffered stream buffers handled separately |
| return NO_ERROR; |
| } |
| |
| /*=========================================================================== |
| * 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 QCameraStream::invalidateBuf(uint32_t index) |
| { |
| if (mStreamBufs == NULL) { |
| LOGE("Invalid Operation"); |
| return INVALID_OPERATION; |
| } |
| return mStreamBufs->invalidateCache(index); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : cleanInvalidateBuf |
| * |
| * DESCRIPTION: clean invalidate a specific stream buffer |
| * |
| * PARAMETERS : |
| * @index : index of the buffer to clean invalidate |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::cleanInvalidateBuf(uint32_t index) |
| { |
| if (mStreamBufs == NULL) { |
| LOGE("Invalid Operation"); |
| return INVALID_OPERATION; |
| } |
| return mStreamBufs->cleanInvalidateCache(index); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : isTypeOf |
| * |
| * DESCRIPTION: helper function to determine if the stream is of the queried type |
| * |
| * PARAMETERS : |
| * @type : stream type as of queried |
| * |
| * RETURN : true/false |
| *==========================================================================*/ |
| bool QCameraStream::isTypeOf(cam_stream_type_t type) |
| { |
| if (mStreamInfo != NULL && (mStreamInfo->stream_type == type)) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : isOrignalTypeOf |
| * |
| * DESCRIPTION: helper function to determine if the original stream is of the |
| * queried type if it's reproc stream |
| * |
| * PARAMETERS : |
| * @type : stream type as of queried |
| * |
| * RETURN : true/false |
| *==========================================================================*/ |
| bool QCameraStream::isOrignalTypeOf(cam_stream_type_t type) |
| { |
| if (mStreamInfo != NULL && |
| mStreamInfo->stream_type == CAM_STREAM_TYPE_OFFLINE_PROC && |
| mStreamInfo->reprocess_config.pp_type == CAM_ONLINE_REPROCESS_TYPE && |
| mStreamInfo->reprocess_config.online.input_stream_type == type) { |
| return true; |
| } else if ( |
| mStreamInfo != NULL && |
| mStreamInfo->stream_type == CAM_STREAM_TYPE_OFFLINE_PROC && |
| mStreamInfo->reprocess_config.pp_type == CAM_OFFLINE_REPROCESS_TYPE && |
| mStreamInfo->reprocess_config.offline.input_type == type) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : getMyType |
| * |
| * DESCRIPTION: return stream type |
| * |
| * PARAMETERS : none |
| * |
| * RETURN : stream type |
| *==========================================================================*/ |
| cam_stream_type_t QCameraStream::getMyType() |
| { |
| if (mStreamInfo != NULL) { |
| return mStreamInfo->stream_type; |
| } else { |
| return CAM_STREAM_TYPE_DEFAULT; |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : getMyOriginalType |
| * |
| * DESCRIPTION: return stream type |
| * |
| * PARAMETERS : none |
| * |
| * RETURN : stream type |
| *==========================================================================*/ |
| cam_stream_type_t QCameraStream::getMyOriginalType() |
| { |
| if (mStreamInfo != NULL) { |
| if (mStreamInfo->stream_type == CAM_STREAM_TYPE_OFFLINE_PROC && |
| mStreamInfo->reprocess_config.pp_type == CAM_ONLINE_REPROCESS_TYPE) { |
| return mStreamInfo->reprocess_config.online.input_stream_type; |
| } else if (mStreamInfo->stream_type == CAM_STREAM_TYPE_OFFLINE_PROC && |
| mStreamInfo->reprocess_config.pp_type == CAM_OFFLINE_REPROCESS_TYPE) { |
| return mStreamInfo->reprocess_config.offline.input_type; |
| } else { |
| return mStreamInfo->stream_type; |
| } |
| } else { |
| return CAM_STREAM_TYPE_DEFAULT; |
| } |
| } |
| |
| /*=========================================================================== |
| * 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 QCameraStream::getFrameOffset(cam_frame_len_offset_t &offset) |
| { |
| if (NULL == mStreamInfo) { |
| return NO_INIT; |
| } |
| |
| offset = mFrameLenOffset; |
| if ((ROTATE_90 == mOnlineRotation) || (ROTATE_270 == mOnlineRotation) |
| || (offset.frame_len == 0) || (offset.num_planes == 0)) { |
| // Re-calculate frame offset in case of online rotation |
| cam_stream_info_t streamInfo = *mStreamInfo; |
| getFrameDimension(streamInfo.dim); |
| calcOffset(&streamInfo); |
| offset = streamInfo.buf_planes.plane_info; |
| } |
| |
| return 0; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : getCropInfo |
| * |
| * DESCRIPTION: query crop info of the stream |
| * |
| * PARAMETERS : |
| * @crop : reference to struct to store the queried crop info |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::getCropInfo(cam_rect_t &crop) |
| { |
| pthread_mutex_lock(&mCropLock); |
| crop = mCropInfo; |
| pthread_mutex_unlock(&mCropLock); |
| return NO_ERROR; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : setCropInfo |
| * |
| * DESCRIPTION: set crop info of the stream |
| * |
| * PARAMETERS : |
| * @crop : struct to store new crop info |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::setCropInfo(cam_rect_t crop) |
| { |
| pthread_mutex_lock(&mCropLock); |
| mCropInfo = crop; |
| pthread_mutex_unlock(&mCropLock); |
| return NO_ERROR; |
| } |
| |
| /*=========================================================================== |
| * 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 QCameraStream::getFrameDimension(cam_dimension_t &dim) |
| { |
| if (mStreamInfo != NULL) { |
| if ((ROTATE_90 == mOnlineRotation) || (ROTATE_270 == mOnlineRotation)) { |
| dim.width = mStreamInfo->dim.height; |
| dim.height = mStreamInfo->dim.width; |
| } else { |
| 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 QCameraStream::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 QCameraStream::getMyServerID() { |
| if (mStreamInfo != NULL) { |
| return mStreamInfo->stream_svr_id; |
| } else { |
| return 0; |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : acquireStreamBufs |
| * |
| * DESCRIPTION: acquire stream buffers and postpone their release. |
| * |
| * PARAMETERS : None |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::acquireStreamBufs() |
| { |
| mStreamBufsAcquired = true; |
| |
| return NO_ERROR; |
| } |
| |
| /*=========================================================================== |
| * 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 address |
| * @size : lenght of the buffer |
| * @ops_tbl : ptr to buf mapping/unmapping ops |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::mapBuf(uint8_t buf_type, uint32_t buf_idx, |
| int32_t plane_idx, int fd, void *buffer, size_t size, |
| mm_camera_map_unmap_ops_tbl_t *ops_tbl) |
| { |
| cam_buf_map_type_list bufMapList; |
| int32_t rc = QCameraBufferMaps::makeSingletonBufMapList( |
| (cam_mapping_buf_type)buf_type, mHandle, buf_idx, plane_idx, |
| 0 /*cookie*/, fd, size, bufMapList, buffer); |
| |
| if (rc != NO_ERROR) { |
| return rc; |
| } |
| |
| return mapBufs(bufMapList, ops_tbl); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mapBufs |
| * |
| * DESCRIPTION: map stream related buffers to backend server |
| * |
| * PARAMETERS : |
| * @bufMapList : buffer mapping information |
| * @ops_tbl : ptr to buf mapping/unmapping ops |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| |
| int32_t QCameraStream::mapBufs(cam_buf_map_type_list bufMapList, |
| __unused mm_camera_map_unmap_ops_tbl_t *ops_tbl) |
| { |
| if (m_MemOpsTbl.bundled_map_ops != NULL) { |
| return m_MemOpsTbl.bundled_map_ops(&bufMapList, m_MemOpsTbl.userdata); |
| } else { |
| return mCamOps->map_stream_bufs(mCamHandle, mChannelHandle, |
| &bufMapList); |
| } |
| |
| } |
| |
| /*=========================================================================== |
| * 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 |
| * @ops_tbl : ptr to buf mapping/unmapping ops |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::unmapBuf(uint8_t buf_type, uint32_t buf_idx, int32_t plane_idx, |
| mm_camera_map_unmap_ops_tbl_t *ops_tbl) |
| { |
| if (ops_tbl != NULL) { |
| return ops_tbl->unmap_ops(buf_idx, plane_idx, |
| (cam_mapping_buf_type)buf_type, ops_tbl->userdata); |
| } else { |
| 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 QCameraStream::setParameter(cam_stream_parm_buffer_t ¶m) |
| { |
| int32_t rc = NO_ERROR; |
| pthread_mutex_lock(&mParameterLock); |
| mStreamInfo->parm_buf = param; |
| rc = mCamOps->set_stream_parms(mCamHandle, |
| mChannelHandle, |
| mHandle, |
| &mStreamInfo->parm_buf); |
| if (rc == NO_ERROR) { |
| param = mStreamInfo->parm_buf; |
| } |
| pthread_mutex_unlock(&mParameterLock); |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : getParameter |
| * |
| * DESCRIPTION: get stream based parameters |
| * |
| * PARAMETERS : |
| * @param : ptr to parameters to be red |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::getParameter(cam_stream_parm_buffer_t ¶m) |
| { |
| int32_t rc = NO_ERROR; |
| pthread_mutex_lock(&mParameterLock); |
| mStreamInfo->parm_buf = param; |
| rc = mCamOps->get_stream_parms(mCamHandle, |
| mChannelHandle, |
| mHandle, |
| &mStreamInfo->parm_buf); |
| if (rc == NO_ERROR) { |
| param = mStreamInfo->parm_buf; |
| } |
| pthread_mutex_unlock(&mParameterLock); |
| 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 QCameraStream::releaseFrameData(void *data, void *user_data) |
| { |
| QCameraStream *pme = (QCameraStream *)user_data; |
| mm_camera_super_buf_t *frame = (mm_camera_super_buf_t *)data; |
| if (NULL != pme) { |
| pme->bufDone(frame->bufs[0]->buf_idx); |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : configStream |
| * |
| * DESCRIPTION: send stream configuration to back end |
| * |
| * PARAMETERS : |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * none-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::configStream() |
| { |
| int rc = NO_ERROR; |
| |
| // Configure the stream |
| mm_camera_stream_config_t stream_config; |
| stream_config.stream_info = mStreamInfo; |
| stream_config.mem_vtbl = mMemVtbl; |
| stream_config.stream_cb_sync = NULL; |
| stream_config.stream_cb = dataNotifyCB; |
| stream_config.padding_info = mPaddingInfo; |
| stream_config.userdata = this; |
| rc = mCamOps->config_stream(mCamHandle, |
| mChannelHandle, mHandle, &stream_config); |
| if (rc < 0) { |
| LOGE("Failed to config stream, rc = %d", rc); |
| mCamOps->unmap_stream_buf(mCamHandle, |
| mChannelHandle, |
| mHandle, |
| CAM_MAPPING_BUF_TYPE_STREAM_INFO, |
| 0, |
| -1); |
| return UNKNOWN_ERROR; |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : setSyncDataCB |
| * |
| * DESCRIPTION: register callback with mm-interface for this stream |
| * |
| * PARAMETERS : |
| @stream_cb : Callback function |
| * |
| * RETURN : int32_t type of status |
| * NO_ERROR -- success |
| * non-zero failure code |
| *==========================================================================*/ |
| int32_t QCameraStream::setSyncDataCB(stream_cb_routine data_cb) |
| { |
| int32_t rc = NO_ERROR; |
| |
| if (mCamOps != NULL) { |
| mSYNCDataCB = data_cb; |
| rc = mCamOps->register_stream_buf_cb(mCamHandle, |
| mChannelHandle, mHandle, dataNotifySYNCCB, MM_CAMERA_STREAM_CB_TYPE_SYNC, |
| this); |
| if (rc == NO_ERROR) { |
| mSyncCBEnabled = TRUE; |
| return rc; |
| } |
| } |
| LOGE("Interface handle is NULL"); |
| return UNKNOWN_ERROR; |
| } |
| |
| }; // namespace qcamera |