OMX IL Spec将API划分为Control API、Data API、Extension API,所谓Control API指的是IL Client用于控制组件的接口,包含调用OMX Core和OMX Component要用的接口与相关结构体,这一篇我们将重点阅读与Control API相关的宏、结构体与枚举。
1、OMX IL目录结构
OMX IL API由一组头文件定义,包含以下内容:
OMX_Types.h
:OMX使用的数据类型;OMX_Core.h
:OMX Core API以及相关结构体类型;OMX_Component.h
:OMX Component API以及相关结构体类型;OMX_Audio.h
:audio domain(域)相关的结构体,domain表示范围的意思,这里表示audio范围内的,后续将audio domain简称为audio;OMX_IVCommon.h
:audio、image和video公用的结构体;OMX_Video.h
:video相关的结构体;OMX_Image.h
:image相关的结构体;OMX_Other.h
:其他域用到的结构体;OMX_Index.h
:所有OMX定义的数据结构的索引,上面所说的所有结构体都有一个索引与之相对应;
在Android中,OMX IL API放在 frameworks/native/headers/media_plugin/media/openmax
目录下,进入目录可以看到包含所有上述提到的文件,除此之外还多了几个Ext结尾的文件,比如OMX_AudioExt.h
、OMX_VideoExt.h
,与之相对应的要添加索引文件OMX_IndexExt.h
,Ext表示扩展,意为这是Android在OMX IL基础上扩展的内容。
2、OMX_Types.h
OMX IL使用的基本数据类型存放在OMX_Types.h
中,里面有一些宏定义,枚举和结构体,这里我们挑一些比较常见的来阅读。
OMX IL API在函数声明中使用宏参数功能进行描述:
OMX_IN
:指定参数是一个输入参数,由调用者设定,由函数体读取;OMX_OUT
:指定参数是一个输出参数,参数值由函数体设定并回传给调用者,函数返回时调用者可以从参数中读到新的值,属于引用传递;OMX_INOUT
:指定函数调用者可以设置的参数类型为输入/输出参数,函数体可以读到参数值,也可以将
还有另外一个宏OMX_ALL
,用于选择相同类型下的所有内容,在端口选择中会用到这个宏,表示选择所有端口。
接下来是一组typedef定义的数据类型:
typedef unsigned char OMX_U8;
typedef signed char OMX_S8;
typedef unsigned short OMX_U16;
typedef signed short OMX_S16;
typedef uint32_t OMX_U32;
typedef int32_t OMX_S32;
typedef unsigned long long OMX_U64;
typedef signed long long OMX_S64;
typedef void* OMX_PTR;
typedef char* OMX_STRING;
typedef unsigned char* OMX_BYTE;
typedef OMX_PTR OMX_HANDLETYPE;
上篇文章中提到组件句柄,它使用的类型是OMX_HANDLETYPE,在这我们可以知道组件句柄就是一个void*
指针。
最后是一些枚举类型:
typedef enum OMX_DIRTYPE
{
OMX_DirInput, /**< Port is an input port */
OMX_DirOutput, /**< Port is an output port */
OMX_DirMax = 0x7FFFFFFF
} OMX_DIRTYPE;
Dir是Direction的缩写,表示方向,用于表示端口数据的流向。如果数据向组件流入,端口用OMX_DirInput描述,表示输入端口;相对的如果数据从组件流出,用OMX_DirOutput表示输出端口。
为了跨平台OMX IL用枚举定义了布尔类型:
typedef enum OMX_BOOL {
OMX_FALSE = 0,
OMX_TRUE = !OMX_FALSE,
OMX_BOOL_MAX = 0x7FFFFFFF
} OMX_BOOL;
3、OMX_Core.h
OMX Core API主要用于动态加载卸载组件,调用组件方法,所有调用组件用到的参数枚举、结构体类型,加载卸载函数,组件调用函数都存放在OMX_Core.h。
OMX_COMMANDTYPE包含了OMX IL可能发送给OMX组件的所有命令:
typedef enum OMX_COMMANDTYPE
{
OMX_CommandStateSet,
OMX_CommandFlush,
OMX_CommandPortDisable,
OMX_CommandPortEnable,
OMX_CommandMarkBuffer,
OMX_CommandKhronosExtensions = 0x6F000000,
OMX_CommandVendorStartUnused = 0x7F000000,
OMX_CommandMax = 0X7FFFFFFF
} OMX_COMMANDTYPE;
Android中常用的有:
- OMX_CommandStateSet:用于改变组件的状态;
- OMX_CommandFlush:刷新组件端口上的缓冲区队列;
- OMX_CommandPortDisable:禁用组件的一个端口;
- OMX_CommandPortEnable:启用组件的一个端口;
- OMX_CommandVendorStartUnused:除了OMX IL定义的这些命令外,厂商也可以自定义命令,命令值从0x7F000001开始;
typedef enum OMX_STATETYPE
{
OMX_StateInvalid,
OMX_StateLoaded,
OMX_StateIdle,
OMX_StateExecuting,
OMX_StatePause,
OMX_StateWaitForResources,
OMX_StateVendorStartUnused = 0x7F000000,
OMX_StateMax = 0X7FFFFFFF
} OMX_STATETYPE;
OMX_STATETYPE定义了OMX组件的状态类型,Android中只用到了前四个:
- OMX_StateInvalid:组件已损坏或遇到无法恢复的错误进入到该状态;
- OMX_StateLoaded:组件加载/创建完成,但是资源还未分配,资源指的是端口中的buffer;
- OMX_StateIdle:组件拥有所有的资源,但尚未传输任何缓冲区或开始处理数据;
- OMX_StateExecuting:组件正在传输缓冲区并正在处理数据;
由于Android用到的状态只有四种,所以我把组件状态转换图做了简化:
图中的四个红色的状态并不是OMX IL的标准内容,所以在头文件中是找不到的,但是它们在spec中有所描述。组件做状态切换时可能要处理一些事务,事务处理完成后才能完成状态切换,红色状态描述的是处理事务的中间过程。
- OMX_StateLoadedToIdle:当IL Client请求让组件从OMX_StateLoaded状态进入OMX_StateIdle状态时,组件在完成状态转换前需要获取到所有的资源(buffers),等待获取资源的过程用OMX_StateLoadedToIdle来描述。
组件连接IL Client的端口,端口中的buffer可由IL Client分配,通过调用OMX_UseBuffer将buffer传递给组件,也可由IL Client调用OMX_AllocateBuffer方法让组件来分配。
以上图为例,IL Client调用OMX_UseBuffer将buffer传递给OMX组件,OMX组件in port共享IL Client的buffer,in port获取到需要的资源;OMX组件out port由自己分配buffer,IL Client调用OMX_AllocateBuffer让组件分配出所要用的buffer,out port获取到需要的资源;当所有端口buffer获取完成,OMX组件即可进入Idle状态。
如果端口用于隧道模式,supplier port中的buffer可由自己分配,也可以复用其他buffer,简单来说我们并不在意供应端口的buffer是怎么来的;供应端口组件调用OMX_UseBuffer把buffer传递给非供应端口。
关注公众号《青山渺渺》阅读全文:
Android Media Framework(二)OpenMAX 类型阅读与分析