1. OpenMax IL控制API
OpenMax IL层的API允许IL client控制Audio,Video,image领域的多媒体组件。除这三个领域的组件以外的称谓其他组件,可以提供了额外的功能,比如音视频同步。一般而言,IL API的用户是多媒体框架。在本文档中,IL API的用户称为IL client。
OpenMax IL API定义在一系列的头文件中,名字如下:
● OMX_Types.h: OpenMax IL使用到的数据类型
● OMX_Core.h: OpenMax IL 核心API
● OMX_Component.h: OpenMax组件API
● OMX_Audio.h: OpenMax Audio领域的数据结构
● OMX_IVCommon.h: image和Video共用的OpenMax数据结构
● OMX_Video.h: Video使用的数据结构
● OMX_Image.h: 图像领域使用的数据结构
● OMX_Other.h: 其他方面的数据结构
● OMX_Index.h: OpenMax定义的数据结构的索引
本节描述OpenMAX core 和 OpenMAX 组件如何被配置。
首先介绍OpenMax的数据结构。然后描述OpenMax core的函数。组件实现的方法在1.3小节讨论。最后,1.4小节展示了一些有意义的操作的时序图,包括组件初始化,正常数据流程,数据隧道话的建立,数据隧道化中数据的流程。这些时序图旨在动态的展示IL client,IL core,IL 组件之间的交互。
当描述函数的时候,以下的规范用于函数的参数:
● <param_name> [in] 指定一个输入参数,这个参数是参数调用者设置,然后函数实现者读取
● <param_name> [out] 指定一个输出参数,参数实现者设置,然后传递给函数调用者。当函数调用返回,函数调用者可以读取参数新的值,这个参数以引用的形式传递
● <param_name> [inout] 指定一个输入输出参数。函数调用者设置,函数实现者可以修改这个参数的值。
在OpenMax的头文件中以空宏的形式定义了这三种参数的分类,分别为: OMX_IN, OMX_OUT和OMX_INOUT 。
1.1 OpenMax的数据类型
1.1.1 枚举
OMX_Core.h中定义了32位整数的枚举值:
● OMX_ERRORTYPE :OpenMax IL API的返回值
● OMX_COMMANDTYPE :ILclient可以发送给OpenMax组件的命令
● OMX_EVENTTYPE :OpenMax组件可能产生的事件,通过callback传递给IL client
● OMX_BUFFERSUPPLIERTYPE :隧道话端口作为buffer提供者
● OMX_STATETYPE 1.1.1.2小节描述
下图展示了OMX_Core.h中定义的枚举值:
时候的属性
1.1.1.1 OMX_COMMANDTYPE
下表列出了IL client可能发送给IL组件的命令。由于命令是非阻塞的方式发送,所以当IL组件执行完这些命令之后,将会通过callback传递一个完成命令的事件给IL client。
名字 | 描述 |
OMX_CommandStateSet | 改变组件的状态 |
OMX_CommandFlush | 刷新组件一个端口上的buffer队列 |
OMX_CommandPortDisable | 禁用组件的一个端口 |
OMX_CommandPortEnable | 启用组件的一个端口 |
OMX_CommandMarkBuffer | 标记buffer,当其他的组件处理完这个buffer的时候会发送一个事件通知 |
下表描述了各个命令的参数:
命令code | nParam | pCmdData |
OMX_CommandStateSet | OMX_STATETYPE:要转换的状态 | NULL |
OMX_CommandFlush | OMX_U32:目标端口号 | NULL |
OMX_CommandPortDisable | OMX_U32:目标端口号 | NULL |
OMX_CommandPortEnable | OMX_U32:目标端口号 | NULL |
OMX_CommandMarkBuffer | OMX_U32:目标端口号 | OMX_MARKTYPE*标记数据和目标组件 |
1.1.1.2 OMX_STATETYPE
下图说明了当IL client调用 OMX_SendCommand(OMX_StateSet, <state>)之后的状态变化图,参数参数作为新的状态。
椭圆框内的状态不是由IL client发送命令触发的,而是组件内部事件导致的结果。
这一部分描述组件的状态。IL client通过OMX_SendCommand发送 OMX_CommandStateSet命令,让组件改变状态。
下表列出了组件的状态:
名称 | 描述 | 资源分配 | buffer位置 |
OMX_StateInvalid | 组件被破坏或者遇到了一个不能复归的错误 | Unknown | Unknown |
OMX_StateLoaded | 组件已经被加载,但是还没有分配资源 | No | Not available |
OMX_StateIdle | 组件已经分配好了资源,但是还没有开始传送buffer或者处理数据 | Yes | Supplier only |
OMX_StateExecuting | 组件正在传送buffer,并且在处理数据 | Yes | Supplier or non-supplier |
OMX_StatePause | 组件的数据处理已经暂停,但是可能从它暂停的点复归 | Yes | Supplier or non-supplier |
OMX_StateWaitForResources | 组件正在等待资源变为可用 | Yes | Not available |
1..1.1.2.1 OMX_StateLoaded
在组件通过OMX_GetHandle调用被创建,但是还没有分配资源,组件处于 OMX_StateLoaded 状态。在这种状况下IL client可以通过 OMX_SetParameter修改组件的参数,通过 OMX_SetupTunnel在组件端口之间建立隧道化,或者改变组件的状态到 OMX_StateIdle或者 OMX_StateWaitForResources。
IL client可能会选择将组件的状态从OMX_StateLoaded改变为 OMX_StateWaitForResources,比如,组件没有成功的请求到它所需要的所有资源,当它试图转换到OMX_StateIdle状态的时候。
1.1.1.2.1.1 OMX_StateLoaded to OMX_StateIdle
如果IL client要求组件从OMX_StateLoaded转变为 OMX_StateIdle,在转变完成之前,组件必须获得它所需要的所有资源,包括buffer。进一步说,在转变完成之前,buffer的提供者(一般而言是IL client)在没有隧道话的情况下,必须确保非buffer提供者具有所有它需要的buffer。对于链接到IL client上的端口,IL client‘自身可能会分配所有的buffer,然后通过在端口上调用 OMX_UseBuffer函数,将这些buffer传递给端口。或者它可以通过调用 OMX_AllocateBuffer,直接让端口自己分配buffer。当一个端口是隧道化的,buffer提供者的端口要么自己分配buffer,要么复用组件内其他端口的buffer,当端口被实现为buffer分享模式。一个buffer提供者的端口通过OMX_UseBuffer将buffer传递给非buffer提供者端口。
一个端口所需要的buffer数目指定在它的端口定义中(见OMX_IndexParamPortDefinition)。默认情况是最小的buffer数目,这个值可以被buffer提供者在调用OMX_UseBuffer或者 OMX_AllocateBuffer之前通过调用OMX_SetParameter函数修改。
1..1.1.2.2 OMX_StateIdle
在 OMX_StateIdle状态下,组件已经准备好被使用,这意味着所有必要的资源都已经正确的分配。然而,此时buffer提供者占据着所有的buffer,没有发生buffer交换或者数据处理。因此如果是从OMX_StateExecuting或者 OMX_StatePause转变为OMX_StateIdle状态,组件应该将它处理的buffer返回给对应的buffer提供者。IL client可以将组件从这个状态转变为任意的状态,除了 OMX_StateInvalid和OMX_StateWaitForResources
。
1..1.1.2.2.1 OMX_StateIdle to OMX_StateLoaded
当从OMX_StateIdle状态变为 OMX_StateLoaded,buffer提供者端口必须在非buffer提供者的端口上调用OMX_FreeBuffer,以释放驻留在非buffer提供者端口上的buffer。如果是buffer提供者分配的buffer,那么它必须在调用OMX_FreeBuffer之前,释放掉这些buffer。如果是非buffer提供者分配的这些buffer,那么它必须在接受到 OMX_FreeBuffer 时候,释放这些buffer。此外,一个非buffer提供者必须在接收OMX_FreeBuffer时候,释放掉它的buffer头。当所有的buffer已经从组件移除,状态的变化完成。
1..1.1.2.2.2 OMX_StateIdle to OMX_StateExecuting
如果IL client要求组件由 OMX_StateIdle进入 OMX_StateExecuting,组件将会开始传送和处理数据。对于和IL client通信的端口,IL client会通过OMX_EmptyThisBuffer和OMX_FillThisBuffer函数调用启动buffer传送。在隧道化端口之间,任意一个输入端口,同时也是一个buffer提供者的端口,应该通过调用 OMX_FillThisBuffer将空buffer传递到输出端口。
1..1.1.2.3 OMX_StateExecuting
在这种状态下,组件正在传送和处理数据。在输入端口组件接收 OMX_EmptyThisBuffer,在输出端口组件接收OMX_FillThisBuffer。任何和IL client通信的组件应该通过回调 EmptyBufferDone 和 FillBufferDone 将空buffer或者装满数据的buffer返回给IL client。任何隧道化的端口在与之隧道化的端口上应该调用OMX_FillThisBuffer 或者 OMX_EmptyThisBuffe以返回一个空的buffer或者装满数据的buffer。IL
client可以命令一个组件从 OMX_StateExecuting状态转变到OMX_StateIdle s 或者 OMX_StatePaused 状态。
1..1.1.2.3.1 OMX_StateExecuting to OMX_StateIdle
当IL client要求组件从 OMX_StateExecuting状态变化为 OMX_StateIdle状态,在完成状态转换之前,组件会返回所有的buffer给它的buffer提供者,或者回收所有属于它内部buffer提供者端口的buffer。对于和IL client通信的端口,如果是输入端口,会通过OMX_EmptyBufferDone返回buffer给IL client,如果是输出端口,会通过OMX_FillBufferDone返回buffer给IL client。对于一个非buffer提供者端口,如果与之隧道化的是一个输入端口,通过调用OMX_EmptyThisBuffer返回buffer,如果与之隧道化的是一个输出端口,通过调用OMX_FillThisBuffer返回buffer。同时,任何一个buffer提供者的隧道话端口,应该等待所有的buffer从与之隧道化的端口返回。
1.1.1.2.4 OMX_StatePause
在这种状态下,组件不会传送或者处理数据,但是buffer没有必要返回给buffer提供者。
1..1.1.2.5 OMX_StateWaitForResources
在这种状态下,组件等待必要的资源变为可用。这个状态和资源管理者有关系。假设在平台上存在一个或者多个与特定硬件相关的资源管理器用于管理可用的资源。组件和资源管理器之间的交流超出了本文档的范围。
如果组件从OMX_StateLoaded 转变为 OMX_StateIdle失败,并非buffer不满足,而是其他的资源不可用,IL client可以将组件的状态变为OMX_StateWaitForResources,如果IL client想在组件的资源变为可用的时候得到通知。IL client也可以命令组件放弃等待资源而从OMX_StateWaitForResources变为 OMX_StateLoaded状态。
1.1.1.2.5.1 OMX_StateWaitForResources to OMX_StateIdle
当组件发起状态变化从OMX_StateWaitForResources到 OMX_StateIdle,它应该通过 OMX_EventResourcesAcquired事件通知IL client。当IL client接收到 OMX_EventResourcesAcquired事件,它应该采取从OMX_StateLoaded 到OMX_StateIdle转变一样的操作:调用 OMX_UseBuffer 或者OMX_AllocateBuffer。同样的组件的状态转换无法完成,直到它需要的资源包括buffer都得到满足,转换才会完成。
1..1.1.2.6 OMX_StateInvalid
在这种状态下,组件内部状态被破坏或者遇到了不可复归的错误。当检测到这些条件,组件将自己的状态变化为OMX_StateInvalid ,然后通过OMX_ErrorEvent
事件通知IL client。当IL client接收到这个事件,它应该释放组件的资源,最后调用 OMX_FreeHandle释放组件的句柄。
当组件处于OMX_StateInvalid状态时候,任何的函数调用都会返回 OMX_ErrorStateInvalid,除了OMX_GetState,OMX_FreeBuffer, OMX_ComponentDeinit。IL client也可以通过显示的调用OMX_SendCommand来让组件的状态变为 OMX_StateInvalid。组件可以从任何状态变迁为OMX_StateInvalid 。
1.1.1.3 OMX_ERRORTYPE
OMX_ERRORTYPE枚举值,定义了OpenMax IL API标准的错误返回值。这些错误值包含了大多数的错误case。尽管如此,只要厂商遵循下面的规则,它依然可以添加自己额外的错误信息:
● 厂商的错误消息应该位于 0x90000000 到0x9000FFFF之间
● 厂商的错误消息应该在组件的头文件中定义
1.1.1.4 OMX_EVENTTYPE
下表列出了OpenMax组件可能产生的事件类型。
名称 | 描述 |
OMX_EventCmdComplete | 组件执行完一个命令 |
OMX_EventError | 组件检测到一个错误 |
OMX_EventMark | 一个标记的buffer到达了目标组件。当一个组件接收到一个buffer,它应该比较自己的指针和buffer中包含的pMarkTargetComponent的值,如果值相等,组件在处理完buffer之后将会发送一个包含pMarkData为参数的事件给IL client |
OMX_EventPortSettingsChanged | 组件改变了端口的设置 |
OMX_EventBufferFlag | 组件检测到流的结束 |
OMX_EventResourcesAcquired | 组件获得了资源,正在从OMX_StateWaitForResources转换为OMX_StateIdle state |
1.1.1.5 OMX_BUFFERSUPPLIERTYPE
这个枚举指定了隧道化端口哪一个是buffer的提供者
名称 | 值 | 描述 |
OMX_BufferSupplyUnspecified | 0x0 | 不确定buffer提供者 |
OMX_BufferSupplyInput | 输入端口提供buffer | |
OMX_BufferSupplyOutput | 输出端口提供buffer |
1.1.2 结构体
这一部分描述 OpenMAX core中定义的数据结构体。每一个OpenMax数据结构体的最开始两个域代表了结构体的大小和版本 OMX_VERSIONTYPE(定义在 1.1.2.4)。分配 OpenMAX结构体的实体负责填充这两个域。
1.1.2.1 OMX_COMPONENTREGISTERTYPE
此结构体用于静态链接组件到核心,核心可以选择使用这个结构体加载组件然后运行它的初始化函数。
typedef struct OMX_COMPONENTREGISTERTYPE { const char * pName; OMX_COMPONENTINITTYPE pInitialize; } OMX_COMPONENTREGISTERTYPE;
1.1.2.2 OMX_COMPONENTINITTYPE
OMX_COMPONENTINITTYPE定义了组件初始化的函数指针,这个函数指针表示组件初始化的入口点。
typedef OMX_ERRORTYPE (* OMX_COMPONENTINITTYPE)(OMX_IN OMX_HANDLETYPE hComponent);
1.1.2.2.1 pName
包含组件的名字,最大为128字节,包括‘\0‘。
1.1.2.2.2 pInitialize
指向组件初始化函数。
1.1.2.3 OMX_ComponentRegistered[]
任何采用静态链接组件的核心都应该定义这个全局数组,这个数组包含了注册的组件。组件采用OMX_COMPONENTREGISTERTYPE表示。
1.1.2.4 OMX_VERSIONTYPE
OMX_VERSIONTYPE用于表示组件的版本。
typedef union OMX_VERSIONTYPE { struct { OMX_U8 nVersionMajor; OMX_U8 nVersionMinor; OMX_U8 nRevision; OMX_U8 nStep; } s; OMX_U32 nVersion; } OMX_VERSIONTYPE;
1.1.2.5 OMX_PRIORITYMGMTTYPE
OMX_PRIORITYMGMTTYPE描述了分配给组件集的优先级。
typedef struct OMX_PRIORITYMGMTTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nGroupPriority; OMX_U32 nGroupID; } OMX_PRIORITYMGMTTYPE;
nGroupPriority表示组件组的优先级。0表示最高优先级。
1..1.2.6 OMX_BUFFERHEADERTYPE
在单个port的上下文环境中,每一个buffer都有一个buffer头与之关联,buffer头包含了buffer的元数据。IL client和与之通信的port分享buffer头。同时,隧道化的两个port也分享彼此的buffer头。
typedef struct OMX_BUFFERHEADERTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U8* pBuffer; OMX_U32 nAllocLen; OMX_U32 nFilledLen; OMX_U32 nOffset; OMX_PTR pAppPrivate; OMX_PTR pPlatformPrivate; OMX_U32 nOutputPortPrivate; OMX_U32 nInputPortPrivate; OMX_HANDLETYPE hMarkTargetComponent; OMX_PTR pMarkData; OMX_U32 nTickCount; OMX_TICKS nTimeStamp; OMX_U32 nFlags; OMX_U32 nOutputPortIndex; OMX_U32 nInputPortIndex; } OMX_BUFFERHEADERTYPE;
pAppPrivate指向IL client的私有数据。
hMarkTargetComponent 表示当这个buffer通过这个组件的时候,它应该发送OMX_EventMark事件。NULL 表示没有附带mark信息。 OMX_CommandMarkBuffer命令提供被标记的组件。
pMarkData IL client的特定数据。通过OMX_CommandMarkBuffer设定。
1.1.2.7 OMX_PORT_PARAM_TYPE
组件使用这个结构体表示端口的数目,以及特定领域端口的起始索引值。
typedef struct OMX_PORT_PARAM_TYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPorts; OMX_U32 nStartPortNumber; } OMX_PORT_PARAM_TYPE;
nPorts表示某个领域((audio, video, image, 或者 other)的端口的数目。nStartPortNumber表示给定端口领域的起始索引值,同一个领域的端口,依次编号。
1.1.2.8 OMX_CALLBACKTYPE
定义如下:
typedef struct OMX_CALLBACKTYPE { 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); OMX_ERRORTYPE (*EmptyBufferDone)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); OMX_ERRORTYPE (*FillBufferDone)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); } OMX_CALLBACKTYPE;
组件使用EventHandler通知IL client,当有事件发生。各个参数解释如下:
eEvent | nData1 | nData2 | pEventData |
OMX_EventCmdComplete | OMX_CommandStateSet | 变更后的状态 | NULL |
OMX_CommandFlush | 端口号 | NULL | |
OMX_CommandPortDisable | 端口号 | NULL | |
OMX_CommandPortEnable | 端口号 | NULL | |
OMX_CommandMarkBuffer | 端口号 | NULL | |
OMX_EventError | Error code | 0 | NULL |
OMX_EventMark | 0 | 0 | 与mark关联的数据 |
OMX_EventPortSettingsChanged | 端口号 | 0 | NULL |
OMX_EventBufferFlag | 端口号 | nFlags | |
OMX_EventResourcesAcquired | 0 | 0 | NULL |
1.1.2.9 OMX_PARAM_BUFFERSUPPLIERTYPE
用于表示buffer提供者的设置或者属性。
typedef struct OMX_PARAM_BUFFERSUPPLIERTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_BUFFERSUPPLIERTYPE eBufferSupplier; } OMX_PARAM_BUFFERSUPPLIERTYPE;
1.1.2.10 OMX_TUNNELSETUPTYPE
ComponentTunnelRequest函数使用这个结构体在两个port之间传递数据,当IL client通过OMX_SetupTunnel在port之间建立连接。
typedef struct OMX_TUNNELSETUPTYPE { OMX_U32 nTunnelFlags; OMX_BUFFERSUPPLIERTYPE eSupplier; } OMX_TUNNELSETUPTYPE;
nTunnelFlags包含一个或者多个bit标志位。包括以下标志位:
#define OMX_PORTTUNNELFLAG_READONLY 0x00000001
1.1.2.11 OMX_PARAM_PORTDEFINITIONTYPE
这个结构体表示组件端口的属性。
typedef struct OMX_PARAM_PORTDEFINITIONTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_DIRTYPE eDir; OMX_U32 nBufferCountActual; OMX_U32 nBufferCountMin; OMX_U32 nBufferSize; OMX_BOOL bEnabled; OMX_BOOL bPopulated; union { OMX_AUDIO_PORTDEFINITIONTYPE audio; OMX_VIDEO_PORTDEFINITIONTYPE video; OMX_IMAGE_PORTDEFINITIONTYPE image; OMX_OTHER_PORTDEFINITIONTYPE other; } format; } OMX_PARAM_PORTDEFINITIONTYPE;
OpenMax的数据类型