aboutsummaryrefslogtreecommitdiff
path: root/camera/QCamera2/HAL/QCameraStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--camera/QCamera2/HAL/QCameraStream.cpp2656
1 files changed, 2656 insertions, 0 deletions
diff --git a/camera/QCamera2/HAL/QCameraStream.cpp b/camera/QCamera2/HAL/QCameraStream.cpp
new file mode 100644
index 0000000..cbe8a6a
--- /dev/null
+++ b/camera/QCamera2/HAL/QCameraStream.cpp
@@ -0,0 +1,2656 @@
+/* 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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
+ * @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, 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);
+
+ 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 &param)
+{
+ 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 &param)
+{
+ 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