Android Camera OMX方式数据流分析
在上一篇文章中,对preview过程做了一些简单的分析,其实没有很深入的分析,这篇文章就要在上一篇文章的基础之上深入分析数据到底是怎么传递的,其一,图像是怎样显示的,其二,图像是怎样保存的,这里只针对OMX这种方式进行分析,其实V4L2方式只是在CameraAdapter这里的实现不一样,其他层的调用基本是一致的,理解了OMX方法数据的流向,V4L2方式就没有什么问题
现在开始步入正题了
首先我们必须明确的是camera的图像是需要buffer存储的,那么这块内存是在哪里分配的呢
android camera的操作过程相信大家都比较熟悉,即使不是android 的camera,其他camera也都是一样的,只要打开camera,就自动进入preview模式,然后你点某个button拍了一张照片,或者点了某个button录了一段视频,这是camera的最主要功能,那么应该只有两种可能吧,就是一开始camera被调用的时候内存就申请了,另一种就是打开camera后,开始preview前申请内存,但肯定是不能再preview之后的,很容易理解啊,就像睡觉时先眯起眼睛在睡着的,而不是先睡着再眯起眼睛,嘻嘻
不知道的可以大体看一下frameworks的app,你可以发现好像是没有申请什么内存的方法出现,当然我没有那么细心的去看,那是因为我是认为是通过上面的第二种可能申请内存的,现在就开始看看
camera 打开后,一切都初始化ok,然后就真正的开始干活了,那就是调用startPreview了,开始preview啊,这从app一路高歌,知道走到hal层才去申请这个空间,让我不禁感慨app层就是爽,一声令下,底层你怎么去实现我不管,我只要结果,多有范儿,底层就用足了力气实现去了
再说细一点,这个内存的申请是在hal层startPreview的cameraPreviewInitialization方法中实现的,先贴出代码,待会分析
- status_t CameraHal::allocPreviewBufs(int width, int height, const char* previewFormat, unsigned int buffercount, unsigned int &max_queueable)
- {
- status_t ret = NO_ERROR;
-
- LOG_FUNCTION_NAME;
-
- if(mDisplayAdapter.get() == NULL)
- {
- // Memory allocation of preview buffers is now placed in gralloc
- // CameraHal should not allocate preview buffers without DisplayAdapter
- return NO_MEMORY;
- }
-
- if(!mPreviewBuffers)
- {
- mPreviewLength = 0;
- mPreviewBuffers = mDisplayAdapter->allocateBufferList(width, height,
- previewFormat,
- mPreviewLength,
- buffercount);
- if (NULL == mPreviewBuffers ) {
- CAMHAL_LOGEA("Couldn't allocate preview buffers");
- return NO_MEMORY;
- }
-
- mPreviewOffsets = (uint32_t *) mDisplayAdapter->getOffsets();
- if ( NULL == mPreviewOffsets ) {
- CAMHAL_LOGEA("Buffer mapping failed");
- return BAD_VALUE;
- }
- //指定bufferProvider
- mBufProvider = (BufferProvider*) mDisplayAdapter.get();
- //获取mac_queueable
- ret = mDisplayAdapter->maxQueueableBuffers(max_queueable);
- if (ret != NO_ERROR) {
- return ret;
- }
- }
-
- LOG_FUNCTION_NAME_EXIT;
-
- return ret;
- }
这个方法传入了几个参数,前几个参数是在这个方法之前都可以得到的,方法没什么难的,很容易理解
width:显示的宽
height:显示的高
previewFrame:显示的frame
buffercount:buffer的个数
max_queueable:这个参数以引用方式调用,重点是他是要往外带东西的,嘻嘻
上面的代码在开始分析之前,先大体看一下,也许你可以猜到,这里申请的mPreviewBuffer到底是用来干什么的,他是一个CameraFrame类型,底层获取到的数据最后都会打包成CameraFrame类型在往app层转交,或者直接通过overlay方式显示出来
在这之后还申请了一块memory,其实我不是很理解具体有什么意义,先看看吧
- status_t CameraHal::allocPreviewDataBufs(size_t size, size_t bufferCount)
- {
- status_t ret = NO_ERROR;
- int bytes;
-
- LOG_FUNCTION_NAME;
-
- bytes = size;
-
- if ( NO_ERROR == ret )
- {
- if( NULL != mPreviewDataBuffers )
- {
- ret = freePreviewDataBufs();
- }
- }
-
- if ( NO_ERROR == ret )
- {
- bytes = ((bytes+4095)/4096)*4096;
- mPreviewDataBuffers = mMemoryManager->allocateBufferList(0, 0, NULL, bytes, bufferCount);
-
- CAMHAL_LOGDB("Size of Preview data buffer = %d", bytes);
- if( NULL == mPreviewDataBuffers )
- {
- CAMHAL_LOGEA("Couldn't allocate image buffers using memory manager");
- ret = -NO_MEMORY;
- }
- else
- {
- bytes = size;
- }
- }
-
- if ( NO_ERROR == ret )
- {
- mPreviewDataFd = mMemoryManager->getFd();
- mPreviewDataLength = bytes;
- mPreviewDataOffsets = mMemoryManager->getOffsets();
- }
- else
- {
- mPreviewDataFd = -1;
- mPreviewDataLength = 0;
- mPreviewDataOffsets = NULL;
- }
-
- LOG_FUNCTION_NAME_EXIT;
-
- return ret;
- }
这里是通过
mMemoryManager申请的一块内存区域,这里先知道这个内存区mPreviewDataBuffers
这里首先对
mPreviewDataBuffers这块内存相关的属性信息打包到BuffersDescriptor这个结构中,然后调用
mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW_DATA, ( int ) &desc);
我们看看OMXCameraAdapter是怎样对应实现的吧
- case CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW_DATA:
- CAMHAL_LOGDA("Use buffers for preview data");
- desc = ( BuffersDescriptor * ) value1;
-
- if ( NULL == desc )
- {
- CAMHAL_LOGEA("Invalid preview data buffers!");
- return -EINVAL;
- }
-
- if ( ret == NO_ERROR )
- {
- ret = setState(operation);
- }
-
- if ( ret == NO_ERROR )
- {
- Mutex::Autolock lock(mPreviewDataBufferLock);
- mPreviewDataBuffers = desc->mBuffers;
- mPreviewDataBuffersLength = desc->mLength;
- mPreviewDataBuffersAvailable.clear();
- for ( uint32_t i = 0 ; i < desc->mMaxQueueable ; i++ )
- {
- mPreviewDataBuffersAvailable.add(&mPreviewDataBuffers[i], 0);
- }
- // initial ref count for undeqeueued buffers is 1 since buffer provider
- // is still holding on to it
- for ( uint32_t i = desc->mMaxQueueable ; i < desc->mCount ; i++ )
- {
- mPreviewDataBuffersAvailable.add(&mPreviewDataBuffers[i], 1);
- }
- }
-
- if ( NULL != desc )
- {
- ret = useBuffers(CameraAdapter::CAMERA_MEASUREMENT,
- desc->mBuffers,
- desc->mCount,
- desc->mLength,
- desc->mMaxQueueable);
- }
-
- if ( ret == NO_ERROR )
- {
- ret = commitState();
- }
- else
- {
- ret |= rollbackState();
- }
-
- break;
这里先不做过多说明,之后遇到了再说,最终他会调用到OMXCameraAdapter的UseBuffersPreviewData方法,看看他的实现
- status_t OMXCameraAdapter::UseBuffersPreviewData(CameraBuffer * bufArr, int num)
- {
- status_t ret = NO_ERROR;
- OMX_ERRORTYPE eError = OMX_ErrorNone;
- OMXCameraPortParameters * measurementData = NULL;
- Mutex::Autolock lock( mPreviewDataBufferLock);
-
- LOG_FUNCTION_NAME;
-
- if ( mComponentState != OMX_StateLoaded )
- {
- CAMHAL_LOGEA("Calling UseBuffersPreviewData() when not in LOADED state");
- return BAD_VALUE;
- }
-
- if ( NULL == bufArr )
- {
- CAMHAL_LOGEA("NULL pointer passed for buffArr");
- return BAD_VALUE;
- }
-
- if ( 0 != mUsePreviewDataSem.Count() )
- {
- CAMHAL_LOGEB("Error mUsePreviewDataSem semaphore count %d", mUsePreviewDataSem.Count());
- LOG_FUNCTION_NAME_EXIT;
- return NO_INIT;
- }
-
- if ( NO_ERROR == ret )
- {
- 这里只是把num这个参数保存到measurementPortIndex对应的参数mNumBufs
- measurementData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex];
- measurementData->mNumBufs = num ;
- }
-
- if ( NO_ERROR == ret )
- {
- ///Register for port enable event on measurement port
- ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp,
- OMX_EventCmdComplete,
- OMX_CommandPortEnable,
- mCameraAdapterParameters.mMeasurementPortIndex,
- mUsePreviewDataSem);
-
- if ( ret == NO_ERROR )
- {
- CAMHAL_LOGDB("Registering for event %d", ret);
- }
- else
- {
- CAMHAL_LOGEB("Error in registering for event %d", ret);
- goto EXIT;
- }
- }
-
- if ( NO_ERROR == ret )
- {
- //Enable MEASUREMENT Port
- eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp,
- OMX_CommandPortEnable,
- mCameraAdapterParameters.mMeasurementPortIndex,
- NULL);
-
- if ( eError == OMX_ErrorNone )
- {
- CAMHAL_LOGDB("OMX_SendCommand(OMX_CommandPortEnable) -0x%x", eError);
- }
- else
- {
- CAMHAL_LOGEB("OMX_SendCommand(OMX_CommandPortEnable) -0x%x", eError);
- goto EXIT;
- }
- }
-
- if ( NO_ERROR == ret )
- {
- ret = mUsePreviewDataSem.WaitTimeout(OMX_CMD_TIMEOUT);
-
- //If somethiing bad happened while we wait
- if (mComponentState == OMX_StateInvalid)
- {
- CAMHAL_LOGEA("Invalid State after measurement port enable Exitting!!!");
- goto EXIT;
- }
-
- if ( NO_ERROR == ret )
- {
- CAMHAL_LOGDA("Port enable event arrived on measurement port");
- }
- else
- {
- ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp,
- OMX_EventCmdComplete,
- OMX_CommandPortEnable,
- mCameraAdapterParameters.mMeasurementPortIndex,
- NULL);
- CAMHAL_LOGEA("Timeout expoired during port enable on measurement port");
- goto EXIT;
- }
-
- CAMHAL_LOGDA("Port enable event arrived on measurement port");
- }
-
- LOG_FUNCTION_NAME_EXIT;
-
- return ret;
- EXIT:
- CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError);
- performCleanupAfterError();
- LOG_FUNCTION_NAME_EXIT;
- return (ret | ErrorUtils::omxToAndroidError(eError));
- }
接下来
首先对
mPreviewBuffers这块内存相关的属性信息打包到BuffersDescriptor这个结构中,然后调用
ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW, ( int ) &desc);
看看他的具体实现吧
- case CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW:
- CAMHAL_LOGDA("Use buffers for preview");
- desc = ( BuffersDescriptor * ) value1;
-
- if ( NULL == desc )
- {
- CAMHAL_LOGEA("Invalid preview buffers!");
- return -EINVAL;
- }
-
- if ( ret == NO_ERROR )
- {
- ret = setState(operation);
- }
-
- if ( ret == NO_ERROR )
- {
- Mutex::Autolock lock(mPreviewBufferLock);
- mPreviewBuffers = desc->mBuffers;
- mPreviewBuffersLength = desc->mLength;
- mPreviewBuffersAvailable.clear();
- mSnapshotBuffersAvailable.clear();
- for ( uint32_t i = 0 ; i < desc->mMaxQueueable ; i++ )
- {
- mPreviewBuffersAvailable.add(&mPreviewBuffers[i], 0);
- }
- // initial ref count for undeqeueued buffers is 1 since buffer provider
- // is still holding on to it
- for ( uint32_t i = desc->mMaxQueueable ; i < desc->mCount ; i++ )
- {
- mPreviewBuffersAvailable.add(&mPreviewBuffers[i], 1);
- }
- }
-
- if ( NULL != desc )
- {
- ret = useBuffers(CameraAdapter::CAMERA_PREVIEW,
- desc->mBuffers,
- desc->mCount,
- desc->mLength,
- desc->mMaxQueueable);
- }
-
- if ( ret == NO_ERROR )
- {
- ret = commitState();
- }
- else
- {
- ret |= rollbackState();
- }
-
- break;
到这里大家看到了这个过程跟上面的调用时那么的相似,接下来也看看他在OMXCameraAdapter的实现方法UseBuffersPreview
- status_t OMXCameraAdapter::UseBuffersPreview(CameraBuffer * bufArr, int num)
- {
- status_t ret = NO_ERROR;
- OMX_ERRORTYPE eError = OMX_ErrorNone;
- int tmpHeight, tmpWidth;
-
- LOG_FUNCTION_NAME;
-
- if(!bufArr)
- {
- CAMHAL_LOGEA("NULL pointer passed for buffArr");
- LOG_FUNCTION_NAME_EXIT;
- return BAD_VALUE;
- }
-
- OMXCameraPortParameters * mPreviewData = NULL;
- OMXCameraPortParameters *measurementData = NULL;
- 这里暂时将mPreviewData和measurementData这两个指针分别指向preview port和measurement port的port params结构,方便之后对这两个port的设置
- mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex];
- measurementData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex];
- mPreviewData->mNumBufs = num ;
-
- if ( 0 != mUsePreviewSem.Count() )
- {
- CAMHAL_LOGEB("Error mUsePreviewSem semaphore count %d", mUsePreviewSem.Count());
- LOG_FUNCTION_NAME_EXIT;
- return NO_INIT;
- }
-
- if(mPreviewData->mNumBufs != num)
- {
- CAMHAL_LOGEA("Current number of buffers doesnt equal new num of buffers passed!");
- LOG_FUNCTION_NAME_EXIT;
- return BAD_VALUE;
- }
-
- mStateSwitchLock.lock();
- 这里两个横线之中的内容,其实我没有很理解这些东西是干什么用的,不影响我们接着往下看,暂不深入追究
- if ( mComponentState == OMX_StateLoaded ) {
-
- if (mPendingPreviewSettings & SetLDC) {
- mPendingPreviewSettings &= ~SetLDC;
- ret = setLDC(mIPP);
- if ( NO_ERROR != ret ) {
- CAMHAL_LOGEB("setLDC() failed %d", ret);
- }
- }
-
- if (mPendingPreviewSettings & SetNSF) {
- mPendingPreviewSettings &= ~SetNSF;
- ret = setNSF(mIPP);
- if ( NO_ERROR != ret ) {
- CAMHAL_LOGEB("setNSF() failed %d", ret);
- }
- }
-
- if (mPendingPreviewSettings & SetCapMode) {
- mPendingPreviewSettings &= ~SetCapMode;
- ret = setCaptureMode(mCapMode);
- if ( NO_ERROR != ret ) {
- CAMHAL_LOGEB("setCaptureMode() failed %d", ret);
- }
- }
-
- if(mCapMode == OMXCameraAdapter::VIDEO_MODE) {
-
- if (mPendingPreviewSettings & SetVNF) {
- mPendingPreviewSettings &= ~SetVNF;
- ret = enableVideoNoiseFilter(mVnfEnabled);
- if ( NO_ERROR != ret){
- CAMHAL_LOGEB("Error configuring VNF %x", ret);
- }
- }
-
- if (mPendingPreviewSettings & SetVSTAB) {
- mPendingPreviewSettings &= ~SetVSTAB;
- ret = enableVideoStabilization(mVstabEnabled);
- if ( NO_ERROR != ret) {
- CAMHAL_LOGEB("Error configuring VSTAB %x", ret);
- }
- }
-
- }
- }
-
- ret = setSensorOrientation(mSensorOrientation);
- if ( NO_ERROR != ret )
- {
- CAMHAL_LOGEB("Error configuring Sensor Orientation %x", ret);
- mSensorOrientation = 0;
- }
-
- if ( mComponentState == OMX_StateLoaded )
- {
- ///Register for IDLE state switch event
- ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp,
- OMX_EventCmdComplete,
- OMX_CommandStateSet,
- OMX_StateIdle,
- mUsePreviewSem);
-
- if(ret!=NO_ERROR)
- {
- CAMHAL_LOGEB("Error in registering for event %d", ret);
- goto EXIT;
- }
-
- ///Once we get the buffers, move component state to idle state and pass the buffers to OMX comp using UseBuffer
- eError = OMX_SendCommand (mCameraAdapterParameters.mHandleComp ,
- OMX_CommandStateSet,
- OMX_StateIdle,
- NULL);
-
- CAMHAL_LOGDB("OMX_SendCommand(OMX_CommandStateSet) 0x%x", eError);
-
- GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError);
-
- mComponentState = OMX_StateIdle;
- }
- else
- {
- ///Register for Preview port ENABLE event
- ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp,
- OMX_EventCmdComplete,
- OMX_CommandPortEnable,
- mCameraAdapterParameters.mPrevPortIndex,
- mUsePreviewSem);
-
- if ( NO_ERROR != ret )
- {
- CAMHAL_LOGEB("Error in registering for event %d", ret);
- goto EXIT;
- }
-
- ///Enable Preview Port
- eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp,
- OMX_CommandPortEnable,
- mCameraAdapterParameters.mPrevPortIndex,
- NULL);
- }
-
-
- ///Configure DOMX to use either gralloc handles or vptrs
- OMX_TI_PARAMUSENATIVEBUFFER domxUseGrallocHandles;
- OMX_INIT_STRUCT_PTR (&domxUseGrallocHandles, OMX_TI_PARAMUSENATIVEBUFFER);
-
- domxUseGrallocHandles.nPortIndex = mCameraAdapterParameters.mPrevPortIndex;
- domxUseGrallocHandles.bEnable = OMX_TRUE;
-
- eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, (OMX_INDEXTYPE)OMX_TI_IndexUseNativeBuffers, &domxUseGrallocHandles);
- if(eError!=OMX_ErrorNone)
- {
- CAMHAL_LOGEB("OMX_SetParameter - %x", eError);
- }
- GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError);
-
- OMX_BUFFERHEADERTYPE *pBufferHdr;
- for(int index=0;index<num;index++) {
- OMX_U8 *ptr;
-
- ptr = (OMX_U8 *)camera_buffer_get_omx_ptr (&bufArr[index]);
- eError = OMX_UseBuffer( mCameraAdapterParameters.mHandleComp,
- &pBufferHdr,
- mCameraAdapterParameters.mPrevPortIndex,
- 0,
- mPreviewData->mBufSize,
- ptr);
- if(eError!=OMX_ErrorNone)
- {
- CAMHAL_LOGEB("OMX_UseBuffer-0x%x", eError);
- }
- GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError);
- 这里在我看来还是很重要的,将我们从hal层申请的内存与preview port的bufferheader关联到一起,这里先填充一个bufferheader然后指向port param的mBufferHeader
- pBufferHdr->pAppPrivate = (OMX_PTR)&bufArr[index];
- pBufferHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
- pBufferHdr->nVersion.s.nVersionMajor = 1 ;
- pBufferHdr->nVersion.s.nVersionMinor = 1 ;
- pBufferHdr->nVersion.s.nRevision = 0 ;
- pBufferHdr->nVersion.s.nStep = 0;
- mPreviewData->mBufferHeader[index] = pBufferHdr;
- }
-
- if ( mMeasurementEnabled )
- {
-
- for( int i = 0; i < num; i++ )
- {
- OMX_BUFFERHEADERTYPE *pBufHdr;
- OMX_U8 *ptr;
-
- ptr = (OMX_U8 *)camera_buffer_get_omx_ptr (&mPreviewDataBuffers[i]);
- eError = OMX_UseBuffer( mCameraAdapterParameters.mHandleComp,
- &pBufHdr,
- mCameraAdapterParameters.mMeasurementPortIndex,
- 0,
- measurementData->mBufSize,
- ptr);
-
- if ( eError == OMX_ErrorNone )
- {
- 这里在我看来还是很重要的,将我们从hal层申请的内存与measurement port的bufferheader关联到一起,这里先填充一个bufferheader然后指向port param的mBufferHeader
- pBufHdr->pAppPrivate = (OMX_PTR *)&mPreviewDataBuffers[i];
- pBufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
- pBufHdr->nVersion.s.nVersionMajor = 1 ;
- pBufHdr->nVersion.s.nVersionMinor = 1 ;
- pBufHdr->nVersion.s.nRevision = 0 ;
- pBufHdr->nVersion.s.nStep = 0;
- measurementData->mBufferHeader[i] = pBufHdr;
- }
- else
- {
- CAMHAL_LOGEB("OMX_UseBuffer -0x%x", eError);
- ret = BAD_VALUE;
- break;
- }
- }
-
- }
-
- CAMHAL_LOGDA("Registering preview buffers");
-
- ret = mUsePreviewSem.WaitTimeout(OMX_CMD_TIMEOUT);
-
- //If somethiing bad happened while we wait
- if (mComponentState == OMX_StateInvalid)
- {
- CAMHAL_LOGEA("Invalid State after Registering preview buffers Exitting!!!");
- goto EXIT;
- }
-
- if ( NO_ERROR == ret )
- {
- CAMHAL_LOGDA("Preview buffer registration successfull");
- }
- else
- {
- if ( mComponentState == OMX_StateLoaded )
- {
- ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp,
- OMX_EventCmdComplete,
- OMX_CommandStateSet,
- OMX_StateIdle,
- NULL);
- }
- else
- {
- ret |= SignalEvent(mCameraAdapterParameters.mHandleComp,
- OMX_EventCmdComplete,
- OMX_CommandPortEnable,
- mCameraAdapterParameters.mPrevPortIndex,
- NULL);
- }
- CAMHAL_LOGEA("Timeout expired on preview buffer registration");
- goto EXIT;
- }
-
- LOG_FUNCTION_NAME_EXIT;
-
- return (ret | ErrorUtils::omxToAndroidError(eError));
-
- ///If there is any failure, we reach here.
- ///Here, we do any resource freeing and convert from OMX error code to Camera Hal error code
- EXIT:
- mStateSwitchLock.unlock();
-
- CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError);
- performCleanupAfterError();
- CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError);
-
- LOG_FUNCTION_NAME_EXIT;
-
- return (ret | ErrorUtils::omxToAndroidError(eError));
- }
到这里我所关注的初始化已经完成了,其实一些初始动作,这里暂时不关注,最后hal层调用OMXCameraAdapter的startPreview真正要开始preview了
接下来的分析就要仔细一点了,相对来说很重要,不能马虎,慢慢研究startPreview的实现吧
- status_t OMXCameraAdapter::startPreview()
- {
- status_t ret = NO_ERROR;
- OMX_ERRORTYPE eError = OMX_ErrorNone;
- OMXCameraPortParameters *mPreviewData = NULL;
- OMXCameraPortParameters *measurementData = NULL;
-
- LOG_FUNCTION_NAME;
-
- if( 0 != mStartPreviewSem.Count() )
- {
- CAMHAL_LOGEB("Error mStartPreviewSem semaphore count %d", mStartPreviewSem.Count());
- ret = NO_INIT;
- goto EXIT;
- }
-
- // Enable all preview mode extra data.
- if ( OMX_ErrorNone == eError) {
- ret |= setExtraData(true, mCameraAdapterParameters.mPrevPortIndex, OMX_AncillaryData);
- ret |= setExtraData(true, OMX_ALL, OMX_TI_VectShotInfo);
- }
-
- 这里获取到preview port和measurement port param结构的指针,方便之后的使用
- mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex];
- measurementData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex];
-
- if( OMX_StateIdle == mComponentState )
- {
- ///Register for EXECUTING state transition.
- ///This method just inserts a message in Event Q, which is checked in the callback
- ///The sempahore passed is signalled by the callback
- ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp,
- OMX_EventCmdComplete,
- OMX_CommandStateSet,
- OMX_StateExecuting,
- mStartPreviewSem);
-
- if(ret!=NO_ERROR)
- {
- CAMHAL_LOGEB("Error in registering for event %d", ret);
- goto EXIT;
- }
-
- ///Switch to EXECUTING state,为fillbuffer做准备
- eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp,
- OMX_CommandStateSet,
- OMX_StateExecuting,
- NULL);
-
- if(eError!=OMX_ErrorNone)
- {
- CAMHAL_LOGEB("OMX_SendCommand(OMX_StateExecuting)-0x%x", eError);
- }
-
- CAMHAL_LOGDA("+Waiting for component to go into EXECUTING state");
- ret = mStartPreviewSem.WaitTimeout(OMX_CMD_TIMEOUT);
-
- //If somethiing bad happened while we wait
- if (mComponentState == OMX_StateInvalid)
- {
- CAMHAL_LOGEA("Invalid State after IDLE_EXECUTING Exitting!!!");
- goto EXIT;
- }
-
- if ( NO_ERROR == ret )
- {
- CAMHAL_LOGDA("+Great. Component went into executing state!!");
- }
- else
- {
- ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp,
- OMX_EventCmdComplete,
- OMX_CommandStateSet,
- OMX_StateExecuting,
- NULL);
- CAMHAL_LOGDA("Timeout expired on executing state switch!");
- goto EXIT;
- }
-
- mComponentState = OMX_StateExecuting;
-
- }
-
- mStateSwitchLock.unlock();
-
- //Queue all the buffers on preview port
- 这里把所有的preview port的bufferheader fill到preview port上,然后等待数据经过处理,buffer被填充后通过fillBufferDone回调给应用层
- for(int index=0;index< mPreviewData->mMaxQueueable;index++)
- {
- CAMHAL_LOGDB("Queuing buffer on Preview port - 0x%x", (uint32_t)mPreviewData->mBufferHeader[index]->pBuffer);
- mPreviewData->mStatus[index] = OMXCameraPortParameters::FILL;
- eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp,
- (OMX_BUFFERHEADERTYPE*)mPreviewData->mBufferHeader[index]);
- if(eError!=OMX_ErrorNone)
- {
- CAMHAL_LOGEB("OMX_FillThisBuffer-0x%x", eError);
- }
- mFramesWithDucati++;
- #ifdef CAMERAHAL_DEBUG
- mBuffersWithDucati.add((int)mPreviewData->mBufferHeader[index]->pAppPrivate,1);
- #endif
- GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError);
- }
-
- if ( mMeasurementEnabled )
- {
- 这里把所有的measure port的bufferheader fill到measure port上,然后等待数据经过处理,buffer被填充后通过fillBufferDone回调给应用层
- for(int index=0;index< mPreviewData->mNumBufs;index++)
- {
- CAMHAL_LOGDB("Queuing buffer on Measurement port - 0x%x", (uint32_t) measurementData->mBufferHeader[index]->pBuffer);
- measurementData->mStatus[index] = OMXCameraPortParameters::FILL;
- eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp,
- (OMX_BUFFERHEADERTYPE*) measurementData->mBufferHeader[index]);
- if(eError!=OMX_ErrorNone)
- {
- CAMHAL_LOGEB("OMX_FillThisBuffer-0x%x", eError);
- }
- GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError);
- }
-
- }
-
- setFocusCallback(true);
-
- //reset frame rate estimates
- mFPS = 0.0f;
- mLastFPS = 0.0f;
- // start frame count from 0. i.e first frame after
- // startPreview will be the 0th reference frame
- // this way we will wait for second frame until
- // takePicture/autoFocus is allowed to run. we
- // are seeing SetConfig/GetConfig fail after
- // calling after the first frame and not failing
- // after the second frame
- mFrameCount = -1;
- mLastFrameCount = 0;
- mIter = 1;
- mLastFPSTime = systemTime();
- mTunnelDestroyed = false;
-
- LOG_FUNCTION_NAME_EXIT;
-
- return (ret | ErrorUtils::omxToAndroidError(eError));
-
- EXIT:
-
- CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError);
- performCleanupAfterError();
- mStateSwitchLock.unlock();
- LOG_FUNCTION_NAME_EXIT;
-
- return (ret | ErrorUtils::omxToAndroidError(eError));
-
- }
经过上面的调用,之前初始化ok的buffer全部被分别fill到preview和measure port上,然后我上面也已经说过了,我们就等待组件处理完,并填充buffer,然后通知我,那么我们是在哪里接到组件的通知的呢??
不错,就是上面说的FillBufferDone方法,下面就多花点时间看看这个
FillBufferDone方法
- /*========================================================*/
- /* @ fn SampleTest_FillBufferDone :: Application callback*/
- /*========================================================*/
- OMX_ERRORTYPE OMXCameraAdapterFillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader)
- {
- TIUTILS::Message msg;
- OMX_ERRORTYPE eError = OMX_ErrorNone;
-
- if (UNLIKELY(mDebugFps)) {
- debugShowFPS();
- }
-
- OMXCameraAdapter *adapter = ( OMXCameraAdapter * ) pAppData;
- if ( NULL != adapter )
- {
- msg.command = OMXCameraAdapter::OMXCallbackHandler::CAMERA_FILL_BUFFER_DONE;
- msg.arg1 = ( void * ) hComponent;
- msg.arg2 = ( void * ) pBuffHeader;
- adapter->mOMXCallbackHandler->put(&msg);
- }
-
- return eError;
- }
分析一下上面的fillbufferdone方法,他没有直接对组件发给我们的消息做任何操作,他只是有点懒,他对发来的消息只是进行了打包然后就丢下去,让下面的小弟去做那些繁琐的处理过程,就是之前在初始化时启动的OMXCallbackHandler
线程
去做这件事请的,那么就看看这个handle方法吧,看看他到底是怎么处理的
- bool OMXCameraAdapter::OMXCallbackHandler::Handler()
- {
- TIUTILS::Message msg;
- volatile int forever = 1;
- status_t ret = NO_ERROR;
-
- LOG_FUNCTION_NAME;
-
- while(forever){
- TIUTILS::MessageQueue::waitForMsg(&mCommandMsgQ, NULL, NULL, -1);
- {
- Mutex::Autolock lock(mLock);
- mCommandMsgQ.get(&msg);
- mIsProcessed = false;
- }
-
- switch ( msg.command ) {
- case OMXCallbackHandler::CAMERA_FILL_BUFFER_DONE:
- {
- ret = mCameraAdapter->OMXCameraAdapterFillBufferDone(( OMX_HANDLETYPE ) msg.arg1, ( OMX_BUFFERHEADERTYPE *) msg.arg2);
- break;
- }
- case OMXCallbackHandler::CAMERA_FOCUS_STATUS:
- {
- mCameraAdapter->handleFocusCallback();
- break;
- }
- case CommandHandler::COMMAND_EXIT:
- {
- CAMHAL_LOGDA("Exiting OMX callback handler");
- forever = 0;
- break;
- }
- }
-
- {
- android::AutoMutex locker(mLock);
- CAMHAL_UNUSED(locker);
-
- mIsProcessed = mCommandMsgQ.isEmpty();
- if ( mIsProcessed )
- mCondition.signal();
- }
- }
-
- // force the condition to wake
- {
- android::AutoMutex locker(mLock);
- CAMHAL_UNUSED(locker);
-
- mIsProcessed = true;
- mCondition.signal();
- }
-
- LOG_FUNCTION_NAME_EXIT;
- return false;
- }
不错,上面标注部分就是组件给我们返回来的消息,开始处理喽,这个处理过程第一次看很复杂,没办法啊,谁让他那么重要呢??硬着头皮看看吧
- /*========================================================*/
- /* @ fn SampleTest_FillBufferDone :: Application callback*/
- /*========================================================*/
- OMX_ERRORTYPE OMXCameraAdapter::OMXCameraAdapterFillBufferDone(OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader)
- {
-
- status_t stat = NO_ERROR;
- status_t res1, res2;
- OMXCameraPortParameters *pPortParam;
- OMX_ERRORTYPE eError = OMX_ErrorNone;
- CameraFrame::FrameType typeOfFrame = CameraFrame::ALL_FRAMES;
- unsigned int refCount = 0;
- BaseCameraAdapter::AdapterState state, nextState;
- BaseCameraAdapter::getState(state);
- BaseCameraAdapter::getNextState(nextState);
- sp<CameraMetadataResult> metadataResult = NULL;
- unsigned int mask = 0xFFFF;
- CameraFrame cameraFrame;
- OMX_OTHER_EXTRADATATYPE *extraData;
- OMX_TI_ANCILLARYDATATYPE *ancillaryData = NULL;
- bool snapshotFrame = false;
-
- if ( NULL == pBuffHeader ) {
- return OMX_ErrorBadParameter;
- }
-
- #ifdef CAMERAHAL_OMX_PROFILING
-
- storeProfilingData(pBuffHeader);
-
- #endif
-
- res1 = res2 = NO_ERROR;
-
- if ( !pBuffHeader || !pBuffHeader->pBuffer ) {
- CAMHAL_LOGEA("NULL Buffer from OMX");
- return OMX_ErrorNone;
- }
- 这里这个pPortParm到底应该是哪个port的param呢??其实是不一定的
- 1.如果这个消息是preview port 的fillbufferdone,那么自然这里这个pPortParm指针指向的就是preview port 的param
- 2.如果这个消息是measurement port 的fillbufferdone,那么自然这里这个pPortParm指针指向的就是measurement port 的param
- pPortParam = &(mCameraAdapterParameters.mCameraPortParams[pBuffHeader->nOutputPortIndex]);
-
- // Find buffer and mark it as filled,首先比对,比对ok后标记为filldone
- for (int i = 0; i < pPortParam->mNumBufs; i++) {
- if (pPortParam->mBufferHeader[i] == pBuffHeader) {
- pPortParam->mStatus[i] = OMXCameraPortParameters::DONE;
- }
- }
- 从这里开始就要进行分类处理了,对应不同output port type有不同的处理方法
- 1.OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW(对应preview过程)
- if (pBuffHeader->nOutputPortIndex == OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW)
- {
-
- if ( ( PREVIEW_ACTIVE & state ) != PREVIEW_ACTIVE )
- {
- return OMX_ErrorNone;
- }
- 从这里开始我们暂时不做过多研究,只是对preview环境的一些初始化
- if ( mWaitingForSnapshot ) {
- extraData = getExtradata(pBuffHeader->pPlatformPrivate,
- (OMX_EXTRADATATYPE) OMX_AncillaryData);
-
- if ( NULL != extraData ) {
- ancillaryData = (OMX_TI_ANCILLARYDATATYPE*) extraData->data;
- if ((OMX_2D_Snap == ancillaryData->eCameraView)
- || (OMX_3D_Left_Snap == ancillaryData->eCameraView)
- || (OMX_3D_Right_Snap == ancillaryData->eCameraView)) {
- snapshotFrame = OMX_TRUE;
- } else {
- snapshotFrame = OMX_FALSE;
- }
- mPending3Asettings |= SetFocus;
- }
- }
-
- ///Prepare the frames to be sent - initialize CameraFrame object and reference count
- // TODO(XXX): ancillary data for snapshot frame is not being sent for video snapshot
- // if we are waiting for a snapshot and in video mode...go ahead and send
- // this frame as a snapshot
- if( mWaitingForSnapshot && (mCapturedFrames > 0) &&
- (snapshotFrame || (mCapMode == VIDEO_MODE)))
- {
- typeOfFrame = CameraFrame::SNAPSHOT_FRAME;
- mask = (unsigned int)CameraFrame::SNAPSHOT_FRAME;
-
- // video snapshot gets ancillary data and wb info from last snapshot frame
- mCaptureAncillaryData = ancillaryData;
- mWhiteBalanceData = NULL;
- extraData = getExtradata(pBuffHeader->pPlatformPrivate,
- (OMX_EXTRADATATYPE) OMX_WhiteBalance);
- if ( NULL != extraData )
- {
- mWhiteBalanceData = (OMX_TI_WHITEBALANCERESULTTYPE*) extraData->data;
- }
- }
- else
- {
- typeOfFrame = CameraFrame::PREVIEW_FRAME_SYNC;
- mask = (unsigned int)CameraFrame::PREVIEW_FRAME_SYNC;
- }
-
- if (mRecording)
- {
- mask |= (unsigned int)CameraFrame::VIDEO_FRAME_SYNC;
- mFramesWithEncoder++;
- }
-
- //LOGV("FBD pBuffer = 0x%x", pBuffHeader->pBuffer);
-
- if( mWaitingForSnapshot )
- {
- if (!mBracketingEnabled &&
- ((HIGH_SPEED == mCapMode) || (VIDEO_MODE == mCapMode)) )
- {
- notifyShutterSubscribers();
- }
- }
- 这里这个sendCallBacks还是要好好研究一下的
- stat = sendCallBacks(cameraFrame, pBuffHeader, mask, pPortParam);
- mFramesWithDisplay++;
-
- mFramesWithDucati--;
- 下面暂不做研究
- #ifdef CAMERAHAL_DEBUG
- if(mBuffersWithDucati.indexOfKey((uint32_t)pBuffHeader->pBuffer)<0)
- {
- LOGE("Buffer was never with Ducati!! %p", pBuffHeader->pBuffer);
- for(unsigned int i=0;i<mBuffersWithDucati.size();i++) LOGE("0x%x", mBuffersWithDucati.keyAt(i));
- }
- mBuffersWithDucati.removeItem((int)pBuffHeader->pBuffer);
- #endif
-
- if(mDebugFcs)
- CAMHAL_LOGEB("C[%d] D[%d] E[%d]", mFramesWithDucati, mFramesWithDisplay, mFramesWithEncoder);
-
- recalculateFPS();
-
- createPreviewMetadata(pBuffHeader, metadataResult, pPortParam->mWidth, pPortParam->mHeight);
- if ( NULL != metadataResult.get() ) {
- notifyMetadataSubscribers(metadataResult);
- metadataResult.clear();
- }
-
- {
- Mutex::Autolock lock(mFaceDetectionLock);
- if ( mFDSwitchAlgoPriority ) {
-
- //Disable region priority and enable face priority for AF
- setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, false);
- setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO , true);
-
- //Disable Region priority and enable Face priority
- setAlgoPriority(REGION_PRIORITY, EXPOSURE_ALGO, false);
- setAlgoPriority(FACE_PRIORITY, EXPOSURE_ALGO, true);
- mFDSwitchAlgoPriority = false;
- }
- }
-
- sniffDccFileDataSave(pBuffHeader);
-
- stat |= advanceZoom();
-
- // On the fly update to 3A settings not working
- // Do not update 3A here if we are in the middle of a capture
- // or in the middle of transitioning to it
- if( mPending3Asettings &&
- ( (nextState & CAPTURE_ACTIVE) == 0 ) &&
- ( (state & CAPTURE_ACTIVE) == 0 ) ) {
- apply3Asettings(mParameters3A);
- }
-
- }
- 2.OMX_CAMERA_PORT_VIDEO_OUT_MEASUREMENT
- else if( pBuffHeader->nOutputPortIndex == OMX_CAMERA_PORT_VIDEO_OUT_MEASUREMENT )
- {
- typeOfFrame = CameraFrame::FRAME_DATA_SYNC;
- mask = (unsigned int)CameraFrame::FRAME_DATA_SYNC;
-
- stat = sendCallBacks(cameraFrame, pBuffHeader, mask, pPortParam);
- }
- 3.OMX_CAMERA_PORT_IMAGE_OUT_IMAGE
- else if( pBuffHeader->nOutputPortIndex == OMX_CAMERA_PORT_IMAGE_OUT_IMAGE )
- {
- OMX_COLOR_FORMATTYPE pixFormat;
- const char *valstr = NULL;
-
- pixFormat = pPortParam->mColorFormat;
-
- if ( OMX_COLOR_FormatUnused == pixFormat )
- {
- typeOfFrame = CameraFrame::IMAGE_FRAME;
- mask = (unsigned int) CameraFrame::IMAGE_FRAME;
- } else if ( pixFormat == OMX_COLOR_FormatCbYCrY &&
- ((mPictureFormatFromClient &&
- !strcmp(mPictureFormatFromClient,
- CameraParameters::PIXEL_FORMAT_JPEG)) ||
- !mPictureFormatFromClient) ) {
- // signals to callbacks that this needs to be coverted to jpeg
- // before returning to framework
- typeOfFrame = CameraFrame::IMAGE_FRAME;
- mask = (unsigned int) CameraFrame::IMAGE_FRAME;
- cameraFrame.mQuirks |= CameraFrame::ENCODE_RAW_YUV422I_TO_JPEG;
- cameraFrame.mQuirks |= CameraFrame::FORMAT_YUV422I_UYVY;
-
- // populate exif data and pass to subscribers via quirk
- // subscriber is in charge of freeing exif data
- ExifElementsTable* exif = new ExifElementsTable();
- setupEXIF_libjpeg(exif, mCaptureAncillaryData, mWhiteBalanceData);
- cameraFrame.mQuirks |= CameraFrame::HAS_EXIF_DATA;
- cameraFrame.mCookie2 = (void*) exif;
- } else {
- typeOfFrame = CameraFrame::RAW_FRAME;
- mask = (unsigned int) CameraFrame::RAW_FRAME;
- }
-
- pPortParam->mImageType = typeOfFrame;
-
- if((mCapturedFrames>0) && !mCaptureSignalled)
- {
- mCaptureSignalled = true;
- mCaptureSem.Signal();
- }
-
- if( ( CAPTURE_ACTIVE & state ) != CAPTURE_ACTIVE )
- {
- goto EXIT;
- }
-
- {
- Mutex::Autolock lock(mBracketingLock);
- if ( mBracketingEnabled )
- {
- doBracketing(pBuffHeader, typeOfFrame);
- return eError;
- }
- }
-
- if (mZoomBracketingEnabled) {
- doZoom(mZoomBracketingValues[mCurrentZoomBracketing]);
- CAMHAL_LOGDB("Current Zoom Bracketing: %d", mZoomBracketingValues[mCurrentZoomBracketing]);
- mCurrentZoomBracketing++;
- if (mCurrentZoomBracketing == ARRAY_SIZE(mZoomBracketingValues)) {
- mZoomBracketingEnabled = false;
- }
- }
-
- if ( 1 > mCapturedFrames )
- {
- goto EXIT;
- }
-
- #ifdef OMAP_ENHANCEMENT_CPCAM
- setMetaData(cameraFrame.mMetaData, pBuffHeader->pPlatformPrivate);
- #endif
-
- CAMHAL_LOGDB("Captured Frames: %d", mCapturedFrames);
-
- mCapturedFrames--;
-
- #ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING
- if (mYuvCapture) {
- struct timeval timeStampUsec;
- gettimeofday(&timeStampUsec, NULL);
-
- time_t saveTime;
- time(&saveTime);
- const struct tm * const timeStamp = gmtime(&saveTime);
-
- char filename[256];
- snprintf(filename,256, "%s/yuv_%d_%d_%d_%lu.yuv",
- kYuvImagesOutputDirPath,
- timeStamp->tm_hour,
- timeStamp->tm_min,
- timeStamp->tm_sec,
- timeStampUsec.tv_usec);
-
- const status_t saveBufferStatus = saveBufferToFile(((CameraBuffer*)pBuffHeader->pAppPrivate)->mapped,
- pBuffHeader->nFilledLen, filename);
-
- if (saveBufferStatus != OK) {
- CAMHAL_LOGE("ERROR: %d, while saving yuv!", saveBufferStatus);
- } else {
- CAMHAL_LOGD("yuv_%d_%d_%d_%lu.yuv successfully saved in %s",
- timeStamp->tm_hour,
- timeStamp->tm_min,
- timeStamp->tm_sec,
- timeStampUsec.tv_usec,
- kYuvImagesOutputDirPath);
- }
- }
- #endif
-
- stat = sendCallBacks(cameraFrame, pBuffHeader, mask, pPortParam);
- }
- 4.OMX_CAMERA_PORT_VIDEO_OUT_VIDEO
- else if (pBuffHeader->nOutputPortIndex == OMX_CAMERA_PORT_VIDEO_OUT_VIDEO) {
- typeOfFrame = CameraFrame::RAW_FRAME;
- pPortParam->mImageType = typeOfFrame;
- {
- Mutex::Autolock lock(mLock);
- if( ( CAPTURE_ACTIVE & state ) != CAPTURE_ACTIVE ) {
- goto EXIT;
- }
- }
-
- CAMHAL_LOGD("RAW buffer done on video port, length = %d", pBuffHeader->nFilledLen);
-
- mask = (unsigned int) CameraFrame::RAW_FRAME;
-
- #ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING
- if ( mRawCapture ) {
- struct timeval timeStampUsec;
- gettimeofday(&timeStampUsec, NULL);
-
- time_t saveTime;
- time(&saveTime);
- const struct tm * const timeStamp = gmtime(&saveTime);
-
- char filename[256];
- snprintf(filename,256, "%s/raw_%d_%d_%d_%lu.raw",
- kRawImagesOutputDirPath,
- timeStamp->tm_hour,
- timeStamp->tm_min,
- timeStamp->tm_sec,
- timeStampUsec.tv_usec);
-
- const status_t saveBufferStatus = saveBufferToFile( ((CameraBuffer*)pBuffHeader->pAppPrivate)->mapped,
- pBuffHeader->nFilledLen, filename);
-
- if (saveBufferStatus != OK) {
- CAMHAL_LOGE("ERROR: %d , while saving raw!", saveBufferStatus);
- } else {
- CAMHAL_LOGD("raw_%d_%d_%d_%lu.raw successfully saved in %s",
- timeStamp->tm_hour,
- timeStamp->tm_min,
- timeStamp->tm_sec,
- timeStampUsec.tv_usec,
- kRawImagesOutputDirPath);
- stat = sendCallBacks(cameraFrame, pBuffHeader, mask, pPortParam);
- }
- }
- #endif
- } else {
- CAMHAL_LOGEA("Frame received for non-(preview/capture/measure) port. This is yet to be supported");
- goto EXIT;
- }
这里在上面的操作完成之后都会进行下面的方法returnFrame,这个returnFrame同样要好好分析一下
- if ( NO_ERROR != stat )
- {
- CameraBuffer *camera_buffer;
-
- camera_buffer = (CameraBuffer *)pBuffHeader->pAppPrivate;
-
- CAMHAL_LOGDB("sendFrameToSubscribers error: %d", stat);
- returnFrame(camera_buffer, typeOfFrame);
- }
-
- return eError;
-
- EXIT:
-
- CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, stat, eError);
-
- if ( NO_ERROR != stat )
- {
- if ( NULL != mErrorNotifier )
- {
- mErrorNotifier->errorNotify(CAMERA_ERROR_UNKNOWN);
- }
- }
-
- return eError;
- }
首先看一下sendCallbacks方法的实现
- status_t OMXCameraAdapter::sendCallBacks(CameraFrame frame, OMX_IN OMX_BUFFERHEADERTYPE *pBuffHeader, unsigned int mask, OMXCameraPortParameters *port)
- {
- status_t ret = NO_ERROR;
-
- LOG_FUNCTION_NAME;
-
- if ( NULL == port)
- {
- CAMHAL_LOGEA("Invalid portParam");
- return -EINVAL;
- }
-
- if ( NULL == pBuffHeader )
- {
- CAMHAL_LOGEA("Invalid Buffer header");
- return -EINVAL;
- }
-
- Mutex::Autolock lock(mSubscriberLock);
- 首先填充我们将要发送的camerabuffer
- //frame.mFrameType = typeOfFrame;
- frame.mFrameMask = mask;
- frame.mBuffer = (CameraBuffer *)pBuffHeader->pAppPrivate;
- frame.mLength = pBuffHeader->nFilledLen;
- frame.mAlignment = port->mStride;
- frame.mOffset = pBuffHeader->nOffset;
- frame.mWidth = port->mWidth;
- frame.mHeight = port->mHeight;
- frame.mYuv[0] = NULL;
- frame.mYuv[1] = NULL;
-
- if ( onlyOnce && mRecording )
- {
- mTimeSourceDelta = (pBuffHeader->nTimeStamp * 1000) - systemTime(SYSTEM_TIME_MONOTONIC);
- onlyOnce = false;
- }
-
- frame.mTimestamp = (pBuffHeader->nTimeStamp * 1000) - mTimeSourceDelta;
-
- ret = setInitFrameRefCount(frame.mBuffer, mask);
-
- if (ret != NO_ERROR) {
- CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret);
- } else {
- ret = sendFrameToSubscribers(&frame);
- }
-
- CAMHAL_LOGVB("B 0x%x T %llu", frame.mBuffer, pBuffHeader->nTimeStamp);
-
- LOG_FUNCTION_NAME_EXIT;
-
- return ret;
- }
上面两个方法的实现也是很重点的部分,先看setInitFrameRefCount的实现
- int BaseCameraAdapter::setInitFrameRefCount(CameraBuffer * buf, unsigned int mask)
- {
- int ret = NO_ERROR;
- unsigned int lmask;
-
- LOG_FUNCTION_NAME;
-
- if (buf == NULL)
- {
- return -EINVAL;
- }
-
- for( lmask = 1; lmask < CameraFrame::ALL_FRAMES; lmask <<= 1){
- if( lmask & mask ){
- switch( lmask ){
-
- case CameraFrame::IMAGE_FRAME:
- {
- 把buffer添加到mImageSubscribers的最后的key上
- setFrameRefCount(buf, CameraFrame::IMAGE_FRAME, (int) mImageSubscribers.size());
- }
- break;
- case CameraFrame::RAW_FRAME:
- {
- setFrameRefCount(buf, CameraFrame::RAW_FRAME, mRawSubscribers.size());
- }
- break;
- case CameraFrame::PREVIEW_FRAME_SYNC:
- {
- setFrameRefCount(buf, CameraFrame::PREVIEW_FRAME_SYNC, mFrameSubscribers.size());
- }
- break;
- case CameraFrame::SNAPSHOT_FRAME:
- {
- setFrameRefCount(buf, CameraFrame::SNAPSHOT_FRAME, mSnapshotSubscribers.size());
- }
- break;
- case CameraFrame::VIDEO_FRAME_SYNC:
- {
- setFrameRefCount(buf,CameraFrame::VIDEO_FRAME_SYNC, mVideoSubscribers.size());
- }
- break;
- case CameraFrame::FRAME_DATA_SYNC:
- {
- setFrameRefCount(buf, CameraFrame::FRAME_DATA_SYNC, mFrameDataSubscribers.size());
- }
- break;
- case CameraFrame::REPROCESS_INPUT_FRAME:
- {
- setFrameRefCount(buf,CameraFrame::REPROCESS_INPUT_FRAME, mVideoInSubscribers.size());
- }
- break;
- default:
- CAMHAL_LOGEB("FRAMETYPE NOT SUPPORTED 0x%x", lmask);
- break;
- }//SWITCH
- mask &= ~lmask;
- }//IF
- }//FOR
- LOG_FUNCTION_NAME_EXIT;
- return ret;
- }
- void BaseCameraAdapter::setFrameRefCount(CameraBuffer * frameBuf, CameraFrame::FrameType frameType, int refCount)
- {
-
- LOG_FUNCTION_NAME;
-
- switch ( frameType )
- {
- case CameraFrame::IMAGE_FRAME:
- case CameraFrame::RAW_FRAME:
- {
- Mutex::Autolock lock(mCaptureBufferLock);
- mCaptureBuffersAvailable.replaceValueFor(frameBuf, refCount);
- }
- break;
- case CameraFrame::SNAPSHOT_FRAME:
- {
- Mutex::Autolock lock(mSnapshotBufferLock);
- mSnapshotBuffersAvailable.replaceValueFor( ( unsigned int ) frameBuf, refCount);
- }
- break;
- case CameraFrame::PREVIEW_FRAME_SYNC:
- {
- Mutex::Autolock lock(mPreviewBufferLock);
- 更新framebuf在mPreviewBuffersAviailable中的key
- mPreviewBuffersAvailable.replaceValueFor(frameBuf, refCount);
- }
- break;
- case CameraFrame::FRAME_DATA_SYNC:
- {
- Mutex::Autolock lock(mPreviewDataBufferLock);
- mPreviewDataBuffersAvailable.replaceValueFor(frameBuf, refCount);
- }
- break;
- case CameraFrame::VIDEO_FRAME_SYNC:
- {
- Mutex::Autolock lock(mVideoBufferLock);
- mVideoBuffersAvailable.replaceValueFor(frameBuf, refCount);
- }
- break;
- case CameraFrame::REPROCESS_INPUT_FRAME: {
- Mutex::Autolock lock(mVideoInBufferLock);
- mVideoInBuffersAvailable.replaceValueFor(frameBuf, refCount);
- }
- break;
- default:
- break;
- };
-
- LOG_FUNCTION_NAME_EXIT;
-
- }
然后我们再看看sendFrameToSubscribers这个很重要的方法,最终调用以下方法
- status_t BaseCameraAdapter::__sendFrameToSubscribers(CameraFrame* frame,
- KeyedVector<int, frame_callback> *subscribers,
- CameraFrame::FrameType frameType)
- {
- size_t refCount = 0;
- status_t ret = NO_ERROR;
- frame_callback callback = NULL;
-
- frame->mFrameType = frameType;
-
- if ( (frameType == CameraFrame::PREVIEW_FRAME_SYNC) ||
- (frameType == CameraFrame::VIDEO_FRAME_SYNC) ||
- (frameType == CameraFrame::SNAPSHOT_FRAME) ){
- if (mFrameQueue.size() > 0){
- CameraFrame *lframe = (CameraFrame *)mFrameQueue.valueFor(frame->mBuffer);
- frame->mYuv[0] = lframe->mYuv[0];
- frame->mYuv[1] = frame->mYuv[0] + (frame->mLength + frame->mOffset)*2/3;
- }
- else{
- CAMHAL_LOGDA("Empty Frame Queue");
- return -EINVAL;
- }
- }
-
- if (NULL != subscribers) {
- refCount = getFrameRefCount(frame->mBuffer, frameType);
-
- if (refCount == 0) {
- CAMHAL_LOGDA("Invalid ref count of 0");
- return -EINVAL;
- }
-
- if (refCount > subscribers->size()) {
- CAMHAL_LOGEB("Invalid ref count for frame type: 0x%x", frameType);
- return -EINVAL;
- }
-
- CAMHAL_LOGVB("Type of Frame: 0x%x address: 0x%x refCount start %d",
- frame->mFrameType,
- ( uint32_t ) frame->mBuffer,
- refCount);
-
- for ( unsigned int i = 0 ; i < refCount; i++ ) {
- frame->mCookie = ( void * ) subscribers->keyAt(i);
- callback = (frame_callback) subscribers->valueAt(i);
-
- if (!callback) {
- CAMHAL_LOGEB("callback not set for frame type: 0x%x", frameType);
- return -EINVAL;
- }
-
- callback(frame);
- }
- } else {
- CAMHAL_LOGEA("Subscribers is null??");
- return -EINVAL;
- }
-
- return ret;
- }
通过获得callback最终实现数据网上层回调
待续。。。。。