Android开发之:OpenMax的接口与实现

OpenMax IL层的接口定义由若干个头文件组成,这也是实现它需要实现的内容,它们的基本描述如下所示。

  OMX_Types.h:OpenMax Il的数据类型定义

  OMX_Core.h:OpenMax IL核心的API

  OMX_Component.h:OpenMax IL 组件相关的 API

  OMX_Audio.h:音频相关的常量和数据结构

  OMX_IVCommon.h:图像和视频公共的常量和数据结构

  OMX_Image.h:图像相关的常量和数据结构

  OMX_Video.h:视频相关的常量和数据结构

  OMX_Other.h:其他数据结构(包括A/V 同步)

  OMX_Index.h:OpenMax IL定义的数据结构索引

  OMX_ContentPipe.h:内容的管道定义

  提示:OpenMax标准只有头文件,没有标准的库,设置没有定义函数接口。对于实现者,需要实现的主要是包含函数指针的结构体。

  其中,OMX_Component.h中定义的OMX_COMPONENTTYPE结构体是OpenMax IL层的核心内容,表示一个组件,其内容如下所示:

typedef struct OMX_COMPONENTTYPE
{
    OMX_U32 nSize;                          
/* 这个结构体的大小 */
    OMX_VERSIONTYPE nVersion;              
/* 版本号 */
    OMX_PTR pComponentPrivate;            
/* 这个组件的私有数据指针. */
    
/* 调用者(IL client)设置的指针,用于保存它的私有数据,传回给所有的回调函数 */
    OMX_PTR pApplicationPrivate;
    
/* 以下的函数指针返回OMX_core.h中的对应内容 */
    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);
    OMX_ERRORTYPE (
* SendCommand)(                           /* 发送命令 */
            OMX_IN  OMX_HANDLETYPE hComponent,
            OMX_IN  OMX_COMMANDTYPE Cmd,
            OMX_IN  OMX_U32 nParam1,
            OMX_IN  OMX_PTR pCmdData);
    OMX_ERRORTYPE (
* GetParameter)(                           /* 获得参数 */
            OMX_IN  OMX_HANDLETYPE hComponent,
            OMX_IN  OMX_INDEXTYPE nParamIndex,  
            OMX_INOUT OMX_PTR pComponentParameterStructure);
    OMX_ERRORTYPE (
* SetParameter)(                         /* 设置参数 */
            OMX_IN  OMX_HANDLETYPE hComponent,
            OMX_IN  OMX_INDEXTYPE nIndex,
            OMX_IN  OMX_PTR pComponentParameterStructure);
    OMX_ERRORTYPE (
* GetConfig)(                             /* 获得配置 */
            OMX_IN  OMX_HANDLETYPE hComponent,
            OMX_IN  OMX_INDEXTYPE nIndex,
            OMX_INOUT OMX_PTR pComponentConfigStructure);
    OMX_ERRORTYPE (
* SetConfig)(                             /* 设置配置 */
            OMX_IN  OMX_HANDLETYPE hComponent,
            OMX_IN  OMX_INDEXTYPE nIndex,
            OMX_IN  OMX_PTR pComponentConfigStructure);
    OMX_ERRORTYPE (
* GetExtensionIndex)(                     /* 转换成OMX结构的索引 */
            OMX_IN  OMX_HANDLETYPE hComponent,
            OMX_IN  OMX_STRING cParameterName,
            OMX_OUT OMX_INDEXTYPE
* pIndexType);
    OMX_ERRORTYPE (
* GetState)(                               /* 获得组件当前的状态 */
            OMX_IN  OMX_HANDLETYPE hComponent,
            OMX_OUT OMX_STATETYPE
* pState);
    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);
    OMX_ERRORTYPE (
* UseBuffer)(                             /* 为某个端口使用Buffer */
            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);
    OMX_ERRORTYPE (
* AllocateBuffer)(                       /* 在某个端口分配Buffer */
            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);
    OMX_ERRORTYPE (
* FreeBuffer)(                             /* 将某个端口Buffer释放 */
            OMX_IN  OMX_HANDLETYPE hComponent,
            OMX_IN  OMX_U32 nPortIndex,
            OMX_IN  OMX_BUFFERHEADERTYPE
* pBuffer);
    OMX_ERRORTYPE (
* EmptyThisBuffer)(                         /* 让组件消耗这个Buffer */
            OMX_IN  OMX_HANDLETYPE hComponent,
            OMX_IN  OMX_BUFFERHEADERTYPE
* pBuffer);
    OMX_ERRORTYPE (
* FillThisBuffer)(                         /* 让组件填充这个Buffer */
            OMX_IN  OMX_HANDLETYPE hComponent,
            OMX_IN  OMX_BUFFERHEADERTYPE
* pBuffer);
    OMX_ERRORTYPE (
* SetCallbacks)(                           /* 设置回调函数 */
            OMX_IN  OMX_HANDLETYPE hComponent,
            OMX_IN  OMX_CALLBACKTYPE
* pCallbacks,
            OMX_IN  OMX_PTR pAppData);
    OMX_ERRORTYPE (
* ComponentDeInit)(                         /* 反初始化组件 */
            OMX_IN  OMX_HANDLETYPE hComponent);
    OMX_ERRORTYPE (
* UseEGLImage)(
            OMX_IN OMX_HANDLETYPE hComponent,
            OMX_INOUT OMX_BUFFERHEADERTYPE
** ppBufferHdr,
            OMX_IN OMX_U32 nPortIndex,
            OMX_IN OMX_PTR pAppPrivate,
            OMX_IN void
* eglImage);
    OMX_ERRORTYPE (
* ComponentRoleEnum)(
            OMX_IN OMX_HANDLETYPE hComponent,
         OMX_OUT OMX_U8
* cRole,
         OMX_IN OMX_U32 nIndex);
} OMX_COMPONENT

  OMX_COMPONENTTYPE结构体实现后,其中的各个函数指针就是调用者可以使用的内容。各个函数指针和OMX_core.h中定义的内容相对应。

  EmptyThisBuffer和FillThisBuffer是驱动组件运行的基本的机制,前者表示让组件消耗缓冲区,表示对应组件输入的内容;后者表示让组件填充缓冲区,表示对应组件输出的内容。

  UseBuffer,AllocateBuffer,FreeBuffer为和端口相关的缓冲区管理函数,对于组件的端口有些可以自己分配缓冲区,有些可以使用外部的缓冲区,因此有不同的接口对其进行操作。

  SendCommand表示向组件发送控制类的命令。GetParameter,SetParameter,GetConfig,SetConfig几个接口用于辅助的参数和配置的设置和获取。

  ComponentTunnelRequest用于组件之间的隧道化连接,其中需要制定两个组件及其相连的端口。

  ComponentDeInit用于组件的反初始化。

  提示:OpenMax函数的参数中,经常包含OMX_IN和OMX_OUT等宏,它们的实际内容为空,只是为了标记参数的方向是输入还是输出。

  OMX_Component.h中端口类型的定义为OMX_PORTDOMAINTYPE枚举类型,内容如下所示:

typedef enum OMX_PORTDOMAINTYPE {
    OMX_PortDomainAudio,        
/* 音频类型端口 */
    OMX_PortDomainVideo,        
/* 视频类型端口 */
    OMX_PortDomainImage,        
/* 图像类型端口 */
    OMX_PortDomainOther,        
/* 其他类型端口 */
    OMX_PortDomainKhronosExtensions
= 0x6F000000,
    OMX_PortDomainVendorStartUnused
= 0x7F000000
    OMX_PortDomainMax
= 0x7ffffff
} OMX_PORTDOMA

  音频类型,视频类型,图像类型,其他类型是OpenMax IL层此所定义的四种端口的类型。

  端口具体内容的定义使用OMX_PARAM_PORTDEFINITIONTYPE类(也在OMX_Component.h中定义)来表示,其内容如下所示:

typedef struct OMX_PARAM_PORTDEFINITIONTYPE {
    OMX_U32 nSize;                        
/* 结构体大小 */
    OMX_VERSIONTYPE nVersion;            
/* 版本 */
    OMX_U32 nPortIndex;                
/* 端口号 */
    OMX_DIRTYPE eDir;                    
/* 端口的方向 */
    OMX_U32 nBufferCountActual;            
/* 为这个端口实际分配的Buffer的数目 */
    OMX_U32 nBufferCountMin;            
/* 这个端口最小Buffer的数目 */
    OMX_U32 nBufferSize;                
/* 缓冲区的字节数 */
    OMX_BOOL bEnabled;                    
/* 是否使能 */
    OMX_BOOL bPopulated;                
/* 是否在填充 */
    OMX_PORTDOMAINTYPE eDomain;            
/* 端口的类型 */
    union {                            
/* 端口实际的内容,由类型确定具体结构 */
        OMX_AUDIO_PORTDEFINITIONTYPE audio;
        OMX_VIDEO_PORTDEFINITIONTYPE video;
        OMX_IMAGE_PORTDEFINITIONTYPE image;
        OMX_OTHER_PORTDEFINITIONTYPE other;
    } format;
    OMX_BOOL bBuffersContiguous;
    OMX_U32 nBufferAlignment;
} OMX_PARAM_PORTDEFINITIONTYPE;

  对于一个端口,其重点的内容如下。

  端口的方向(OMX_DIRTYPE):包含OMX_DirInput(输入)和OMX_DirOutput(输出)两种

  端口分配的缓冲区数目和最小缓冲区数目

  端口的类型(OMX_PORTDOMAINTYPE):可以是四种类型

  端口格式的数据结构:使用format联合体来表示,具体由四种不同类型来表示,与端口的类型相对应

  OMX_AUDIO_PORTDEFINITIONTYPE,OMX_VIDEO_PORTDEFINITIONTYPE,OMX_IMAGE_PORTDEFINITIONTYPE和OMX_OTHER_PORTDEFINITIONTYPE等几个具体的格式类型,分别在OMX_Audio.h,OMX_Video.h,OMX_Image.h和OMX_Other.h这四个头文件中定义。

  OMX_BUFFERHEADERTYPE是在OMX_Core.h中定义的,表示一个缓冲区的头部结构。

  OMX_Core.h中定义的枚举类型OMX_STATETYPE命令表示OpenMax的状态机,内容如下所示:

typedef enum OMX_STATETYPE
{
    OMX_StateInvalid,                  
/* 组件监测到内部的数据结构被破坏 */
    OMX_StateLoaded,                    
/* 组件被加载但是没有完成初始化 */
    OMX_StateIdle,                      
/* 组件初始化完成,准备开始 */
    OMX_StateExecuting,                
/* 组件接受了开始命令,正在树立数据 */
    OMX_StatePause,                    
/* 组件接受暂停命令 */
    OMX_StateWaitForResources,        
/* 组件正在等待资源 */
    OMX_StateKhronosExtensions
= 0x6F000000, /* 保留 */
    OMX_StateVendorStartUnused
= 0x7F000000, /* 保留 */
    OMX_StateMax
= 0X7FFFFFFF
} OMX_STATETYPE;

  OpenMax组件的状态机可以由外部的命令改变,也可以由内部发生的情况改变。OpenMax IL组件的状态机的迁移关系如图18-6所示。

OpenMax的接口与实现
▲图18-6 OpenMax IL组件的状态机的迁移关系

  OMX_Core.h中定义的枚举类型OMX_COMMANDTYPE表示对组件的命令类型,内容如下所示:

typedef enum OMX_COMMANDTYPE
{
    OMX_CommandStateSet,                
/* 改变状态机器 */
    OMX_CommandFlush,                    
/* 刷新数据队列 */
    OMX_CommandPortDisable,            
/* 禁止端口 */
    OMX_CommandPortEnable,              
/* 使能端口 */
    OMX_CommandMarkBuffer,              
/* 标记组件或Buffer用于观察 */
    OMX_CommandKhronosExtensions
= 0x6F000000, /* 保留 */
    OMX_CommandVendorStartUnused
= 0x7F000000, /* 保留 */
    OMX_CommandMax
= 0X7FFFFFFF
} OMX_COMMANDTYPE;

  OMX_COMMANDTYPE类型在SendCommand调用中作为参数被使用,其中OMX_CommandStateSet就是改变状态机的命令。


  OpenMax IL实现的内容

  对于OpenMax IL层的实现,一般的方式并不调用OpenMax DL层。具体实现的内容就是各个不同的组件。OpenMax IL组件的实现包含以下两个步骤。

  组件的初始化函数:硬件和OpenMax数据结构的初始化,一般分成函数指针初始化、私有数据结构的初始化、端口的初始化等几个步骤,使用其中的pComponentPrivate成员保留本组件的私有数据为上下文,最后获得填充完成OMX_COMPONENTTYPE类型的结构体

  OMX_COMPONENTTYPE类型结构体的各个指针:实现其中的各个函数指针,需要使用私有数据的时候,从其中的pComponentPrivate得到指针,转化成实际的数据结构使用

  端口的定义是OpenMax IL组件对外部的接口。OpenMax IL常用的组件大都是输入和输出端口各一个。对于最常用的编解码(Codec)组件,通常需要在每个组件的实现过程中,调用硬件的编解码接口来实现。在组件的内部处理中,可以建立线程来处理。OpenMax的组件的端口有默认参数,但也可以在运行时设置,因此一个端口也可以支持不同的编码格式。音频编码组件的输出和音频编码组件的输入通常是原始数据格式(PCM格式),视频编码组件的输出和视频编码组件的输入通常是原始数据格式(YUV格式)。

  提示:在一种特定的硬件实现中,编解码部分具有相似性,因此通常可以构建一个OpenMax组件的“基类”或者公共函数,来完成公共性的操作。


  Android中OpenMax的适配层

  Android中的OpenMax适配层的接口在frameworks/base/include/media/目录中的IOMX.h文件定义,其内容如下所示:

class IOMX : public IInterface {
public :
    DECLARE_META_INTERFACE(OMX);
    typedef void
* buffer_id;
    typedef void
* node_id;
    virtual bool livesLocally(pid_t pid)
= 0 ;
    struct ComponentInfo {                    
// 组件的信息
        String8 mName;
        List
< String8 > mRoles;
    };
    virtual status_t listNodes(List
< ComponentInfo > * list) = 0 ;   // 节点列表
    virtual status_t allocateNode(
            
const char * name, const sp < IOMXObserver > & observer,   // 分配节点
            node_id
* node) = 0 ;
    virtual status_t freeNode(node_id node)
= 0 ;                   // 找到节点
    virtual status_t sendCommand(                                    
// 发送命令
            node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param)
= 0 ;
    virtual status_t getParameter(                                  
// 获得参数
            node_id node, OMX_INDEXTYPE index,
            void
* params, size_t size) = 0 ;
    virtual status_t setParameter(                                  
// 设置参数
            node_id node, OMX_INDEXTYPE index,
            
const void * params, size_t size) = 0 ;
    virtual status_t getConfig(                                      
// 获得配置
            node_id node, OMX_INDEXTYPE index,
            void
* params, size_t size) = 0 ;
    virtual status_t setConfig(                                      
// 设置配置
            node_id node, OMX_INDEXTYPE index,
            
const void * params, size_t size) = 0 ;
    virtual status_t useBuffer(                                      
// 使用缓冲区
            node_id node, OMX_U32 port_index,
const sp < IMemory > & params,
            buffer_id
* buffer) = 0 ;
    virtual status_t allocateBuffer(                                
// 分配缓冲区
            node_id node, OMX_U32 port_index, size_t size,
            buffer_id
* buffer, void ** buffer_data) = 0 ;
    virtual status_t allocateBufferWithBackup(                    
// 分配带后备缓冲区
            node_id node, OMX_U32 port_index,
const sp < IMemory > & params,
            buffer_id
* buffer) = 0 ;
    virtual status_t freeBuffer(                                      
// 释放缓冲区
            node_id node, OMX_U32 port_index, buffer_id buffer)
= 0 ;
    virtual status_t fillBuffer(node_id node, buffer_id buffer)
= 0 ; // 填充缓冲区
    virtual status_t emptyBuffer(                                    
// 消耗缓冲区
            node_id node,
            buffer_id buffer,
            OMX_U32 range_offset, OMX_U32 range_length,
            OMX_U32 flags, OMX_TICKS timestamp)
= 0 ;
    virtual status_t getExtensionIndex(
            node_id node,
            
const char * parameter_name,
            OMX_INDEXTYPE
* index) = 0 ;
    virtual sp
< IOMXRenderer > createRenderer(         // 创建渲染器(从ISurface)
            
const sp < ISurface > & surface,
            
const char * componentName,
            OMX_COLOR_FORMATTYPE colorFormat,
            size_t encodedWidth, size_t encodedHeight,
            size_t displayWidth, size_t displayHeight)
= 0 ;
    sp
< IOMXRenderer > createRenderer(                   // 创建渲染器(从Surface)
            
const sp < Surface > & surface,
            
const char * componentName,
            OMX_COLOR_FORMATTYPE colorFormat,
            size_t encodedWidth, size_t encodedHeight,
            size_t displayWidth, size_t displayHeight);
    sp
< IOMXRenderer > createRendererFromJavaSurface(         // 从Java层创建渲染器
            JNIEnv
* env, jobject javaSurface,
            
const char * componentName,
            OMX_COLOR_FORMATTYPE colorFormat,
            size_t encodedWidth, size_t encodedHeight,
            size_t displayWidth, size_t displayHeight);
};

  IOMX表示的是OpenMax的一个组件,根据Android的Binder IPC机制,BnOMX继承IOMX,实现者需要继承实现BnOMX。IOMX类中,除了和标准的OpenMax的GetParameter,SetParameter,GetConfig,SetConfig,SendCommand,UseBuffer,AllocateBuffer,FreeBuffer,FillThisBuffer和EmptyThisBuffer等接口之外,还包含了创造渲染器的接口createRenderer(),创建的接口为IOMXRenderer类型。

  IOMX中只有第一个createRenderer()函数是纯虚函数,第二个的createRenderer()函数和createRendererFromJavaSurface()通过调用第一个createRenderer()函数实现。

  IOMXRenderer类表示一个OpenMax的渲染器,其定义如下所示:

class IOMXRenderer : public IInterface {
public :
    DECLARE_META_INTERFACE(OMXRenderer);
    virtual void render(IOMX::buffer_id buffer)
= 0 ;   // 渲染输出函数
};

  IOMXRenderer只包含了一个render接口,其参数类型IOMX::buffer_id实际上是void*,根据不同渲染器使用不同的类型。

  在IOMX.h文件中,另有表示观察器类的IOMXObserver,这个类表示OpenMax的观察者,其中只包含一个onMessage()函数,其参数为omx_message接口体,其中包含Event事件类型、FillThisBuffer完成和EmptyThisBuffer完成几种类型。

  提示:Android中OpenMax的适配层是OpenMAX IL层至上的封装层,在Android系统中被StageFright调用,也可以被其他部分调用。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值