openmax用法

     

一  omx概述

 OpenMax是一个多媒体应用程序的框架标准。它自上而下分为三层,Application Layer, Integration Layer和Development Layer。应用层规定了应用程序和多媒体中间层的标准接口,使应用程序的移植性更好。集成层定义了多媒体组件的接口,使得多媒体框架能以一种统一的方式访问多媒体Codec和组件,以便在嵌入式流媒体框架中快速集成加速编解码器。开发层为Codec厂商和硬件厂商提供了一套API,使开发更加便捷。

openmax用法_第1张图片                                                          图 OpenMax的分层结构

omx由组件构成:

1. 组件是独立的一个处理模块,可以有内部独立的线程(但并不一定)处理数据。 通常组件类型有:splitter组件、hot组件、sink组件、clock组件等。

2. 组件之间通过端口进行数据通信,每个组件至少要有一个端口,根据数据方向区分:有输入端口 和 输出端口 两种方向。任意一个端口只能是其中一种方向。

     OMXMaster 负责OMX中编解码器插件管理,软件解码和硬件解码都使用OMX标准,挂载plugins的方式来进行管理。

     软解通过 addPlugin(new SoftOMXPlugin)把这些编解码器的名字都放在PluginByComponentName。

     硬件编解码是通过 addVendorPlugin(); 加载 libstagefrighthw.so.各个芯片平台可以遵循openmax 标准,生成libstagefrighthw.so的库来提供android应用。

android定义软编解码    /frameworks/av/media/libstagefright/omx/OMXMaster.cpp

  1. kComponents[] = {  
  2.     { "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" },  
  3.     { "OMX.google.aac.encoder", "aacenc", "audio_encoder.aac" },  
  4.     { "OMX.google.amrnb.decoder", "amrdec", "audio_decoder.amrnb" },  
  5.     { "OMX.google.amrnb.encoder", "amrnbenc", "audio_encoder.amrnb" },  
  6.     { "OMX.google.amrwb.decoder", "amrdec", "audio_decoder.amrwb" },  
  7.     { "OMX.google.amrwb.encoder", "amrwbenc", "audio_encoder.amrwb" },  
  8.     { "OMX.google.h264.decoder", "h264dec", "video_decoder.avc" },  
  9.     { "OMX.google.h264.encoder", "h264enc", "video_encoder.avc" },  
  10.     { "OMX.google.g711.alaw.decoder", "g711dec", "audio_decoder.g711alaw" },  
  11.     { "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" },  
  12.     { "OMX.google.h263.decoder", "mpeg4dec", "video_decoder.h263" },  
  13.     { "OMX.google.h263.encoder", "mpeg4enc", "video_encoder.h263" },  
  14.     { "OMX.google.mpeg4.decoder", "mpeg4dec", "video_decoder.mpeg4" },  
  15.     { "OMX.google.mpeg4.encoder", "mpeg4enc", "video_encoder.mpeg4" },  
  16.     { "OMX.google.mp3.decoder", "mp3dec", "audio_decoder.mp3" },  
  17.     { "OMX.google.vorbis.decoder", "vorbisdec", "audio_decoder.vorbis" },  
  18.     { "OMX.google.vpx.decoder", "vpxdec", "video_decoder.vpx" },  
  19.     { "OMX.google.raw.decoder", "rawdec", "audio_decoder.raw" },  
  20.     { "OMX.google.flac.encoder", "flacenc", "audio_encoder.flac" },  
  21. };  

高通定义         /QNX/qnx_ap/AMSS/multimedia/video/source/common/applications/qplayer/inc/OmxPlayer.h

// OMX component name

#define QCOM_DEMUXER_COMPONENT_NAME              "OMX.qcom.file.demuxer"

#define QCOM_IVRENDERER_COMPONENT_NAME           "OMX.qcom.video.mmirenderer"

#define QCOM_CLOCK_COMPONENT_NAME                "OMX.qcom.mmiclock"

#define QCOM_VIDEODECODER_COMPONENT_NAME         "OMX.qcom.video.decoder"

#define QCOM_VIDEODECODER_COMPONENT_NAME_AVC     "OMX.qcom.video.decoder.avc"

#define QCOM_VIDEODECODER_COMPONENT_NAME_MPEG4   "OMX.qcom.video.decoder.mpeg4"

#define QCOM_VIDEODECODER_COMPONENT_NAME_H263    "OMX.qcom.video.decoder.h263"

#define QCOM_VIDEODECODER_COMPONENT_NAME_WMV     "OMX.qcom.video.decoder.wmv"

#define QCOM_VIDEODECODER_COMPONENT_NAME_MPEG2   "OMX.qcom.video.decoder.mpeg2"

#define QCOM_VIDEODECODER_COMPONENT_NAME_DIVX    "OMX.qcom.video.decoder.divx"

#define QCOM_VIDEODECODER_COMPONENT_NAME_DIVX311 "OMX.qcom.video.decoder.divx311"

#define QCOM_VIDEODECODER_COMPONENT_NAME_VP8     "OMX.qcom.video.decoder.vp8"

#define QCOM_VIDEODECODER_COMPONENT_NAME_SPARK   "OMX.qcom.video.decoder.spark"

#define QCOM_VIDEODECODER_COMPONENT_NAME_VC1     "OMX.qcom.video.decoder.vc1"

#define QCOM_VIDEODECODER_COMPONENT_NAME_HEVC    "OMX.qcom.video.decoder.hevc"

#define QCOM_VIDEODECODER_COMPONENT_NAME_VP9     "OMX.qcom.video.decoder.vp9"

#define QCOM_AUDIODECODER_COMPONENT_NAME         "OMX.qcom.audiodecoder"

#define QCOM_AUDIORENDERER_COMPONENT_NAME        "OMX.qcom.audiorenderer"

#define QCOM_RTPSOURCE_COMPONENT_NAME            "OMX.qcom.rtpSource"

#define QCOM_MPEG2TSDEMUXER_COMPONENT_NAME       "OMX.qcom.demuxer.mpeg2ts"

#define QCOM_VPP_COMPONENT_NAME                  "OMX.qcom.vpp"

3. 端口根据通信的数据类型可以分为四种:Video_Port; Audio_Port; Image_Port; Other_Port; 其中除了音视频和图像数据,其他数据都是通过Other_Port来传递,比较典型的就是Clock全局时钟。

4. 每个组件都有自己独立的运行状态机,总共有6个状态。

   OMX_StateInvalid : 组件运行中产生无法恢复的错误,不能再继续进行了,只能卸载组件

   OMX_StateLoaded : 组件已经加载到系统中,但是还没有进行初始化

   OMX_StateWaitForResources:组件正在等待资源,当资源到位后会切换成Idle状态

   OMX_StateIdle:组件初始化完成,一切准备就绪

   OMX_StateExecuting:组件正常运行,进行相关数据处理

   OMX_StatePause:组件暂停运行

5. 组件支持两种不同的Profile:

1)Base Profile: 仅支持 non-tunnel方式的数据通信,也可能支持Proprietary模式

2)Interop Profile: 必须支持tunnel 和 non-tunnel两种数据通信方式,也可能支持Proprietary模式

       OMX集成层由Client、Core、Component和Port组成,Client通过Core得到对应Component的Handle,而后通过命令直接和Component进行交互。每个Component至少有一个Port进行数据交互,如Decoder有一个输入Port接收码流,一个输出Port输出YUV序列。Component内部可能通过消息处理机制完成Client要求的任务。

openmax用法_第2张图片

                                              图 StageFright的OMX结构

调用过程

二  omx用法

文件 描述
OMX_Types.h 数据类型,里面定义了组件类型、输入输出等
OMX_Core.h IL层的核心API,有命令枚举、状态枚举、组件注册/初始化等等
OMX_Component.h 组件相关的API,有端口类型与定义、组件回调函数成员定义等
OMX_Audio.h 与音频相关的常量和结构体定义
OMX_IVCommon.h 图像与视频通用的一些常量和结构体定义
OMX_Video.h 视频相关的常量和结构体定义
OMX_VideoExt.h 视频相关的常量和数据结构,是对OMX_Video.h的补充扩展
OMX_Image.h 图像相关的常量和结构体定义
OMX_Other.h 其它部分的结构体定义 (包含A/V同步)
OMX_Index.h OpenMAX定义的数据结构索引
OMX_IndexExt.h OpenMax 定义的数据结构扩展索引
OMX_ContentPipe.h 内容的管道定义
  • OMX_BUFFERSUPPLIERTYPE:用于组件内部端口数据流标识。

  • OMX_COMMANDTYPE:命令相关的枚举,用于Client对组件的命令控制。

  • OMX_STATETYPE:组件状态相关的枚举,用于组件状态标识。

  • OMX_ERRORTYPE:错误相关的枚举,类似于C库的错误状态集,用于标识组件内部或者Client的出错状态。

  • OMX_EVENTTYPE:事件相关的枚举,用于组件内部向Client发送事件通知。

1组件库函数:

       openmax用法_第3张图片

  1. IL层支持的库函数主要有两组:一组是针对所有组件库的Core函数; 另外一组是针对单个组件的函数。
  2. 大部分的函数操作都是同步调用,并且严格限制函数的执行时间(例如:OMX_SetConfig 限制在5ms内;OMX_UseBuffer 限制在20ms内)。
  3. OMX_FillThisBuffer() 和 OMX_EmptyThisBuffer()是异步调用,组件在实际执行完成后通过 EmptyBufferDone() 和 FillBufferDone() 两个回调通知执行完成。
  4. OMX_SendCommand() 函数也是异步调用,支持5种命令调用

        1)OMX_CommandStateSet: 切换状态机

        2)OMX_CommandFlush: 刷新缓冲区

        3)OMX_CommandPortDisable:禁用某个端口

        4)OMX_CommandPortEnable 启用某个端口

        5)OMX_CommandMarkBuffer:标记缓冲区对象(如:仅解码)

        这些命令执行完成后通过 EventHandler() 回调来通知完成

通过EmptyThisBuffer传递未解码的buffer给component,component收到该命令后会去读取input port buffer中的数据,将其组装为帧之后进行解码,buffer处理完成后会通过EmptyBufferDone通知上层输入使用完成,上层收到命令可以继续送输入帧流程。输出buffer方面,通过FillThisBuffer传递填充输出的空buffer给component,component在解码之后通过FillBufferDone通知上层输出填写完成,上层可以继续送待填充的输出帧流程。
 

openmax用法_第4张图片

 

  2缓冲区对象

 3组件通信方式

openmax用法_第5张图片

tunnel模式

  1. IL Client通过OMX_AllocateBuffer() 在组件A的输出端口上创建缓冲区对象,这个缓冲区对象直接返回给 IL Client。
  2. IL Client再将这个缓冲区对象,通过 OMX_UseBuffer()指定给组件B的输入端口使用这个缓冲区对象。
  3. IL Client调用 OMX Core的 OMX_SetupTunnel(hCompA, nOutPortIdx, hCompB, nInPortIdx) 函数来将两个组件的输入输出端口建立隧道通信方式。注:这个函数内部实现会调用两个组件的内部函数ComponentTunnelRequest()来传递组件本身的信息。
  4. Push数据方式:组件A数据准备完毕后,直接调用组件B上的 OMX_EmptyThisBuffer()方法让组件B取数据,组件B获取完数据后,将OMX_EmptyBufferDone()通知直接回调给组件A,通知组件A这个缓冲区已经清空,可以继续使用了。
  5. Pull数据方式:组件B需要数据的时候,直接调用组件A上的 OMX_FillThisBuffer()方法让组件A填充数据,组件A填充完成后,将OMX_FillBufferDone()通知直接回调给组件B,通知组件B这个缓冲区上数据可以使用了。

与 Non-tunnel方式主要的差异就是:建立隧道后,组件之间的数据通信不需要IL Client参与了,两个组件内部直接进行。 通常支持Tunnel通信方式的组件都有内部线程,方便数据同步处理

non-tunnel模式

  1. IL Client通过OMX_AllocateBuffer() 在组件A的输出端口上创建缓冲区对象,这个缓冲区对象直接返回给 IL Client。
  2. IL Client再将这个缓冲区对象,通过 OMX_UseBuffer()指定给组件B的输入端口使用这个缓冲区对象。
  3. 在循环的数据处理过程中,IL Client调用OMX_FillThisBuffer() 命令组件A将处理好要输出的数据填入这个缓冲区中,注意:这个调用是异步的,这个调用返回后,缓冲区数据可能还没有填充好。
  4. 组件A内部先进行数据处理,处理完成后将输出数据填入缓冲区,然后通过 OMX_FillBufferDone()回调函数通知IL Client数据已经准备好。
  5. IL Client接收到回调后,调用OMX_EmptyThisBuffer()命令组件B来取缓冲区中的数据,注意:这个调用也是异步的,这个调用返回后,缓冲区数据可能还没有取走。
  6. 组件B内部根据优先处理顺序,将缓冲区中的数据全部取走后,然后通过OMX_EmptyBufferDone()回调函数通知IL Client缓冲区已经清空,可以继续使用。 如此反复来传递缓冲区对象,使得两个组件通过一个缓冲区来进行通信。
  7. 最后在组件A上释放这个缓冲区对象

proprietary模式

  1. 组件之间有类似DMA之类的直接通信机制,不需要外部提供缓冲区和控制缓冲区对象传递。
  2. IL Client 只需要调用 OMX Core的 OMX_SetupTunnel(hCompA, nOutPortIdx, hCompB, nInPortIdx) 函数来将两个组件的输入输出端口建立关联即可。
  3. 通常这种情况下的组件都是由硬件来实现,直接通过硬件或者系统内部的共享缓冲区来访问数据
  4. 通信时也不再有 OMX_FillBufferDone() 和 OMX_EmptyBufferDone() 的回调

你可能感兴趣的:(音视频,openmax)