导读:
本文聚焦于如何编程实现一个真正的组件,主题思想是介绍一个组件在编程sjo的模块组成以及如何编写,也会介绍下组件的初始化过程、组件之间的绑定过程、数据同步过程。在下一篇文章里面会对video、audio、clock等组件进行介绍。
注意:该文章主要介绍组件内部代码的实现,其余部分简略介绍,实际上完整的组件还包括有组件类型的管理,组件绑定模块,组件句柄的分配,然后才是下面的各个组件的实现,但是OpenMAX的标准化使得我们编写组件内部代码的时候不必过于关心更上层的组件管理代码的实现,只需要知道应该按照什么样的规则去编写组件内部代码即可。
原型:typedef OMX_ERRORTYPE (* OMX_COMPONENTINITTYPE)(OMX_IN OMX_HANDLETYPE hComponent);
。所有的组件都是通过该函数来进行初始化创建的,该函数等于说是整个组件内部世界的入口,该函数的参数则是整个组件的句柄,由IL Client分配空间并传入给该函数进行填充与初始化。该函数的参数是一个void *
类型的指针,意味着组件的编写者可以自行定义组件句柄的结构体类型,但通常情况下,组件句柄类型都是一个OMX_COMPONENTTYPE
类型的结构体,其原型如下:
/** The OMX_HANDLETYPE structure defines the component handle. The component
* handle is used to access all of the component's public methods and also
* contains pointers to the component's private data area. The component
* handle is initialized by the OMX core (with help from the component)
* during the process of loading the component. After the component is
* successfully loaded, the application can safely access any of the
* component's public functions (although some may return an error because
* the state is inappropriate for the access).
*/
typedef struct OMX_COMPONENTTYPE
{
/** The size of this structure, in bytes. It is the responsibility
of the allocator of this structure to fill in this value. Since
this structure is allocated by the GetHandle function, this
function will fill in this value. */
OMX_U32 nSize;
/** nVersion is the version of the OMX specification that the structure
is built against. It is the responsibility of the creator of this
structure to initialize this value and every user of this structure
should verify that it knows how to use the exact version of
this structure found herein. */
OMX_VERSIONTYPE nVersion;
/** pComponentPrivate is a pointer to the component private data area.
This member is allocated and initialized by the component when the
component is first loaded. The application should not access this
data area. */
OMX_PTR pComponentPrivate;
/** pApplicationPrivate is a pointer that is a parameter to the
OMX_GetHandle method, and contains an application private value
provided by the IL client. This application private data is
returned to the IL Client by OMX in all callbacks */
OMX_PTR pApplicationPrivate;
/** refer to OMX_GetComponentVersion in OMX_core.h or the OMX IL
specification for details on the GetComponentVersion method.
*/
OMX_ERRORTYPE (*GetComponentVersion)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_OUT OMX_STRING pComponentName,
OMX_OUT OMX_VERSIONTYPE* pComponentVersion,
OMX_OUT OMX_VERSIONTYPE* pSpecVersion,
OMX_OUT OMX_UUIDTYPE* pComponentUUID);
/** refer to OMX_SendCommand in OMX_core.h or the OMX IL
specification for details on the SendCommand method.
*/
OMX_ERRORTYPE (*SendCommand)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_COMMANDTYPE Cmd,
OMX_IN OMX_U32 nParam1,
OMX_IN OMX_PTR pCmdData);
/** refer to OMX_GetParameter in OMX_core.h or the OMX IL
specification for details on the GetParameter method.
*/
OMX_ERRORTYPE (*GetParameter)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_INDEXTYPE nParamIndex,
OMX_INOUT OMX_PTR ComponentParameterStructure);
/** refer to OMX_SetParameter in OMX_core.h or the OMX IL
specification for details on the SetParameter method.
*/
OMX_ERRORTYPE (*SetParameter)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_INDEXTYPE nIndex,
OMX_IN OMX_PTR ComponentParameterStructure);
/** refer to OMX_GetConfig in OMX_core.h or the OMX IL
specification for details on the GetConfig method.
*/
OMX_ERRORTYPE (*GetConfig)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_INDEXTYPE nIndex,
OMX_INOUT OMX_PTR pComponentConfigStructure);
/** refer to OMX_SetConfig in OMX_core.h or the OMX IL
specification for details on the SetConfig method.
*/
OMX_ERRORTYPE (*SetConfig)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_INDEXTYPE nIndex,
OMX_IN OMX_PTR pComponentConfigStructure);
/** refer to OMX_GetExtensionIndex in OMX_core.h or the OMX IL
specification for details on the GetExtensionIndex method.
*/
OMX_ERRORTYPE (*GetExtensionIndex)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_STRING cParameterName,
OMX_OUT OMX_INDEXTYPE* pIndexType);
/** refer to OMX_GetState in OMX_core.h or the OMX IL
specification for details on the GetState method.
*/
OMX_ERRORTYPE (*GetState)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_OUT OMX_STATETYPE* pState);
/** The ComponentTunnelRequest method will interact with another OMX
component to determine if tunneling is possible and to setup the
tunneling. The return codes for this method can be used to
determine if tunneling is not possible, or if tunneling is not
supported.
Base profile components (i.e. non-interop) do not support this
method and should return OMX_ErrorNotImplemented
The interop profile component MUST support tunneling to another
interop profile component with a compatible port parameters.
A component may also support proprietary communication.
If proprietary communication is supported the negotiation of
proprietary communication is done outside of OMX in a vendor
specific way. It is only required that the proper result be
returned and the details of how the setup is done is left
to the component implementation.
When this method is invoked when nPort in an output port, the
component will:
1. Populate the pTunnelSetup structure with the output port's
requirements and constraints for the tunnel.
When this method is invoked when nPort in an input port, the
component will:
1. Query the necessary parameters from the output port to
determine if the ports are compatible for tunneling
2. If the ports are compatible, the component should store
the tunnel step provided by the output port
3. Determine which port (either input or output) is the buffer
supplier, and call OMX_SetParameter on the output port to
indicate this selection.
The component will return from this call within 5 msec.
@param [in] hComp
Handle of the component to be accessed. This is the component
handle returned by the call to the OMX_GetHandle method.
@param [in] nPort
nPort is used to select the port on the component to be used
for tunneling.
@param [in] hTunneledComp
Handle of the component to tunnel with. This is the component
handle returned by the call to the OMX_GetHandle method. When
this parameter is 0x0 the component should setup the port for
communication with the application / IL Client.
@param [in] nPortOutput
nPortOutput is used indicate the port the component should
tunnel with.
@param [in] pTunnelSetup
Pointer to the tunnel setup structure. When nPort is an output port
the component should populate the fields of this structure. When
When nPort is an input port the component should review the setup
provided by the component with the output port.
@return OMX_ERRORTYPE
If the command successfully executes, the return code will be
OMX_NoError. Otherwise the appropriate OMX error will be returned.
*/
OMX_ERRORTYPE (*ComponentTunnelRequest)(
OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_U32 nPort,
OMX_IN OMX_HANDLETYPE hTunneledComp,
OMX_IN OMX_U32 nTunneledPort,
OMX_INOUT OMX_TUNNELSETUPTYPE* pTunnelSetup);
/** refer to OMX_UseBuffer in OMX_core.h or the OMX IL
specification for details on the UseBuffer method.
*/
OMX_ERRORTYPE (*UseBuffer)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr,
OMX_IN OMX_U32 nPortIndex,
OMX_IN OMX_PTR pAppPrivate,
OMX_IN OMX_U32 nSizeBytes,
OMX_IN OMX_U8* pBuffer);
/** refer to OMX_AllocateBuffer in OMX_core.h or the OMX IL
specification for details on the AllocateBuffer method.
*/
OMX_ERRORTYPE (*AllocateBuffer)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_INOUT OMX_BUFFERHEADERTYPE** ppBuffer,
OMX_IN OMX_U32 nPortIndex,
OMX_IN OMX_PTR pAppPrivate,
OMX_IN OMX_U32 nSizeBytes);
/** refer to OMX_FreeBuffer in OMX_core.h or the OMX IL
specification for details on the FreeBuffer method.
*/
OMX_ERRORTYPE (*FreeBuffer)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_U32 nPortIndex,
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
/** refer to OMX_EmptyThisBuffer in OMX_core.h or the OMX IL
specification for details on the EmptyThisBuffer method.
*/
OMX_ERRORTYPE (*EmptyThisBuffer)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
/** refer to OMX_FillThisBuffer in OMX_core.h or the OMX IL
specification for details on the FillThisBuffer method.
*/
OMX_ERRORTYPE (*FillThisBuffer)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
/** The SetCallbacks method is used by the core to specify the callback
structure from the application to the component. This is a blocking
call. The component will 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 GetHandle function.
@param [in] pCallbacks
pointer to an OMX_CALLBACKTYPE structure used to provide the
callback information to the component
@param [in] pAppData
pointer to an application defined value. It is anticipated that
the application will pass a pointer to a data structure or a "this
pointer" in this area to allow the callback (in the application)
to determine the context of the call
@return OMX_ERRORTYPE
If the command successfully executes, the return code will be
OMX_NoError. Otherwise the appropriate OMX error will be returned.
*/
OMX_ERRORTYPE (*SetCallbacks)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_CALLBACKTYPE* pCallbacks,
OMX_IN OMX_PTR pAppData);
/** ComponentDeInit method is used to deinitialize the component
providing a means to free any resources allocated at component
initialization. NOTE: After this call the component handle is
not valid for further use.
@param [in] hComponent
Handle of the component to be accessed. This is the component
handle returned by the call to the GetHandle function.
@return OMX_ERRORTYPE
If the command successfully executes, the return code will be
OMX_NoError. Otherwise the appropriate OMX error will be returned.
*/
OMX_ERRORTYPE (*ComponentDeInit)(
OMX_IN OMX_HANDLETYPE hComponent);
} OMX_COMPONENTTYPE;
上面代码保留了所有的注释,以便自行了解各个成员的含义以及整个结构体的作用。组件的初始化就是将组件句柄结构体类型内部的成员全部填充好。接下来就是实现OMX_COMPONENTINITTYPE
类型的组件初始化函数。在该函数里面需要做的事情如下:
OMX_COMPONENTTYPE
内部各种类型的回调函数指针该部分详细介绍每一个组件内部回调函数的内部实现(具体的内部代码实现需要开发者自行实现,这里只讲函数里面大概需要做什么事以及各个函数的功能,照着这个指引就可以快速地去实现代码编写了),下面说的该结构体均是指OMX_COMPONENTTYPE
结构体类型。先来看一张图,这张图说明了在各个状态下每一个回调函数是否可执行:
回调函数对应状态可执行表
GetHandle
(后面会介绍),不过暂时不必关心它的实现,只需要知道该字段由GetHandle
填充,代表该结构体的大小即可,该字段也可以由组件本身去实现。当然,该字段不是必须的,可以选择不使用。Loaded
状态时才被分配并且初始化的,但是通常情况下,在组件初始化函数中就直接将组件的状态初始化为Loaded
,因此该指针指向的类型通常由组件初始化函数来分配并进行填充的。该指针指向组件内部的私有结构体类型,这个私有结构体类型由组件内部自定义,只需要将该指针指向自己定义的结构体实例地址即可,通常包含有组件的各个flag变量、端口定义、buffer管理、组件状态描述等等,这些都用于组件自身的管理与功能实现,IL Client不会去访问。GetHandle
的参数传递给组件,它是IL Client层级的私有数据指针,并且组件所有的回调函数都会将该指针再次返回给IL Client(包含在OMX_COMPONENTTYPE
类型中,作为成员返回)。IL Client可以与组件约定一些公认的变量,以此来在IL Client与组件之间传递某些信息。pComponentName
:不必多说,就是该组件的名称(char *);pComponentVersion
:组件的版本,由组件的厂商提供,完全取决于组件厂商;pSpecVersion
:与上一个不同的是,该版本指的是组件编写时所参考的OpenMAX spec文档的标准版本号,也就是说厂商发布的第一版组件版本(version 0.1)可能对应的spec版本是openmax_il_spec_1_0(version 1.0),这里的区别需要注意下;pComponentUUID
:由组件运行时指定,要求每一个组件的UUID都唯一,用于在全局范围内标定组件(因为同一个类型的组件可能会同时创建多个实例化对象,UUID不同就可以区分开它们)。OMX_ERRORTYPE OMX_ComponentSendCommand(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_COMMANDTYPE Cmd,
OMX_IN OMX_U32 nParam1,
OMX_IN OMX_PTR pCmdData)
{
// Invalid状态下不可发送命令
if (get_comp_state() == OMX_StateInvalid) {
return wrong_state;
} else {
fill_command_instance(&cmd_inst);
put_command_into_cmdlist(&list, &cmd_inst);
do something;
if everyting is done, return SUCCESS;
}
}
最后,一定记得在组件获取命令执行完毕之后返回给IL Client一个事件,如果命令被成功执行,则返回一个OMX_EventCmdComplete
类型的事件,否则就返回OMX_EventError
类型的事件。
nParamIndex
参数指定了需要获取的参数索引,通常是一个枚举类型(OMX_INDEXTYPE
枚举类型,比如OMX_IndexParamVideoInit
),用户可以根据自身的需要在头文件的枚举类型中扩展自己需要的枚举成员。除了OMX_StateInvalid
状态不能执行之外,该函数只需要执行拷贝工作即可。也可以在ComponentParameterStructure
参数里面传入一些信息,比如指定端口号等等,该参数是一个void *类型参数,由nParamIndex
索引号来决定其实际的参数类型,由IL Client与组件共同商定。OMX_StateLoaded
与OMX_StateWaitForResources
状态下可以执行,其余状态均需要返回状态错误的错误码。GetParameter
很像。用于从组件里面获取一个配置,该回调函数在组件被初始化之后的任意时刻都可以被调用,调用者需要提前分配好pComponentConfigStructure
对应的空间并填充大小与版本信息,该回调函数应该是加锁保护的(因为APP与组件会去访问同一个变量,需要互斥)。OMX_INDEXTYPE
类型的枚举,它们的区分并不是很严格,在一些场景下,既可以用Config,也可以用Parameter。OMX_INDEXTYPE
枚举类型),改回调函数是上面四个函数的扩展,用于加入一些厂商自定义的index类型,该函数不是必须的,通常情况下该函数的使用方式如下:/* step1: 根据特定的字符串描述获取与之对应的index */
OMX_GetExtensionIndex(
hFileReaderComp,
"OMX.CompanyXYZ.index.param.filename",
&eIndexParamFilename);
/* step2: 根据上一步获取到的index调用OMX_SetParameter/Config宏定义设置参数或者配置到组件里面 */
OMX_SetParameter(hComp, eIndexParamFilename, &oFileName);
OMX_SendCommand(hComp, OMX_CommandStateSet, OMX_StateIdle, 0);
do {
usleep(5*1000);
OMX_GetState(hComp, &eState);
} while (OMX_StateIdle != eState);
nPort
参数是output类型的组件回调来说,它需要做的工作是填充pTunnelSetup
结构体(该结构体描述了该端口的绑定要求与限制);对于nPort
参数是input类型的组件回调来说,它需要执行下列步骤:
pTunnelSetup
以及output端口的组件实力句柄等存储起来以备使用。pTunnelSetup
参数来进行选择),并根据上一步保存的组件实例句柄调用OMX_SetParameter
来和与该组件端口绑定的组件进行确认。 ComponentTunnelRequest
回调,然后再调用input端口提供者的对应回调。OMX_StateLoaded
状态,并且已经发送了OMX_StateIdle
状态转换请求。OMX_StateWaitForResources
状态,此时资源可用,并且正准备切换到OMX_StateIdle
状态。OMX_StateExecuting
,OMX_StatePause
或者OMX_StateIdle
状态。/* supplier端口分配buffer并将其传递给与之绑定的组件 */
for (i=0;inBufferCount;i++)
{
pPort->pBuffer[i] = malloc(pPort->nBufferSize);
OMX_UseBuffer(pPort->hTunnelComponent,
&pPort->pBufferHdr[i],
pPort->nTunnelPort,
pPort,
pPort->nBufferSize,
pPort->pBuffer[j]);
}
ppBufferHdr
参数返回buffer header信息给调用者,通常情况下,调用者(非绑定情况下就是IL Client,绑定情况下就是buffer提供者组件)需要保存这个buffer header到一个链表里面,以备使用。该函数的调用场景与上一个函数一致。Executing
与Idle
状态下均可接收数据。注意,该函数的主语是output port所在的组件,是该组件让input port所在的组件来Empty自己的buffer,这样理解的话这个回调函数的名字就不奇怪了,如果搞错主语,就会奇怪为什么是EmptyThisBuffer
,而不是GetThisBuffer
。在非绑定状态下就是由app来调用该回调函数,此时主语是app。OMX_CALLBACKTYPE
类型的参数就是回调函数的结构体抽象,回调函数成员包括EventHandler
,EmptyBufferDone
,FillBufferDone
。三个的应用场景分别如下:
EmptyBuffer
的主语,该函数通常用于EmptyThisBuffer
之后,并且在非绑定的条件下由EmptyThisBuffer
回调函数的提供者组件调用,该回调函数的作用类似于FillThisBuffer
,可以理解为前者用于非绑定状态下向app**还回数据,后者用于绑定状态下向buffer传递者组件还回数据。此时组件的内心活动是:我已经把你给我的buffer存起来了,我通知你一声,至于你要不要释放这一帧数据或者再次填充这帧数据就听开发者怎么说啦。(此为前文还回的意思)**EmptyBufferDone
。注意:
1. 这些回调函数有很大一部分是加锁互斥访问的(组件实例结构体代码有说明),这个锁是需要自己去实现的。
2. 所有的函数会注明是阻塞的还是非阻塞的(组件实例结构体代码有说明),非阻塞的会有最大时间消耗要求,注意不要超过这个时间。
3. 各个回调函数会有不同的组件状态约束,注意函数实现的时候加上判断,参照”回调函数的实现”开头图片(图在这里)。
4. buffer的管理是灵活的,可以使用生产者消费者的链表结构实现以及pipe管道模式实现,参照OpenMAX编程-组件,不同的组件还可以灵活选择buffer队列的个数。
基本实现以上各个函数,一个组件的框架代码就成型了,下图说明了buffer传递的几个函数的作用:
buffer传递图
命令控制模块的用途如下:
具体的描述在OpenMAX编程-数据结构的OMX_COMMANDTYPE一节可以看到。
命令的生成可以是由app调用组件的SendCommand
回调函数进行生成,也可以由组件内部自行生成,大部分情况下,需要组件实现一个自己的命令描述结构体用来实例化命令,该结构体可能需要包含命令的枚举、命令的数值、命令的字符内容(如果需要传递字符串的话),组件仅在命令产生时申请一个命令描述结构体(通常包含的成员有:命令索引、命令data),然后将这个命令结构体放入一个队列,可以用链表实现,也可以通过创建一个pipe来实现,组件的内部线程在接收到命令之后立即取出执行。创建pipe的方式在OpenMAX的官方文档里面就有相关的代码实现,这里不再赘述。
SetCallbacks
回调函数将回调函数存放到组件的自定义结构体里面以供调用。回调函数通常在需要组件通知IL Client的时候由组件进行调用(回调函数实体在IL Client里面实现)。GetParameter
,SetParameter
,GetConfig
,SetConfig
四个回调函数来完成,组件内部需要实现相关的参数获取与设置项,这部分是跟组件的具体功能有关的,比如一个编码组件,就需要通过这些回调函数来实现编码器参数的设置与获取(编码帧率、质量、buffer大小等等)。OMX_INDEXTYPE
枚举类型的相应集合处,比如属于音频的就加载audio处,该枚举结构体内部有为每一个集合预留空间,专门用于厂商自定义相关的参数控制index。SendCommand
来进行状态转换命令的发送,Cmd
参数填充OMX_CommandStateSet
枚举成员,nParam1
参数填充需要转换的命令。当然除了IL Client的控制,组件内部也可能会主动给产生一些状态转换的命令,比如在组件发生严重错误的时候,此时组件内部就需要主动转入Invalid状态。组件内部需要实现OMX_CommandStateSet
命令的获取与解析,通常在组件的内部线程里面完成,在接收到该命令之后,组件内部线程需要根据命令指定的状态进行相关的动作。OMX_StateLoaded
:该状态在组件被OMX_GetHandle
调用初始化之后就转入,此时相关的buffer资源还没有被分配,IL Client可以使用OMX_SetParameter
函数回调来进行参数的设定,使用OMX_SetupTunnel
函数进行组件之间的绑定操作,最后控制组件从该状态转入OMX_StateIdle
或者OMX_StateWaitForResources
状态,后者是在组件尝试分配相关的buffer资源并转入OMX_StateIdle
状态失败的时候才转入。OMX_StateIdle
:表明组件所有的资源都已经准备好了,正等待正式运行,该状态下,组件持有buffer,但是不传输也不处理buffer。当组件从OMX_StateExecuting
或者OMX_StatePause
状态转入该状态时需要归还所有处理完毕的buffer到buffer提供者。OMX_StateExecuting
:该状态下,组件持有buffer,传输同时处理buffer。此时组件应该接受其它组件对该组件的OMX_EmptyThisBuffer
与OMX_FillThisBuffer
函数回调,同时在非绑定的情况下使用EmptyBufferDone
与FillBufferDone
来归还Empty以及full buffer。绑定情况下就使用OMX_FillThisBuffer
与OMX_EmptyThisBuffer
来进行buffer的传递。OMX_StatePause
:该状态下,组件持有buffer,不传输也不理buffer,但是组件不必归还buffer到buffer的提供者。为了避免丢失数据,此时组件可以选择将接收到的数据存放到自己的buffer队列里面,但是不进一步传输也不去处理,当然也可以选择不去存放,这跟组件的具体类型与功能有关系。OMX_StateWaitForResources
:顾名思义,在该状态下,组件正在等待资源被分配并变得可用。通常情况下该状态由组件自己主动转入,原因前面说过,是因为资源分配失败导致。OMX_StateInvalid
:该状态是在组件发生不可修复的错误时转入,此时组件需要产生一个事件,类型为OMX_ErrorEvent
,值为OMX_ErrorInvalidState
,最后转入OMX_StateInvalid
状态,当IL Client接收到该消息的时候就需要调用OMX_FreeHandle
来释放所有组件持有的资源。 组件的状态转换
组件内部线程主要用于数据处理、命令处理、数据传输。它的基本逻辑是这样的:
组件内部线程逻辑
至于每个组件、每种类型的组件的内部线程都是不一样的,因为不同组件的功能不同,有的可能会有多个内部线程,有的可能会有多个buffer管理等等不一而足。基本原则是,以自己组件的功能出发,由上而下去设计自己的组件的内部线程逻辑。
组件的初始化由IL Client调用OMX_GetHandle
函数回调来完成,该函数根据传入的组件名来找寻对应的组件,然后调用组件的初始化回调函数实例化一个组件句柄并返回给IL Client。该函数的原型如下:
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);
可以看到该函数有一个输出类型的参数,三个输入类型的参数:
OMX_GetHandle
回调函数分配空间,然后传递给typedef OMX_ERRORTYPE (* OMX_COMPONENTINITTYPE)(OMX_IN OMX_HANDLETYPE hComponent);
的函数实例进行初始化(不同的组件都有自己的OMX_COMPONENTINITTYPE
类型的初始化函数实体)。组件初始化完毕之后,该参数就指向一个初始化好之后的组件实例了,此时可供IL Client进行使用。OMX_COMPONENTINITTYPE
类型的初始化函数实体。而该参数就是指定了组件的名字,根据名字可以在整个数据里面找到组件的初始化函数实体,调用之,初始化。注意:OMX_GetHandle
回调函数实体需要IL Client实现。OMX_FreeHandle
函数则是做与前者相反的事情。
组件的绑定操作由OMX_SetupTunnel
回调函数来完成(该函数实体需要IL Client完成),区别于组件内部的ComponentTunnelRequest
回调方法,该函数内部需要实现分别两次调用需要绑定的两个组件实例的ComponentTunnelRequest
回调方法,只有在OMX_StateLoaded
状态下才可以实现组件之间的绑定操作。通常情况下,组件只在需要被销毁的时候才需要进行相互之间的解绑,但是此时不需要进行显式的解绑操作,因为绑定的过程中没有分配任何额外的资源,所以直接销毁组件即可,无需关注解绑。如果既不想销毁组件,又想解绑组件,则可以添加一个解绑的函数,函数中通过SetConfig调用直接清除掉组件内部的绑定标志位即可,也可以在OMX_SetupTunnel
函数当中添加一个选择解绑与绑定的参数,具体可灵活实现。
组件的绑定过程
如图,需要将组件A的端口A1与组件B的端口B0进行绑定,整个过程的步骤如下所示:
1.ComponentTunnelRequest(A,1,B,0,*pTunnelSetup)
调用传入A1与B0端口号以及A、B组件实例句柄,组件A返回pTunnelSetup
,该参数表明了绑定标志位与buffer提供者。
2.ComponentTunnelRequest(B,0,A,1,*pTunnelSetup)
调用传入B0与A1端口号以及B、A组件实例句柄,在组件B的该函数回调内又会去调用组件A的getParameter
获取相关参数,并调用组件A的SetParameter(A, OMX_IndexParamCompBufferSupplier, supplierStructure)
设置组件A的buffer supplier。组件B也返回一个pTunnelSetup
。
3.判断返回值是否正确,如不正确就对组件A解绑ComponentTunnelRequest(A, 1, NULL, 0, NULL)
并返回错误。