您的位置:首页 > 移动开发 > Android开发

Android Camera OMXCameraAdapter.cpp初始化分析

2013-04-22 22:56 666 查看
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_S***ING

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的初始化就结束了

待续。。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: