Android Camera OMXCameraAdapter.cpp初始化分析
这几天一直在研究android 的omx机制,我针对的android是4.0.3,主要是TI 的4430,4460的omx方式实现,这里还是简单的说一下为什么要研究这个文件
之前有一篇文章已经比较详细的说过了OMAP4系列芯片了,这里这个OMXCameraAdapter其实就是omap4 A9端的omx client,通过这个client与ducati端(也就是omap4的DSP端)的omx进行通信,可以把ducati端的这个omx简单理解为omx servicer,之前已经说了很多了andriod camera了,但是之前文章都是针对V4LCameraAdapter这个适配器进行的,这是大家都比较了解的,就是app通过V4L2这种方式与kernel camera driver实现交互,进而实现camera 的使用,包括数据回调等过程,但是这里的OMX方法完全颠覆了我之前的想法,开始在研究OMX的时候自己就是调用这个死胡同里了,一直在试图在OMX的实现中找到他到底是在哪么访问设备的,本来我是以后最终他还是通过V4L2这种方式,事实证明我错了,OMX是一种完全不同于V4L2 的访问camera的策略,他通过A9端的omx client和DSP端的omx通信,而且最终访问camera的方法是在DSP端omx server接到到A9端的omx client配置后按照指定方法实现camera 的控制的,这里ducati端到底是怎么处理的我暂时没有关注,暂时精力有限啊!
以上是我自己的见解,也许是完全错误的,待确认,这里只是总结我的分析过程
经过上面我的概述,自然A9端的这个OMXCameraAdapter对于我来说就是一切了,分析它是必经之路啊
现在就开始:
首先要知道在哪里实例化了这个类的对象,这个在之前已经说到过了,这个不在说明,重点看看他的initialize方法都干了些甚么?
- /*--------------------Camera Adapter Class STARTS here-----------------------------*/
-
- status_t OMXCameraAdapter::initialize(CameraProperties::Properties* caps)
- {
- LOG_FUNCTION_NAME;
-
- char value[PROPERTY_VALUE_MAX];
- const char *mountOrientationString = NULL;
-
- property_get("debug.camera.showfps", value, "0");
- mDebugFps = atoi(value);
- property_get("debug.camera.framecounts", value, "0");
- mDebugFcs = atoi(value);
-
- #ifdef CAMERAHAL_OMX_PROFILING
-
- property_get("debug.camera.profile", value, "0");
- mDebugProfile = atoi(value);
-
- #endif
-
- TIMM_OSAL_ERRORTYPE osalError = OMX_ErrorNone;
- OMX_ERRORTYPE eError = OMX_ErrorNone;
- status_t ret = NO_ERROR;
-
- mLocalVersionParam.s.nVersionMajor = 0x1;
- mLocalVersionParam.s.nVersionMinor = 0x1;
- mLocalVersionParam.s.nRevision = 0x0 ;
- mLocalVersionParam.s.nStep = 0x0;
-
- mPending3Asettings = 0;//E3AsettingsAll;
- mPendingCaptureSettings = 0;
- mPendingPreviewSettings = 0;
-
- if ( 0 != mInitSem.Count() )
- {
- CAMHAL_LOGEB("Error mInitSem semaphore count %d", mInitSem.Count());
- LOG_FUNCTION_NAME_EXIT;
- return NO_INIT;
- }
-
- ///Update the preview and image capture port indexes
- mCameraAdapterParameters.mPrevPortIndex = OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW;
- // temp changed in order to build OMX_CAMERA_PORT_VIDEO_OUT_IMAGE;
- mCameraAdapterParameters.mImagePortIndex = OMX_CAMERA_PORT_IMAGE_OUT_IMAGE;
- mCameraAdapterParameters.mMeasurementPortIndex = OMX_CAMERA_PORT_VIDEO_OUT_MEASUREMENT;
- //currently not supported use preview port instead
- mCameraAdapterParameters.mVideoPortIndex = OMX_CAMERA_PORT_VIDEO_OUT_VIDEO;
- mCameraAdapterParameters.mVideoInPortIndex = OMX_CAMERA_PORT_VIDEO_IN_VIDEO;
- // 1.OMX_Init
- eError = OMX_Init();
- if (eError != OMX_ErrorNone) {
- CAMHAL_LOGEB("OMX_Init() failed, error: 0x%x", eError);
- return ErrorUtils::omxToAndroidError(eError);
- }
- mOmxInitialized = true;
-
- // 2.Initialize the callback handles
- OMX_CALLBACKTYPE callbacks;
- callbacks.EventHandler = android::OMXCameraAdapterEventHandler;
- callbacks.EmptyBufferDone = android::OMXCameraAdapterEmptyBufferDone;
- callbacks.FillBufferDone = android::OMXCameraAdapterFillBufferDone;
-
- // 3.Get the handle to the OMX Component
- eError = OMXCameraAdapter::OMXCameraGetHandle(&mCameraAdapterParameters.mHandleComp, this, callbacks);
- if(eError != OMX_ErrorNone) {
- CAMHAL_LOGEB("OMX_GetHandle -0x%x", eError);
- }
- GOTO_EXIT_IF((eError != OMX_ErrorNone), eError);
-
- mComponentState = OMX_StateLoaded;
-
- CAMHAL_LOGVB("OMX_GetHandle -0x%x sensor_index = %lu", eError, mSensorIndex);
- initDccFileDataSave(&mCameraAdapterParameters.mHandleComp, mCameraAdapterParameters.mPrevPortIndex);
-
- eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, OMX_CommandPortDisable, OMX_ALL,NULL);
-
- if(eError != OMX_ErrorNone) {
- CAMHAL_LOGEB("OMX_SendCommand(OMX_CommandPortDisable) -0x%x", eError);
- }
- GOTO_EXIT_IF((eError != OMX_ErrorNone), eError);
-
- // 4.Register for port enable event
- ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp,
- OMX_EventCmdComplete,
- OMX_CommandPortEnable,
- mCameraAdapterParameters.mPrevPortIndex,
- mInitSem);
- if(ret != NO_ERROR) {
- CAMHAL_LOGEB("Error in registering for event %d", ret);
- goto EXIT;
- }
-
- // 5.Enable PREVIEW Port
- eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp,
- OMX_CommandPortEnable,
- mCameraAdapterParameters.mPrevPortIndex,
- NULL);
- if(eError != OMX_ErrorNone) {
- CAMHAL_LOGEB("OMX_SendCommand(OMX_CommandPortEnable) -0x%x", eError);
- }
- GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError);
-
- // 6.Wait for the port enable event to occur
- ret = mInitSem.WaitTimeout(OMX_CMD_TIMEOUT);
- if ( NO_ERROR == ret ) {
- CAMHAL_LOGDA("-Port enable event arrived");
- } else {
- ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp,
- OMX_EventCmdComplete,
- OMX_CommandPortEnable,
- mCameraAdapterParameters.mPrevPortIndex,
- NULL);
- CAMHAL_LOGEA("Timeout for enabling preview port expired!");
- goto EXIT;
- }
-
- // 7.Select the sensor
- OMX_CONFIG_SENSORSELECTTYPE sensorSelect;
- OMX_INIT_STRUCT_PTR (&sensorSelect, OMX_CONFIG_SENSORSELECTTYPE);
- sensorSelect.eSensor = (OMX_SENSORSELECT) mSensorIndex;
- eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, ( OMX_INDEXTYPE ) OMX_TI_IndexConfigSensorSelect, &sensorSelect);
- if ( OMX_ErrorNone != eError ) {
- CAMHAL_LOGEB("Error while selecting the sensor index as %d - 0x%x", mSensorIndex, eError);
- return BAD_VALUE;
- } else {
- CAMHAL_LOGDB("Sensor %d selected successfully", mSensorIndex);
- }
-
- #ifdef CAMERAHAL_DEBUG
-
- printComponentVersion(mCameraAdapterParameters.mHandleComp);
-
- #endif
- // 8.初始化默认参数
- mBracketingEnabled = false;
- mZoomBracketingEnabled = false;
- mBracketingBuffersQueuedCount = 0;
- mBracketingRange = 1;
- mLastBracetingBufferIdx = 0;
- mBracketingBuffersQueued = NULL;
- mOMXStateSwitch = false;
- mBracketingSet = false;
- #ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING
- mRawCapture = false;
- mYuvCapture = false;
- #endif
-
- mCaptureSignalled = false;
- mCaptureConfigured = false;
- mReprocConfigured = false;
- mRecording = false;
- mWaitingForSnapshot = false;
- mPictureFormatFromClient = NULL;
-
- mCapabilitiesOpMode = MODE_MAX;
- mCapMode = INITIAL_MODE;
- mIPP = IPP_NULL;
- mVstabEnabled = false;
- mVnfEnabled = false;
- mBurstFrames = 1;
- mBurstFramesAccum = 0;
- mCapturedFrames = 0;
- mFlushShotConfigQueue = false;
- mPictureQuality = 100;
- mCurrentZoomIdx = 0;
- mTargetZoomIdx = 0;
- mPreviousZoomIndx = 0;
- mReturnZoomStatus = false;
- mZoomInc = 1;
- mZoomParameterIdx = 0;
- mExposureBracketingValidEntries = 0;
- mZoomBracketingValidEntries = 0;
- mSensorOverclock = false;
- mAutoConv = OMX_TI_AutoConvergenceModeMax;
- mManualConv = 0;
- mDeviceOrientation = 0;
- mCapabilities = caps;
- mZoomUpdating = false;
- mZoomUpdate = false;
- mGBCE = BRIGHTNESS_OFF;
- mGLBCE = BRIGHTNESS_OFF;
- mParameters3A.ExposureLock = OMX_FALSE;
- mParameters3A.WhiteBalanceLock = OMX_FALSE;
-
- mEXIFData.mGPSData.mAltitudeValid = false;
- mEXIFData.mGPSData.mDatestampValid = false;
- mEXIFData.mGPSData.mLatValid = false;
- mEXIFData.mGPSData.mLongValid = false;
- mEXIFData.mGPSData.mMapDatumValid = false;
- mEXIFData.mGPSData.mProcMethodValid = false;
- mEXIFData.mGPSData.mVersionIdValid = false;
- mEXIFData.mGPSData.mTimeStampValid = false;
- mEXIFData.mModelValid = false;
- mEXIFData.mMakeValid = false;
-
- //update the mDeviceOrientation with the sensor mount orientation.
- //So that the face detect will work before onOrientationEvent()
- //get triggered.
- CAMHAL_ASSERT(mCapabilities);
- mountOrientationString = mCapabilities->get(CameraProperties::ORIENTATION_INDEX);
- CAMHAL_ASSERT(mountOrientationString);
- mDeviceOrientation = atoi(mountOrientationString);
-
- if (mSensorIndex != 2) {
- mCapabilities->setMode(MODE_HIGH_SPEED);
- }
-
- if (mCapabilities->get(CameraProperties::SUPPORTED_ZOOM_STAGES) != NULL) {
- mMaxZoomSupported = mCapabilities->getInt(CameraProperties::SUPPORTED_ZOOM_STAGES) + 1;
- } else {
- mMaxZoomSupported = 1;
- }
-
- // 9.initialize command handling thread
- if(mCommandHandler.get() == NULL)
- mCommandHandler = new CommandHandler(this);
-
- if ( NULL == mCommandHandler.get() )
- {
- CAMHAL_LOGEA("Couldn't create command handler");
- return NO_MEMORY;
- }
-
- ret = mCommandHandler->run("CallbackThread", PRIORITY_URGENT_DISPLAY);
- if ( ret != NO_ERROR )
- {
- if( ret == INVALID_OPERATION){
- CAMHAL_LOGDA("command handler thread already runnning!!");
- ret = NO_ERROR;
- } else {
- CAMHAL_LOGEA("Couldn't run command handlerthread");
- return ret;
- }
- }
-
- // 10.initialize omx callback handling thread
- if(mOMXCallbackHandler.get() == NULL)
- mOMXCallbackHandler = new OMXCallbackHandler(this);
-
- if ( NULL == mOMXCallbackHandler.get() )
- {
- CAMHAL_LOGEA("Couldn't create omx callback handler");
- return NO_MEMORY;
- }
-
- ret = mOMXCallbackHandler->run("OMXCallbackThread", PRIORITY_URGENT_DISPLAY);
- if ( ret != NO_ERROR )
- {
- if( ret == INVALID_OPERATION){
- CAMHAL_LOGDA("omx callback handler thread already runnning!!");
- ret = NO_ERROR;
- } else {
- CAMHAL_LOGEA("Couldn't run omx callback handler thread");
- return ret;
- }
- }
-
- OMX_INIT_STRUCT_PTR (&mRegionPriority, OMX_TI_CONFIG_3A_REGION_PRIORITY);
- OMX_INIT_STRUCT_PTR (&mFacePriority, OMX_TI_CONFIG_3A_FACE_PRIORITY);
- mRegionPriority.nPortIndex = OMX_ALL;
- mFacePriority.nPortIndex = OMX_ALL;
-
- //Setting this flag will that the first setParameter call will apply all 3A settings
- //and will not conditionally apply based on current values.
- mFirstTimeInit = true;
-
- //Flag to avoid calling setVFramerate() before OMX_SetParameter(OMX_IndexParamPortDefinition)
- //Ducati will return an error otherwise.
- mSetFormatDone = false;
-
- memset(mExposureBracketingValues, 0, EXP_BRACKET_RANGE*sizeof(int));
- memset(mZoomBracketingValues, 0, ZOOM_BRACKET_RANGE*sizeof(int));
- mMeasurementEnabled = false;
- mFaceDetectionRunning = false;
- mFaceDetectionPaused = false;
- mFDSwitchAlgoPriority = false;
-
- memset(&mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex], 0, sizeof(OMXCameraPortParameters));
- memset(&mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex], 0, sizeof(OMXCameraPortParameters));
- memset(&mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoPortIndex], 0, sizeof(OMXCameraPortParameters));
- memset(&mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoInPortIndex], 0, sizeof(OMXCameraPortParameters));
-
- // 11.initialize 3A defaults
- mParameters3A.Effect = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_EFFECT, EffLUT);
- mParameters3A.FlashMode = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_FLASH_MODE, FlashLUT);
- mParameters3A.SceneMode = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_SCENE_MODE, SceneLUT);
- mParameters3A.EVCompensation = atoi(OMXCameraAdapter::DEFAULT_EV_COMPENSATION);
- mParameters3A.Focus = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_FOCUS_MODE, FocusLUT);
- mParameters3A.ISO = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_ISO_MODE, IsoLUT);
- mParameters3A.Flicker = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_ANTIBANDING, FlickerLUT);
- mParameters3A.Brightness = atoi(OMXCameraAdapter::DEFAULT_BRIGHTNESS);
- mParameters3A.Saturation = atoi(OMXCameraAdapter::DEFAULT_SATURATION) - SATURATION_OFFSET;
- mParameters3A.Sharpness = atoi(OMXCameraAdapter::DEFAULT_SHARPNESS) - SHARPNESS_OFFSET;
- mParameters3A.Contrast = atoi(OMXCameraAdapter::DEFAULT_CONTRAST) - CONTRAST_OFFSET;
- mParameters3A.WhiteBallance = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_WB, WBalLUT);
- mParameters3A.Exposure = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_EXPOSURE_MODE, ExpLUT);
- mParameters3A.ExposureLock = OMX_FALSE;
- mParameters3A.FocusLock = OMX_FALSE;
- mParameters3A.WhiteBalanceLock = OMX_FALSE;
-
- mParameters3A.ManualExposure = 0;
- mParameters3A.ManualExposureRight = 0;
- mParameters3A.ManualGain = 0;
- mParameters3A.ManualGainRight = 0;
-
- mParameters3A.AlgoFixedGamma = OMX_TRUE;
- mParameters3A.AlgoNSF1 = OMX_TRUE;
- mParameters3A.AlgoNSF2 = OMX_TRUE;
- mParameters3A.AlgoSharpening = OMX_TRUE;
- mParameters3A.AlgoThreeLinColorMap = OMX_TRUE;
- mParameters3A.AlgoGIC = OMX_TRUE;
-
- LOG_FUNCTION_NAME_EXIT;
- return ErrorUtils::omxToAndroidError(eError);
-
- EXIT:
-
- CAMHAL_LOGDB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError);
- performCleanupAfterError();
- LOG_FUNCTION_NAME_EXIT;
- return ErrorUtils::omxToAndroidError(eError);
- }
就是这里了,下面对上面的方法按步骤一一做分析
1.OMX_Init
从字面上就可以知道,要使用OMX这个方式,那就要为使用它做准备啊,初始化,但我们还是严谨点,说一说吧,
- /** The OMX_Init method is used to initialize the OMX core. It shall be the
- first call made into OMX and it should only be executed one time without
- an interviening OMX_Deinit call.
-
- The core should return from this call within 20 msec.
- @return OMX_ERRORTYPE
- If the command successfully executes, the return code will be
- OMX_ErrorNone. Otherwise the appropriate OMX error will be returned.
- @ingroup core
- */
- OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Init(void);
2.Initialize the callback handles
这里初始化callback handle,那么上面初始化了三个handle,这三个handle具体都实现什么用途呢?
当然一下不是我说的,是TI为方便大家理解,在andriod底层加入了很多很全的注释,一起看看吧
- typedef struct OMX_CALLBACKTYPE
- {
- /** The EventHandler method is used to notify the application when an
- event of interest occurs. Events are defined in the OMX_EVENTTYPE
- enumeration. Please see that enumeration for details of what will
- be returned for each type of event. Callbacks should not return
- an error to the component, so if an error occurs, the application
- shall handle it internally. This is a blocking call.
- The application should return from this call within 5 msec to avoid
- blocking the component for an excessively long period of time.
- @param hComponent
- handle of the component to access. This is the component
- handle returned by the call to the GetHandle function.
- @param pAppData
- pointer to an application defined value that was provided in the
- pAppData parameter to the OMX_GetHandle method for the component.
- This application defined value is provided so that the application
- can have a component specific context when receiving the callback.
- @param eEvent
- Event that the component wants to notify the application about.
- @param nData1
- nData will be the OMX_ERRORTYPE for an error event and will be
- an OMX_COMMANDTYPE for a command complete event and OMX_INDEXTYPE for a OMX_PortSettingsChanged event.
- @param nData2
- nData2 will hold further information related to the event. Can be OMX_STATETYPE for
- a OMX_CommandStateSet command or port index for a OMX_PortSettingsChanged event.
- Default value is 0 if not used. )
- @param pEventData
- Pointer to additional event-specific data (see spec for meaning).
- */
- OMX_ERRORTYPE (*EventHandler)(
- OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_EVENTTYPE eEvent,
- OMX_IN OMX_U32 nData1,
- OMX_IN OMX_U32 nData2,
- OMX_IN OMX_PTR pEventData);
- /** The EmptyBufferDone method is used to return emptied buffers from an
- input port back to the application for reuse. This is a blocking call
- so the application should not attempt to refill the buffers during this
- call, but should queue them and refill them in another thread. There
- is no error return, so the application shall handle any errors generated
- internally.
-
- The application should return from this call within 5 msec.
-
- @param hComponent
- handle of the component to access. This is the component
- handle returned by the call to the GetHandle function.
- @param pAppData
- pointer to an application defined value that was provided in the
- pAppData parameter to the OMX_GetHandle method for the component.
- This application defined value is provided so that the application
- can have a component specific context when receiving the callback.
- @param pBuffer
- pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer
- or AllocateBuffer indicating the buffer that was emptied.
- @ingroup buf
- */
- OMX_ERRORTYPE (*EmptyBufferDone)(
- OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
- /** The FillBufferDone method is used to return filled buffers from an
- output port back to the application for emptying and then reuse.
- This is a blocking call so the application should not attempt to
- empty the buffers during this call, but should queue the buffers
- and empty them in another thread. There is no error return, so
- the application shall handle any errors generated internally. The
- application shall also update the buffer header to indicate the
- number of bytes placed into the buffer.
- The application should return from this call within 5 msec.
-
- @param hComponent
- handle of the component to access. This is the component
- handle returned by the call to the GetHandle function.
- @param pAppData
- pointer to an application defined value that was provided in the
- pAppData parameter to the OMX_GetHandle method for the component.
- This application defined value is provided so that the application
- can have a component specific context when receiving the callback.
- @param pBuffer
- pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer
- or AllocateBuffer indicating the buffer that was filled.
- @ingroup buf
- */
- OMX_ERRORTYPE (*FillBufferDone)(
- OMX_OUT OMX_HANDLETYPE hComponent,
- OMX_OUT OMX_PTR pAppData,
- OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
- } OMX_CALLBACKTYPE;
EmptyBufferDone 方法用来实现从组件的输入端口获取到空的缓冲区返回给应用层使得可以重新被使用,这是一个阻塞型的调用,这个调用期间你不可以使用fillThisBuffer方法去fill这个缓冲区,你应该在另外一个线程中进行这个工作,这个回调方法不会提示error信息,所以需要用户端自己去分辨,并处理这些信息,保存错误信息;
EventHandler方法用来通知应用层一些应用层可能感兴趣的一些事件,事件分很多类型,已经用枚举方式定义在
OMX_EVENTTYPE中,
这个回调方法同样不会提示error信息,所以需要用户端自己去分辨,并处理这些信息,保存错误信息;
FillBufferDone方法用来实现从组件的输出端口获取到经过解码等很多操作的buffer,并且放回给应用层,应用层获取使用后,在通过emptyThisBuffer方法清空buffer再次利用,
这个回调方法同样不会提示error信息,所以需要用户端自己去分辨,并处理这些信息,保存错误信息,这里应用层还有一件很重要的事情要做,应用程序要更新缓冲区header的位置,新数据加入,header后移;
3.Get the handle to the OMX Component
- OMX_ERRORTYPE OMXCameraAdapter::OMXCameraGetHandle(OMX_HANDLETYPE *handle, OMX_PTR pAppData,
- const OMX_CALLBACKTYPE & callbacks)
- {
- OMX_ERRORTYPE eError = OMX_ErrorUndefined;
- for ( int i = 0; i < 5; ++i ) {
- if ( i > 0 ) {
- // sleep for 100 ms before next attempt
- usleep(100000);
- }
- // setup key parameters to send to Ducati during init
- OMX_CALLBACKTYPE oCallbacks = callbacks;
- // get handle
- eError = OMX_GetHandle(handle, (OMX_STRING)"OMX.TI.DUCATI1.VIDEO.CAMERA", pAppData, &oCallbacks);
- if ( eError == OMX_ErrorNone ) {
- return OMX_ErrorNone;
- }
- CAMHAL_LOGEB("OMX_GetHandle() failed, error: 0x%x", eError);
- }
- *handle = 0;
- return eError;
- }
这个传入上面初始化的callbacks,是为了获取到handle,这个handle对应一个组件,每个组件同样拥有自己的callbacks方法,所以这里不同的组件公用callbacks,看看这个OMX_GetHandle吧,因为有注释,可以更好理解啊,嘿嘿
- /** The OMX_GetHandle method will locate the component specified by the
- component name given, load that component into memory and then invoke
- the component's methods to create an instance of the component.
-
- The core should return from this call within 20 msec.
-
- @param [out] pHandle
- pointer to an OMX_HANDLETYPE pointer to be filled in by this method.
- @param [in] cComponentName
- pointer to a null terminated string with the component name. The
- names of the components are strings less than 127 bytes in length
- plus the trailing null for a maximum size of 128 bytes. An example
- of a valid component name is "OMX.TI.AUDIO.DSP.MIXER\0". Names are
- assigned by the vendor, but shall start with "OMX." and then have
- the Vendor designation next.
- @param [in] pAppData
- pointer to an application defined value that will be returned
- during callbacks so that the application can identify the source
- of the callback.
- @param [in] pCallBacks
- pointer to a OMX_CALLBACKTYPE structure that will be passed to the
- component to initialize it with.
- @return OMX_ERRORTYPE
- If the command successfully executes, the return code will be
- OMX_ErrorNone. Otherwise the appropriate OMX error will be returned.
- @ingroup core
- */
- OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(
- OMX_OUT OMX_HANDLETYPE* pHandle,
- OMX_IN OMX_STRING cComponentName,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_CALLBACKTYPE* pCallBacks);
这个方法会通过name获取到想要的组件,并且加载组件的内存,请求组件中定义的方法实例化组件
4.设置组件最初状态为OMX_StateLoaded状态,并disable所以command port
mComponentState
=
OMX_StateLoaded
;
eError
=
OMX_SendCommand
(
mCameraAdapterParameters
.
mHandleComp
,
OMX_CommandPortDisable
,
OMX_ALL
,
NULL
)
;
这里必须重点说说OMX_SendCommand这个方法
- /** Send a command to the component. This call is a non-blocking call.
- The component should check the parameters and then queue the command
- to the component thread to be executed. The component thread shall
- send the EventHandler() callback at the conclusion of the command.
- This macro will go directly from the application to the component (via
- a core macro). The component will return from this call within 5 msec.
-
- When the command is "OMX_CommandStateSet" the component will queue a
- state transition to the new state idenfied in nParam.
-
- When the command is "OMX_CommandFlush", to flush a port's buffer queues,
- the command will force the component to return all buffers NOT CURRENTLY
- BEING PROCESSED to the application, in the order in which the buffers
- were received.
-
- When the command is "OMX_CommandPortDisable" or
- "OMX_CommandPortEnable", the component's port (given by the value of
- nParam) will be stopped or restarted.
-
- When the command "OMX_CommandMarkBuffer" is used to mark a buffer, the
- pCmdData will point to a OMX_MARKTYPE structure containing the component
- handle of the component to examine the buffer chain for the mark. nParam1
- contains the index of the port on which the buffer mark is applied.
- Specification text for more details.
-
- @param [in] hComponent
- handle of component to execute the command
- @param [in] Cmd
- Command for the component to execute
- @param [in] nParam
- Parameter for the command to be executed. When Cmd has the value
- OMX_CommandStateSet, value is a member of OMX_STATETYPE. When Cmd has
- the value OMX_CommandFlush, value of nParam indicates which port(s)
- to flush. -1 is used to flush all ports a single port index will
- only flush that port. When Cmd has the value "OMX_CommandPortDisable"
- or "OMX_CommandPortEnable", the component's port is given by
- the value of nParam. When Cmd has the value "OMX_CommandMarkBuffer"
- the components pot is given by the value of nParam.
- @param [in] pCmdData
- Parameter pointing to the OMX_MARKTYPE structure when Cmd has the value
- "OMX_CommandMarkBuffer".
- @return OMX_ERRORTYPE
- If the command successfully executes, the return code will be
- OMX_ErrorNone. Otherwise the appropriate OMX error will be returned.
- @ingroup comp
- */
- #define OMX_SendCommand( \
- hComponent, \
- Cmd, \
- nParam, \
- pCmdData) \
- ((OMX_COMPONENTTYPE*)hComponent)->SendCommand( \
- hComponent, \
- Cmd, \
- nParam, \
- pCmdData) /* Macro End */
通过这个方法给组件发送一个command,组件接收到command后会检查传入的参数并将这个command压入队列,待组件的处理线程处理,处理完成后会通过上面初始化的EventHandler通知应用层处理结果,最多不会超出5min,超过则超时报错,具体的command type上面注释中已经说明,简单说明一下吧
在上面参数中分为以下几种情况:
1.
Cmd 为
OMX_CommandStateSet
这种command用于组件状态之间的切换
这个第三个参数nParam代表参数类型是
OMX_STATETYPE,是组件的状态参数
2.Cmd 为
OMX_CommandFlush
这种command用于刷新组件缓冲区,不管是否缓冲区经过处理,缓冲区数据都会按照接收的顺序交给应用层
这个第三个参数nParam代表参数类型是组件的port,第四个参数pCmdData都为NULL
3.Cmd 为
OMX_CommandPortDisable或者
OMX_CommandPortEnable
这个情况下,第三个参数nParam代表要设置disable或enable的组件的port,OMX_ALL表示所有的组件,第四个参数pCmdData都为NULL
4.Cmd 为
OMX_CommandMarkBuffer
这种command用于标记组件缓冲区
这个第三个参数nParam代表参数类型是组件的port,第四个参数的类型是OMX_MARKTYPE 结构
5.Register for port enable event
调用方式如下:
ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp,//这个参数指定组件的handle
OMX_EventCmdComplete,//这个参数是EventType
OMX_CommandPortEnable,//nData1
mCameraAdapterParameters.mPrevPortIndex,
//nData2
mInitSem);//这个参数是信号量,保证同步
- status_t OMXCameraAdapter::RegisterForEvent(OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_EVENTTYPE eEvent,
- OMX_IN OMX_U32 nData1,
- OMX_IN OMX_U32 nData2,
- OMX_IN Semaphore &semaphore)
- {
- status_t ret = NO_ERROR;
- ssize_t res;
- Mutex::Autolock lock(mEventLock);
- LOG_FUNCTION_NAME;
- TIUTILS::Message * msg = ( struct TIUTILS::Message * ) malloc(sizeof(struct TIUTILS::Message));
- if ( NULL != msg )
- {
- msg->command = ( unsigned int ) eEvent;
- msg->arg1 = ( void * ) nData1;
- msg->arg2 = ( void * ) nData2;
- msg->arg3 = ( void * ) &semaphore;
- msg->arg4 = ( void * ) hComponent;
- res = mEventSignalQ.add(msg);
- if ( NO_MEMORY == res )
- {
- CAMHAL_LOGEA("No ressources for inserting OMX events");
- free(msg);
- ret = -ENOMEM;
- }
- }
- LOG_FUNCTION_NAME_EXIT;
- return ret;
- }
这里将传入的数据打包到message结构中,并且添加到mEventSignalQ队列中,这里先不说为什么,之后再说明
6.Enable PREVIEW Port
eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp,
OMX_CommandPortEnable,
mCameraAdapterParameters.mPrevPortIndex,
NULL);
前面disable了所有组件,这里保证了只有previewPort enable了
7.Wait for the port enable event to occur
调用过程如下:
ret = mInitSem.WaitTimeout(OMX_CMD_TIMEOUT);
这里我自己的感觉还是比较难于理解,因为自己在看这部分一开始也没有吃透
所以这里是我眼中的重点,重点啊
首先上面第6步 sendcommand to 组件,那么组件就该给应用层以反馈,叫做callback也可以,这里是通过我们上面初始化的OMXCameraAdapterEventHandler这个callback来应答应用层的,我们就看看这个方法的具体实现方法
- /* Application callback Functions */
- /*========================================================*/
- /* @ fn SampleTest_EventHandler :: Application callback */
- /*========================================================*/
- OMX_ERRORTYPE OMXCameraAdapter::OMXCameraAdapterEventHandler(OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_EVENTTYPE eEvent,
- OMX_IN OMX_U32 nData1,
- OMX_IN OMX_U32 nData2,
- OMX_IN OMX_PTR pEventData)
- {
- LOG_FUNCTION_NAME;
- OMX_ERRORTYPE eError = OMX_ErrorNone;
- CAMHAL_LOGDB("+OMX_Event %x, %d %d", eEvent, (int)nData1, (int)nData2);
- switch (eEvent) {
- case OMX_EventCmdComplete:
- CAMHAL_LOGDB("+OMX_EventCmdComplete %d %d", (int)nData1, (int)nData2);
- if (OMX_CommandStateSet == nData1) {
- mCameraAdapterParameters.mState = (OMX_STATETYPE) nData2;
- } else if (OMX_CommandFlush == nData1) {
- CAMHAL_LOGDB("OMX_CommandFlush received for port %d", (int)nData2);
- } else if (OMX_CommandPortDisable == nData1) {
- CAMHAL_LOGDB("OMX_CommandPortDisable received for port %d", (int)nData2);
- } else if (OMX_CommandPortEnable == nData1) {//我们发送的是OMX_CommandPortEnable命令,所以这了nData1就是command type
- CAMHAL_LOGDB("OMX_CommandPortEnable received for port %d", (int)nData2);
- } else if (OMX_CommandMarkBuffer == nData1) {
- ///This is not used currently
- }
- CAMHAL_LOGDA("-OMX_EventCmdComplete");
- break;
- case OMX_EventIndexSettingChanged:
- CAMHAL_LOGDB("OMX_EventIndexSettingChanged event received data1 0x%x, data2 0x%x",
- ( unsigned int ) nData1, ( unsigned int ) nData2);
- break;
- case OMX_EventError:
- CAMHAL_LOGDB("OMX interface failed to execute OMX command %d", (int)nData1);
- CAMHAL_LOGDA("See OMX_INDEXTYPE for reference");
- if ( NULL != mErrorNotifier && ( ( OMX_U32 ) OMX_ErrorHardware == nData1 ) && mComponentState != OMX_StateInvalid)
- {
- CAMHAL_LOGEA("***Got Fatal Error Notification***\n");
- mComponentState = OMX_StateInvalid;
- /*
- Remove any unhandled events and
- unblock any waiting semaphores
- */
- if ( !mEventSignalQ.isEmpty() )
- {
- for (unsigned int i = 0 ; i < mEventSignalQ.size(); i++ )
- {
- CAMHAL_LOGEB("***Removing %d EVENTS***** \n", mEventSignalQ.size());
- //remove from queue and free msg
- TIUTILS::Message *msg = mEventSignalQ.itemAt(i);
- if ( NULL != msg )
- {
- Semaphore *sem = (Semaphore*) msg->arg3;
- if ( sem )
- {
- sem->Signal();
- }
- free(msg);
- }
- }
- mEventSignalQ.clear();
- }
- ///Report Error to App
- mErrorNotifier->errorNotify(CAMERA_ERROR_FATAL);
- }
- break;
- case OMX_EventMark:
- break;
- case OMX_EventPortSettingsChanged:
- break;
- case OMX_EventBufferFlag:
- break;
- case OMX_EventResourcesAcquired:
- break;
- case OMX_EventComponentResumed:
- break;
- case OMX_EventDynamicResourcesAvailable:
- break;
- case OMX_EventPortFormatDetected:
- break;
- default:
- break;
- }
- ///Signal to the thread(s) waiting that the event has occured
- SignalEvent(hComponent, eEvent, nData1, nData2, pEventData);//这里才是重点
- LOG_FUNCTION_NAME_EXIT;
- return eError;
- EXIT:
- CAMHAL_LOGEB("Exiting function %s because of eError=%x", __FUNCTION__, eError);
- LOG_FUNCTION_NAME_EXIT;
- return eError;
- }
我们接着看看
SignalEvent的实现
- OMX_ERRORTYPE OMXCameraAdapter::SignalEvent(OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_EVENTTYPE eEvent,
- OMX_IN OMX_U32 nData1,
- OMX_IN OMX_U32 nData2,
- OMX_IN OMX_PTR pEventData)
- {
- Mutex::Autolock lock(mEventLock);
- TIUTILS::Message *msg;
- bool eventSignalled = false;
- LOG_FUNCTION_NAME;
- if ( !mEventSignalQ.isEmpty() )
- {
- CAMHAL_LOGDA("Event queue not empty");
- for ( unsigned int i = 0 ; i < mEventSignalQ.size() ; i++ )
- {
- msg = mEventSignalQ.itemAt(i);
- if ( NULL != msg )
- {
- if( ( msg->command != 0 || msg->command == ( unsigned int ) ( eEvent ) )
- && ( !msg->arg1 || ( OMX_U32 ) msg->arg1 == nData1 )
- && ( !msg->arg2 || ( OMX_U32 ) msg->arg2 == nData2 )
- && msg->arg3)
- {
- Semaphore *sem = (Semaphore*) msg->arg3;
- CAMHAL_LOGDA("Event matched, signalling sem");
- mEventSignalQ.removeAt(i);
- //Signal the semaphore provided
- sem->Signal();
- free(msg);
- break;
- }
- }
- }
- }
- else
- {
- CAMHAL_LOGDA("Event queue empty!!!");
- }
- // Special handling for any unregistered events
- if (!eventSignalled) {
- // Handling for focus callback
- if ((nData2 == OMX_IndexConfigCommonFocusStatus) &&
- (eEvent == (OMX_EVENTTYPE) OMX_EventIndexSettingChanged)) {
- TIUTILS::Message msg;
- msg.command = OMXCallbackHandler::CAMERA_FOCUS_STATUS;
- msg.arg1 = NULL;
- msg.arg2 = NULL;
- mOMXCallbackHandler->put(&msg);
- }
- }
- LOG_FUNCTION_NAME_EXIT;
- return OMX_ErrorNone;
- }
这里我们只关注上面的实现,至于下面handle focus callback这里咱不做说明,以后可能会再次碰到
我们看看上面的语句到底做了什么,检测到
mEventSignalQ这个消息队列中有消息,而这里在第6步中不是刚刚往这个消息队列中添加了一个消息嘛!看来他们有点暧昧,接着看,进行了遍历查找的操作,那么找的到底是什么呢?上面的判断条件很明确,不同的一点马虎,看看这个消息队列中是是否有和我从组件发来的消息一致的消息,找到了,那就说明消息处理完了,组件成功应答给应用层了,那么就得到了那个信号量,并且发送一个信号给wait方法,wait方法接到信号立即返回,否则一直等待直到超时,超时返回非零值,否则返回零,程序中如果wait超时,调用RemoveEvent方法
- OMX_ERRORTYPE OMXCameraAdapter::RemoveEvent(OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_EVENTTYPE eEvent,
- OMX_IN OMX_U32 nData1,
- OMX_IN OMX_U32 nData2,
- OMX_IN OMX_PTR pEventData)
- {
- Mutex::Autolock lock(mEventLock);
- TIUTILS::Message *msg;
- LOG_FUNCTION_NAME;
- if ( !mEventSignalQ.isEmpty() )
- {
- CAMHAL_LOGDA("Event queue not empty");
- for ( unsigned int i = 0 ; i < mEventSignalQ.size() ; i++ )
- {
- msg = mEventSignalQ.itemAt(i);
- if ( NULL != msg )
- {
- if( ( msg->command != 0 || msg->command == ( unsigned int ) ( eEvent ) )
- && ( !msg->arg1 || ( OMX_U32 ) msg->arg1 == nData1 )
- && ( !msg->arg2 || ( OMX_U32 ) msg->arg2 == nData2 )
- && msg->arg3)
- {
- Semaphore *sem = (Semaphore*) msg->arg3;
- CAMHAL_LOGDA("Event matched, signalling sem");
- mEventSignalQ.removeAt(i);
- free(msg);
- break;
- }
- }
- }
- }
- else
- {
- CAMHAL_LOGEA("Event queue empty!!!");
- }
- LOG_FUNCTION_NAME_EXIT;
- return OMX_ErrorNone;
- }
这个方法检查
mEventSignalQ如果中有成员消息,那么就清除掉
mEventSignalQ其中的所有消息,这个是错误处理,以后还是会接着使用
mEventSignalQ这个消息队列的,这里已经说的很清楚了,为什么在OMX_SendCommand之前要RegisterForEvent,就是为了要判断组件有没有按照我发送给他的命令干活,处理完后给我应答了,我就认为他乖乖的按照我的要求做了事情,这里那叫一个重要,因为后面还会有很多这个机制的使用
这里有一个地方我还是要提及一下,那就是组件回馈的enent类型,直接贴在这里
- /** @ingroup comp */
- typedef enum OMX_EVENTTYPE
- {
- OMX_EventCmdComplete, /**< component has sucessfully completed a command */
- OMX_EventError, /**< component has detected an error condition */
- OMX_EventMark, /**< component has detected a buffer mark */
- OMX_EventPortSettingsChanged, /**< component is reported a port settings change */
- OMX_EventBufferFlag, /**< component has detected an EOS */
- OMX_EventResourcesAcquired, /**< component has been granted resources and is
- automatically starting the state change from
- OMX_StateWaitForResources to OMX_StateIdle. */
- OMX_EventComponentResumed, /**< Component resumed due to reacquisition of resources */
- OMX_EventDynamicResourcesAvailable, /**< Component has acquired previously unavailable dynamic resources */
- OMX_EventPortFormatDetected, /**< Component has detected a supported format. */
- OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
- OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
- OMX_EventMax = 0x7FFFFFFF
- } OMX_EVENTTYPE;
8.Select the sensor
这里我们首先看看OMX_CONFIG_SENSORSELECTTYPE这个结构
定义在以下目录:hardware\ti\omap4xxx\domx\omx_core\inc\OMX_TI_IVCommon.h
- /*
- * Sensor Select
- */
- typedef struct OMX_CONFIG_SENSORSELECTTYPE {
- OMX_U32 nSize; /**< Size of the structure in bytes */
- OMX_VERSIONTYPE nVersion; /**< OMX specification version info */
- OMX_U32 nPortIndex; /**< Port that this struct applies to */
- OMX_SENSORSELECT eSensor; /**< sensor select */
- } OMX_CONFIG_SENSORSELECTTYPE;
接着来看下面这个方法的实现
OMX_INIT_STRUCT_PTR (&sensorSelect, OMX_CONFIG_SENSORSELECTTYPE);
- #define OMX_INIT_STRUCT_PTR(_s_, _name_) \
- memset((_s_), 0x0, sizeof(_name_)); \
- (_s_)->nSize = sizeof(_name_); \
- (_s_)->nVersion.s.nVersionMajor = 0x1; \
- (_s_)->nVersion.s.nVersionMinor = 0x1; \
- (_s_)->nVersion.s.nRevision = 0x0; \
- (_s_)->nVersion.s.nStep = 0x0
这个方法只是对sensorSelect这个结构进行初始化和填充而已,传入
OMX_CONFIG_SENSORSELECTTYPE结构体只是为了获取他的大小,挺大财小用不是吗??嘿嘿
最后调用OMX_SetConfig()这个方法
- /** The OMX_SetConfig macro will send one of the configuration
- structures to a component. Each structure shall be sent one at a time,
- each in a separate invocation of the macro. This macro can be invoked
- anytime after the component has been loaded. The application shall
- allocate the correct structure and shall fill in the structure size
- and version information (as well as the actual data) before invoking
- this macro. The application is free to dispose of this structure after
- the call as the component is required to copy any data it shall retain.
- This is a blocking call.
-
- The component should return from this call within 5 msec.
-
- @param [in] hComponent
- Handle of the component to be accessed. This is the component
- handle returned by the call to the OMX_GetHandle function.
- @param [in] nConfigIndex
- Index of the structure to be sent. This value is from the
- OMX_INDEXTYPE enumeration above.
- @param [in] pComponentConfigStructure
- pointer to application allocated structure to be used for
- initialization by the component.
- @return OMX_ERRORTYPE
- If the command successfully executes, the return code will be
- OMX_ErrorNone. Otherwise the appropriate OMX error will be returned.
- @ingroup comp
- */
- #define OMX_SetConfig( \
- hComponent, \
- nConfigIndex, \
- pComponentConfigStructure) \
- ((OMX_COMPONENTTYPE*)hComponent)->SetConfig( \
- hComponent, \
- nConfigIndex, \
- pComponentConfigStructure) /* Macro End */
9.参数初始化
其中最重要的是initialize方法引入的参数传递给了
mCapabilities
mCapabilities = caps;
并且通过mCapabilities->get()方法获得相应的参数初始化
10.initialize command handling thread
这里只是创建了一个CommandHandler线程,并且启动了这个线程,我们重点看看这个线程都干了些甚么
- bool OMXCameraAdapter::CommandHandler::Handler()
- {
- TIUTILS::Message msg;
- volatile int forever = 1;
- status_t stat;
- ErrorNotifier *errorNotify = NULL;
- LOG_FUNCTION_NAME;
- while ( forever )
- {
- stat = NO_ERROR;
- CAMHAL_LOGDA("Handler: waiting for messsage...");
- TIUTILS::MessageQueue::waitForMsg(&mCommandMsgQ, NULL, NULL, -1);
- {
- Mutex::Autolock lock(mLock);
- mCommandMsgQ.get(&msg);
- }
- CAMHAL_LOGDB("msg.command = %d", msg.command);
- switch ( msg.command ) {
- case CommandHandler::CAMERA_START_IMAGE_CAPTURE:
- {
- OMXCameraAdapter::CachedCaptureParameters* cap_params =
- static_cast<OMXCameraAdapter::CachedCaptureParameters*>(msg.arg2);
- stat = mCameraAdapter->startImageCapture(false, cap_params);
- delete cap_params;
- break;
- }
- case CommandHandler::CAMERA_PERFORM_AUTOFOCUS:
- {
- stat = mCameraAdapter->doAutoFocus();
- break;
- }
- case CommandHandler::COMMAND_EXIT:
- {
- CAMHAL_LOGDA("Exiting command handler");
- forever = 0;
- break;
- }
- case CommandHandler::CAMERA_SWITCH_TO_EXECUTING:
- {
- stat = mCameraAdapter->doSwitchToExecuting();
- break;
- }
- case CommandHandler::CAMERA_START_REPROCESS:
- {
- OMXCameraAdapter::CachedCaptureParameters* cap_params =
- static_cast<OMXCameraAdapter::CachedCaptureParameters*>(msg.arg2);
- stat = mCameraAdapter->startReprocess();
- stat = mCameraAdapter->startImageCapture(false, cap_params);
- delete cap_params;
- break;
- }
- }
- }
- LOG_FUNCTION_NAME_EXIT;
- return false;
- }
11.initialize omx callback handling thread
这里和上面很类似,创建一个OMXCallbackHandler线程,并启动这个线程,同样看看这个线程都干了些甚么
- 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;
- }
12.initialize 3A defaults
这里暂不做说明,都是对很多参数的基本初始化
到这里为止,OMXCameraAdapter的初始化就结束了
待续。。。。。