Android OMX介绍(总括)

2023-05-16

一、OpenMax简介(缩写为:OMX)

    OpenMAX是一个多媒体应用程序的标准。由NVIDIA公司和Khronos™在2006年推出。

    它是无授权费的、跨平台的C语言程序接口序列,这些接口对音频、视频、静态图片的常用操作进行封装。

    它包括三层,分别是应用层(AI)、集成层(IL)和开发层(DL)。其中IL层已经成为了事实上的多媒体框架标准。嵌入式处理器或者多媒体编解码模块的硬件生产者,通常提供标准的OpenMax IL层的软件接口,这样软件的开发者就可以基于这个层次的标准化接口进行多媒体程序的开发。

 

二、OpenMax在Android中的位置

        在Android中,OpenMax IL层,通常可以用于多媒体引擎的插件,Android的多媒体引擎OpenCore和StageFright都可以使用OpenMax作为插件,主要用于编解码(Codec)处理。在Android的框架层,也定义了由Android封装的OpenMax接口,和标准的接口概念基本相同,但是使用C++类型的接口,并且使用了Android的Binder IPC机制。Android封装OpenMax的接口被StageFright使用,OpenCore没有使用这个接口,而是使用其他形式对OpenMax IL层接口进行封装。

        

        

三、OpenMax的主要概念

  • 客户端(Client):访问IL core或IL component的软件层,可能是位于GUI应用程序的下层,如GStreamer。IL client是一个典型的功能块,如filter graph multimedia framework, OpenMAX AL, 或application都可以调用它。IL client与OpenMAX IL core进行交互,利用IL core加载和卸载组件、在组件间建立直接通信以及获得组件方法的入口。
  • core:相关平台的代码,具有将IL component载入主存储器的功能,当应用程序不再需要某组件时,IL core将负责把该组件从存储器卸去。一般来说,组件一旦载入存储器,IL core将不在参与应用程序与组件之间的通信。
  • 端口(Port):组件的输入输出接口
  • 组件(Component):OpenMax IL的单元,每一个组件实现一种功能。组件按照端口可分类为Source(只有一个输出端口)、Sink(只有一个输入端口)和Host组件(一个输入端口和一个输出端口),此外有一个Accelerator组件,它具有一个输入端口,调用了硬件的编解码器,加速主要体现在这个环节上。
  • 隧道化(Tunneled):让两个组件直接连接的方式。通过隧道化可以将不同的组件的一个输入端口和一个输出端口连接到一起,在这种情况下,两个组件的处理过程合并,共同处理。尤其对于单输入和单输出的组件,两个组件将作为类似一个使用。

四、OpenMax的工作方式

        首先,搭建好OpenMax的工作环境:设置组件端口、加载组件,建立连接方式等等。

     

        然后通过输入端口消耗Buffer,通过输出端口填充Buffer,由此多组件相联接可以构成流式的处理。

 

五、OpenMax的测试方式

参考《Build OpenCORE 2.05 on x86 Linux.PDF》和《omx_decoder_test_app_guide.pdf》

 

六、OpenMax接口和集成过程(以android平台的为例)

 

七、android中支持的组件和Role

根据pv_omxregistry.cpp,得到如下表格(其中黄绿色部分表示没有相应编码器)

组件角色动态库名
OMX.PV.mpeg4decvideo_decoder.mpeg4libomx_m4vdec_sharedlibrary
OMX.PV.h263decvideo_decoder.h263libomx_m4vdec_sharedlibrary
OMX.PV.avcdecvideo_decoder.avclibomx_avcdec_sharedlibrary
OMX.PV.wmvdecvideo_decoder.wmvlibomx_wmvdec_sharedlibrary
OMX.PV.rvdecvideo_decoder.rvlibomx_rvdec_sharedlibrary
OMX.PV.aacdecaudio_decoder.aaclibomx_aacdec_sharedlibrary
OMX.PV.amrdecaudio_decoder.amr

audio_decoder.amrnb

audio_decoder.amrwb

libomx_amrdec_sharedlibrary
OMX.PV.mp3decaudio_decoder.mp3libomx_mp3dec_sharedlibrary
OMX.PV.wmadecaudio_decoder.wmalibomx_wmadec_sharedlibrary
OMX.PV.radecaudio_decoder.ralibomx_radec_sharedlibrary
   
OMX.PV.amrencnbaudio_encoder.amrnblibomx_amrenc_sharedlibrary
OMX.PV.mpeg4encvideo_encoder.mpeg4libomx_m4venc_sharedlibrary
OMX.PV.h263encvideo_encoder.h263libomx_m4venc_sharedlibrary
OMX.PV.avcencvideo_encoder.avclibomx_avcenc_sharedlibrary
OMX.PV.aacencaudio_encoder.aaclibomx_aacenc_sharedlibrary

 

八、Openmax 一些函数的简单介绍

1 OMX core methods

1)OMX_Init
2)OMX_Deinit
3)OMX_GetHandle
4)OMX_FreeHandle
5)OMX_ComponentNameEnum
6)OMX_GetComponentsOfRole
7)OMX_GetRolesOfComponent
8)OMX_SetupTunnel
9)OMX_GetContentPipe


2 The configuration parser API
除了以上methods,强烈推荐OMX核心插件库包含此API
2.1函数原型
OMX_BOOL OMXConfigParser ( OMX_PTR aInputParameters,OMX_PTR aOutputParameters);

2.2 传递参数
aInputParameters 指向如下结构
typedef struct
{
OMX_U8* inPtr;    //codec 配置头部指针
OMX_U32 inBytes;   //codec 配置头部长度
OMX_STRING cComponentRole; //OMX codec类型 eg "video_decoder.mpeg4"
OMX_STRING cComponentName; //OMX 组件名称
} OMXConfigParserInputs;

2.3 返回值
OMX_FALSE : 处理codec配置头部错误或不支持该格式
OMX_TURE : 正确处理codec配置头部

2.4 函数作用
填充aOutputParameters,有两种选择:audio coded or vedio codec

for audio
typedef struct
{
OMX_U16 Channels;   //通道:单声道、立体声、5.1
OMX_U16 BitsPerSample;   //位宽(eg16)
OMX_U32 SamplesPerSec;   //采样率
} AudioOMXConfigParserOutputs;

typedef struct
{
OMX_U32 width;    //检测到的视频剪辑宽度
OMX_U32 height;    //检测到的视频剪辑高度
OMX_U32 profile;   //参数
OMX_U32 level;    //级别?
} VideoOMXConfigParserOutputs;

3 动态加载OMX内核
解释了\system\system\etc\pvplayer.cfg文件中最后一行的含义
(0xa054369c,0x22c5,0x412e,0x19,0x17,0x87,0x4c,0x1a,0x19,0xd4,0x5f),"libomx_sharedlibrary.so"

作用:将OMX内核动态加载进OpenCORE框架
位置:\system\system\etc\pvplayer.cfg
形式:(OMX Core API OsclUuid), “shared library name.so”
eg:(0xa054369c,0x22c5,0x412e,0x19,0x17,0x87,0x4c,0x1a,0x19,0xd4,0x5f),"libomx_core_vendorXYZ.so"

注意:(0xa054369c,0x22c5,0x412e,0x19,0x17,0x87,0x4c,0x1a,0x19,0xd4,0x5f) 提供独立API ID,不可修改

 

数据格式及OMX输入缓冲细节

1.1 帧起始代码
一般不用,H.264可能使用。

1.2 OMX缓冲区
三个值得信赖的关键参数
nFilledLen 缓冲区长度
nTimestamp 缓冲区时间戳
OMX_BUFFERLAG_ENDOFFRAME 缓冲区结束标志位

1.3多帧合并输入缓冲
一些音频信息,单帧过小(eg ARM),将其合并作为一个缓冲区处理。
nFilledLen为所有帧总长度,nTimestamp指向缓冲区第一帧时间。

1.4部分帧
视频解码单帧过大情况下,可能将单帧拆分后传递给缓冲区。
部分帧情况下,只有最后一帧的缓冲区才拥有OMX_BUFFERLAG_ENDOFFRAME。
部分帧缓冲区不会包含两帧信息。
流媒体可能包含多帧。
部分帧的nTimestamp应当相同。

总结:OMX输出缓冲区可能包含
——完整多帧
——完整单帧
——部分帧

1.5 错误的数据封装
多帧的部分帧封装 eg wrong(Frame1+Frame2 part)

1.6 Codec配置数据
Codec配置缓冲区使用OMX_BUFFERLAG_ENDOFFRAME 和OMX_BUFFERFLAG_CODECCONFIG标志位。
H.264的SPS和PPS使用独立的OMX输入缓冲区。

2 H264/AVC 解码器格式
Codec配置头部:
SPS和PPS NAL单元位于起始的OMX输入缓冲区。
SPS和PPS NALs使用独立的OMX输入缓冲区,并使用OMX_BUFFERLAG_ENDOFFRAME 和OMX_BUFFERFLAG_CODECCONFIG标记。

2.1 AVC NAL模式与AVC Frame模式
通过设置iOMXComponentUsesFullAVCFrame标志位,可以决定AVC数据使用哪种模式解码。
默认使用NAL模式,此种模式下OpenCORE框架同时提供完整单帧和部分帧输入缓冲区。
在Frame模式下,OpenCORE框架积累NALs并提供完整单帧给输入缓冲区。
OMX_OTHER_EXTRADATA结构体用来区分NAL边界。
如果iOMXComponentUsesFullAVCFrame和iOMXComponentUsesNALStratCodes都被置为OMX_TRUE,
NAL边界可被start codes区分,此时OMX_OTHER_EXTRADATA无用。

数据结构——NAL模式:
输入缓冲区包含一个或多个NAL,但只包含同一帧的NAL,一帧最后一个NAL才含有OMX_BUFFERLAG_ENDOFFRAME标志位。

数据结构——Frame模式:
每个输入缓冲区包含完整帧。
如果使用NAL start codes,可通过读取NAL start codes区分NAL边界。
否则使用OMX_OTHER_EXTRADATA结构体区分NAL边界。
在Frame模式中,每个缓冲区都含有OMX_BUFFERLAG_ENDOFFRAME标志位。
在Frame模式中,每个缓冲区都含有位于OMX_BUFFERLAGHEADERTYPE结构体nFlags区域的OMX_BUFFERLAG_EXTRADATA标志位。

缓冲区最后包含AVC frame,追加以下数据:
OMX_OTHER_EXTRADATATYPE extra;
OMX_OTHER_EXTRADATATYPE terminator;

extra.eType = OMX_ExtraDataNALSizeArray;
extra.nSize = 20+4*(number of NALs in the frame); // 20 is the size of
OMX_OTHER_EXTRADATATYPE structure + 4 bytes per NAL size
extra.nDataSize = 4 * (number of NALs in the frame)
extra.data[4*i] = size of the i-th NAL (data is declared as byte array – so offset is 4*i, since 4 bytes
is assigned to signal the size of each NAL unit)
terminator.eType = OMX_ExtraDataNone;
terminator.nSize = 20;
terminator.nDataSize = 0;

#define OMX_ExtraDataNALSizeArray 0x7F123321

通过获取OMX_OTHER_EXTRADATA结构体信息,可以得知每一帧包含NAL单元的数目并确定NAL边界。

一个例子:AVC Frame模式,包含2个NAL,包含extra数据结构
总结:
1)每个缓冲区都含有位于OMX_BUFFERLAGHEADERTYPE结构体nFlags区域的OMX_BUFFERLAG_EXTRADATA标志位
2)每个NAL的长度应当使用独立的4byte无符号整型数表示(eg OMX_U32)
3)所有NAL的长度被编码成OMX_U32的数组存放在buffer最后。
4)包含完整帧的缓冲区必须含有位于OMX_BUFFERLAGHEADERTYPE结构体nFlags区域的OMX_BUFFERLAG_ENDOFFRAME标志位。
5)一个独立的缓冲区不包含多帧数据。

 

3 YUV和RGB数据格式
OMX编码组件中,生肉提供YUV或者RGB格式,OpenCORE框架将提供一帧完成的YUR或RGB数据给OMX组件。

 

OpenMax 调用顺序(OpenMax Call Sequences)
1 OMX 核心初始化 _OMX_MasterInit

1)调用OMX_Init函数
->OsclInit::Init(error, &select); //init all Oscl layers except Oscl scheduler.
->_Try_OMX_Create(error, data); //create the OMX singleton
->OsclSingletonRegistry::registerInstanceAndUnlock(data, OSCL_SINGLETON_ID_OMX, error); //Release the singleton.
->_Try_OMX_Init(error, status); //If create succeeded, then init the OMX globals.

2)PV框架列举所有OMX

OMX_ComponentNameEnum //列举所有组件的名称
->OsclSingletonRegistry::getInstance(OSCL_SINGLETON_ID_OMX, error);
->oscl_strncpy(cComponentName, (data->ipRegTemplateList[Index])->ComponentName, nNameLength);

OMX_GetRolesOfComponent // 通过组件名称找到组件,返回其角色(role)
->OsclSingletonRegistry::getInstance(OSCL_SINGLETON_ID_OMX, error);
->data->ipRegTemplateList[ii])->GetRolesOfComponent(RoleString)
->oscl_strncpy((OMX_STRING) roles[ii], (OMX_STRING)RoleString[ii], oscl_strlen((OMX_STRING)RoleString[ii]) + 1);

2 OMX组件实例、功能及端口
OMX核心初始化后,下一步为列举每个组件的功能和端口。
1)调用OMX_GetHandle获取所需的OMX组件信息。

2)调用OMX_GetParameter及“PV_OMX_CAPABILITY_TYPE_INDEX”这个index去获取组件的功能。
万一组件不是OpenMax全兼容或者OpenMax的特性不明确,以上获取的功能决定了OMX是否支持输入/输出端口“UseBufeer”和“AllocateBuffer”调用,以及OMX是否支持部分帧等等。

注意:如果OMX组件返回“OMX_ErrorUnsupportedIndex”给index(或其他比如“OMX_ErrorNone”),PV框架将为组件功能赋默认值。

3)调用OMX_GetParameter,针对视频组件再调用“OMX_IndexVideoInit”,针对音频组件则调用“OMX_IndexAudioIni”以获取可用的端口号。

4)循环查找可用的端口号以找到输入端口。

5)循环查找可用的端口号以找到输出端口。

注意:
Index “PV_OMX_CAPABILITY_TYPE_INDEX” is defined as:
#define PV_OMX_COMPONENT_CAPABILITY_TYPE_INDEX 0xFF7A347
The OMX_GetParameter call expects the following structure to be filled for this index:
typedef struct PV_OMXComponentCapabilityFlagsType
{
// OMX COMPONENT CAPABILITY RELATED MEMBERS
OMX_BOOL iIsOMXComponentMultiThreaded;
OMX_BOOL iOMXComponentSupportsExternalOutputBufferAlloc;
OMX_BOOL iOMXComponentSupportsExternalInputBufferAlloc;
OMX_BOOL iOMXComponentSupportsMovableInputBuffers;
OMX_BOOL iOMXComponentSupportsPartialFrames;
OMX_BOOL iOMXComponentUsesNALStartCode;
OMX_BOOL iOMXComponentCanHandleIncompleteFrames;
OMX_BOOL iOMXComponentUsesFullAVCFrames;
} PV_OMXComponentCapabilityFlagsType;

功能参数的默认值:
1)iIsOMXComponentMultiThreaded ——默认值OMX_TRUE。
OMX组件一般运行与独立的线程(与PV框架线程不同),有可能将OMX组件集成进PV框架线程(e.g.,通过同步调用)。

2)iOMXComponentSupportsExternalOutputBufferAlloc ——默认值OMX_TRUE。
OMX规范要求OMX组件支持外部分配输出缓冲(就是输出缓冲的OMX_UseBuffer调用)。
如果组件不支持,必须通知PV框架,以便其调用“OMX_AllocateBuffer”代替。

3)iOMXComponentSupportsExternalInputBufferAlloc ——默认值OMX_TRUE。
OMX规范要求OMX组件支持外部分配输入缓冲(就是输入缓冲的OMX_UseBuffer调用)。
如果组件不支持,必须通知PV框架,以便其调用“OMX_AllocateBuffer”代替。

4)iOMXComponentSupportsMovableInputBuffers ——默认值OMX_TRUE。
如果OMX缓冲是外部分配的,为了提高稳定性和优化性能,可以分离OMX缓冲头部信息(OMX_BUFFERHEADERTYPE)与数据区(“pBuffer”)。换句话说,使OMX缓冲更有“移动性”,当传递一个输入缓冲到OMX组件时,“pBuffer”区域和头部信息不一定指向相同的缓冲区。因此,可以分配更多的数据缓冲在框架中循环工作,只有在需要把缓冲传递到OMX组件时才附加到头部信息去。如果OMX组件要求头部和数据一直指向相同的缓冲,则iOMXComponentSupportsMovableInputBuffers应该被置为OMX_FALSE。

5)iOMXComponentSupportsPartialFrames ——默认值OMX_TRUE。
OMX规范要求OMX组件支持将任意数据打包进OMX缓冲,包括独立单帧、NAL和被拆分到多个缓冲区的解码单元。PV框架支持“OMX_BUFFERFLAG_ENDOFFRAME”标记去组装部分帧。然而,如果OMX组件不支持组装部分帧,也就是OMX组件要求PV框架来组装部分帧并提供给OMX组件完整单帧或NAL,此时iOMXComponentSupportsPartialFrames需要被设置为OMX_FALSE。
注意:设置为OMX_FALSE将影响性能。

6)iOMXComponentUsesNALStartCode ——默认值OMX_FALSE。
这个标志位将影响H264解码。PV框架提供所有信息以重建立H264 NALs(通过OMX缓冲的大小和OMX_BUFFERFLAG_ENDOFFRAME的大小)。因此没有必要由OMX组件解码输出流来获取0x0001的NAL初始代码。如果OMX的H264组件及解码单元需要NAL起始代码,可将iOMXComponentUsesNALStartCode置为OMX_TRUE。

7)iOMXComponentCanHandleIncompleteFrames ——默认值OMX_TRUE。
如果丢失部分数据流(比如数据包丢失),假定OMX组件及解码单元可以解决这个问题。如果不可以,则将iOMXComponentCanHandleIncompleteFrames 设置为OMX_FALSE。当“iOMXComponentSupportsPartialFrames”也被设置为OMX_FALSE时,这点相当重要,因为OMX组件不提供组装部分帧,也就是说PV框架必须提供组装好的frame/NALs,因此需要通知OMX组件不完整的帧数据是否可以传递进来。

8)iOMXComponentUsesFullAVCFrames ——默认值OMX_FALSE。
这个标志位决定AVC解码中使用NAL模式还是frame模式。AVC数据可由以上两种模式提供给OMX组件。默认为NAL模式(设置为OMX_FALSE),此模式下OpenCore框架可以为OMX输入缓冲同时提供完整或者部分AVC NAL。Frame模式下(OMX_TRUE),OpenCore框架积累NAL,并提供给OMX输入缓冲一帧完整的数据。
NAL边界的问起前面讨论过了,此处省略。

 

3 OMX组件输入输出缓冲协商
在任何数据交换前,输入输出缓冲需要进行协商。PV框架需要做以下工作:、
1)调用OMX_GetParameter获取输入端口缓冲参数(最小/实际缓冲数,缓冲区大小等等)
2)检查有效的输入缓冲参数(修改一些参数,比如帧的长度和宽度,以及缓冲区的数目等等)
3)调用OMX_SetParameter函数设置输入缓冲参数
4)调用OMX_GetParameter获取输出端口缓冲参数(最小/实际缓冲数,缓冲区大小等等)
5)检查有效的输出缓冲参数(修改一些参数,比如帧的长度和宽度,以及缓冲区的数目等等)
6)调用OMX_SetParameter函数设置输出缓冲参数

过程如图三(省略)

一些设想:
1)缓冲区尺寸的设想:
对于编码器组件,最终分配的输出缓冲区尺寸可能小于profile/level/target比特率所要求的最大帧尺寸。出于内存消耗考虑,OMX编码器组件应当能够输出frame或NAL的比特流划分到多个输出缓冲区去。老调重弹,最后一个部分缓冲区使用“OMX_BUFFERFLAG_ENDOFFRAME”标记结尾。

对于解码器组件,最终分配的输入缓冲区尺寸可能小于profile/level/target比特率所要求的最大帧尺寸。出于内存消耗考虑,PV框架在适当的时候提供采用“OMX_BUFFERFLAG_ENDOFFRAME”标记结尾的输入缓冲区。如果输入缓冲包含完整帧(H264也可能是NAL单元 )或多帧,“OMX_BUFFERFLAG_ENDOFFRAME”将会用来标记一帧的结尾。如果完整的frame/NAL不能放入一个输入缓冲区,则会被拆分放入多个缓冲区。包含部分信息的缓冲区,“OMX_BUFFERFLAG_ENDOFFRAME”标记位将会被置为0。一帧数据的最后一个缓冲区中“OMX_BUFFERFLAG_ENDOFFRAME”才会被置为1。通过这种做法,组件可以方便的重构一帧数据。

如果OMX解码器组件不兼容组长部分帧,PV框架将负责做这件事情。

2)输入/输出缓冲区数量。
框架或许希望分配比OMX要求更多的的输入/输出缓冲区以提供更优的性能(比如解码器输出缓冲或编码器输入缓冲——缓冲更多的数据可以提高性能)。尽管性能提升了,但无法送到OMX组件去(不太理解,应该还是协商不好的意思)。

4 OMX状态变换 加载->空闲 
如果部分已分配的缓冲区进入空闲状态,缓冲区分配将挂起。在变化过程中,PV框架将“
1)通过“OMX_SendCommand”调用发送命令给OMX组件,将状态由OMX_StateLoaded改变为OMX_StateIdle
2)调用一系列“OMX_UseBuffer” 或者“OMX_AllocateBuffer”通知OMX组件。这些调用使用NumInputBuffer记录输入输入端口的数目,使用NumOutputBuffer记录输入输入端口的数目。
3)等待OMX组件的EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)

一些设想与推荐参数:
根据OMX规范,兼容的OMX组件必须同时支持OMX_UseBuffer 和 OMX_AllocateBuffer调用。然而,出于一些内在原因,完全实现是不可能的,组件应当通知PV框架其所具有的功能。

推荐将INPUT缓冲分配在OMX组件外部,这样可以减少额外的内存拷贝(也就是说输入缓冲使用OMX_UseBuffer)。

5 变换到“执行”状态与数据交换
状态变化到执行时才开始真正处理数据。本步骤中,PV框架将:
1)通过“OMX_SendCommand”调用发送命令给OMX组件,将状态由OMX_StateIdle改变为OMX_StateExecuting。
2)等待OMX组件的EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。
3)通过OMX_EmptyThisBuffer调用将输入缓冲发送给OMX组件,通过OMX_FillThisBuffer调用将输出缓冲发送给OMX组件,组件使用合适的回调函数返回缓冲区。

过程如图5

 

注意:
1)在任意时刻OMX组件如果拥有所有输入缓冲区(也就是所有的输入缓冲都通过EmptyThisBuffer调用传给了OMX组件),此时将不能再传递任何输入缓冲区给OMX组件,知道OMX通过EmptyBufferDone释放一个缓冲。对于输出缓冲区同样。

2)如果PV框架没有及时将缓冲区发给OMX框架,OMX组件不会多次返回同一个缓冲区(也就是一旦OMX框架返回一个缓冲区,只有PV框架再次调用这个缓冲,OMX组件才可使用)。这是OMX缓冲交换APSs所规定的基本规则。

6 暂停
PV框架常见的功能包括暂停和恢复,PV框架将:
1)通过“OMX_SendCommand”调用发送命令给OMX组件,将状态由OMX_StateExecuting改变为OMX_StatePause。
2)等待OMX组件的EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。

PV框架向OMX组件发送暂停命令后,立刻停止发送输入输出缓冲。

有暂停就有恢复,PV框架将:
1)通过“OMX_SendCommand”调用发送命令给OMX组件,将状态由OMX_StatePause改变为OMX_StateExecuting。
2)等待OMX组件的EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。

PV框架的状态恢复到执行后,将恢复发送OMX输入输出缓冲。

过程如图6

7 端口刷新(如果可用)
端口刷新调用一般用于重新配置解码器组件,这样会清空所有数据。在此情况下,PV框架将:
1)通过“OMX_SendCommand”调用发送刷新全部端口指令。
2)等待输入缓冲的输出缓冲的两个EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。

刷新命令来了之后,PV框架立刻停止向OMX组件发送输入/输出缓冲。当组件接收到2个回调函数后,PV框架开始恢复发送输入/输出缓冲。

端口刷新的顺序和通告并不相关。

过程如图7。

为了防止动态端口被重复配置,也可以先于OMX IL用户关闭OMX组件端口调用端口刷新指令。

8 停止/变化到“IDLE”状态
为了停止处理过程,PV框架将:
1)通过“OMX_SendCommand”调用发送命令给OMX组件,将状态由OMX_StatePause改变为OMX_StateIdle。
2)等待OMX组件的EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。

过程见图8。

一些设想:
当命令完成“IDEL”态的回调后,PV框架假设所有输入输出缓冲按照OMX规范要求那样返回。

9 OMX组件状态转换 IDLE->Loaded State和 De-initialization
当PV框架结束与一个OMX组件的所有交互后,将:
1)通过“OMX_SendCommand”调用发送命令给OMX组件,将状态由OMX_StateIdle改变为OMX_StateLoaded。
2)向OMX组件发送一系列“OMX_FreeBuffer”调用。
3)等待OMX组件的EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。使用NumInputBuffer记录输入输入端口的数目,使用NumOutputBuffer记录输入输入端口的数目。
4)对OMX核心执行OMX_FreeHandle调用,释放组件句柄。

流程图见图9

注意:在向OMX组件发送卸载命令之前,PV框架一直在等待OMX组件返回的输入输出缓冲。由于回调的过程的不同步性,一些EmptyBufferDone/FillBufferDone的回调有可能在OMX组件状态由“executing” 到 “idle”之后才到达。

10 OMX Core 卸载
PV框架调用函数OMX_Deinit()。


 

OMX_Init()

没有什么好说的,初始化函数,一定要运行的.

 

OMX_GetHandle

得到某一个组件的句柄

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_GetExtensionIndex

除了标准OMX_INDEXTYPE中定义的以外,返回用户自定义的一些参数(第二个参数)对应的index(第三个参数,用在OMX_SetParameter...里面),用来configur或者parameter.

这些参数往往被定义在用户特殊的extension interface里面

 

#define OMX_GetExtensionIndex(                              /
        hComponent,                                         /
        cParameterName,                                     /
        pIndexType)                                         /
    ((OMX_COMPONENTTYPE*)hComponent)->GetExtensionIndex(    /
        hComponent,                                         /
        cParameterName,                                     /
        pIndexType)                     /* Macro End */

 

 

 

OMX_SetParameter

设定某个参数对应的值

#define OMX_SetParameter(                                   /
        hComponent,                                         /
        nParamIndex,                                        /
        pComponentParameterStructure)                        /
    ((OMX_COMPONENTTYPE*)hComponent)->SetParameter(         /
        hComponent,                                         /
        nParamIndex,                                        /
        pComponentParameterStructure)    /* Macro End */

 

 

 

OMX_SetConfig

设定某个config值

#define OMX_SetConfig(                                      /
        hComponent,                                         /
        nConfigIndex,                                       /
        pComponentConfigStructure)                           /
    ((OMX_COMPONENTTYPE*)hComponent)->SetConfig(            /
        hComponent,                                         /
        nConfigIndex,                                       /
        pComponentConfigStructure)       /* Macro End */

 

注意有时候,需要先停止某个组件(的某些端口),才能设置config 成功

 

OMX_SendCommand

 

一般的命令有:

OMX_CommandStateSet 、OMX_CommandFlush、OMX_CommandPortDisable" 、 "OMX_CommandPortEnable、CommandMarkBuffer

 

#define OMX_SendCommand(                                    /
         hComponent,                                        /
         Cmd,                                               /
         nParam,                                            /
         pCmdData)                                          /
     ((OMX_COMPONENTTYPE*)hComponent)->SendCommand(         /
         hComponent,                                        /
         Cmd,                                               /
         nParam,                                            /
         pCmdData)                          /* Macro End */

 

 例子:OMXSAFE(OMX_SendCommand(vrenderer, OMX_CommandPortEnable, 1, 0)); // 停下1对应的端口

 

OMX_SetupTunnel

将两个组件连接起来,实际会引起调用每个组件的ComponentTunnelRequest

 

OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_SetupTunnel(
    OMX_IN  OMX_HANDLETYPE hOutput,
    OMX_IN  OMX_U32 nPortOutput,
    OMX_IN  OMX_HANDLETYPE hInput,
    OMX_IN  OMX_U32 nPortInput);

 

例子:

OMXSAFE(OMX_SetupTunnel(reader,   0, vdecoder,  0)); // reader的0端口为出,vdecoder的0端口为入,连接成一个Tunnel

 

 

准备好后,就可以设置OMX_StateExecuting,来让这个流程活动起来了。

 

再以后,就可以通过OMX_StateIdle 来停下。

 

OMX_GetState

 

#define OMX_GetState(                                       /
        hComponent,                                         /
        pState)                                             /
    ((OMX_COMPONENTTYPE*)hComponent)->GetState(             /
        hComponent,                                         /
        pState)                         /* Macro End */

 

 一些新补充:

 

1:

OMX_PARAM_PORTDEFINITIONTYPE decOutputPortDef;

   INIT_PARAM(decOutputPortDef);
    decOutputPortDef.nPortIndex = 0;

    err = OMX_GetParameter(pCtx->hReaderComp,
                           OMX_IndexParamPortDefinition,
                           &decOutputPortDef); // 利用IndexParamPortDefinition来得到组件的输出端口的属性

 

    videoWidth = decOutputPortDef.format.video.nFrameWidth; 
    videoHeight = decOutputPortDef.format.video.nFrameHeight;

 

2:OMX_BUFFERHEADERTYPE *pOmxBufferHeader ;

// tell decoder output port that it will be using our buffer

        err = OMX_UseBuffer(hDecodeComp,
                            &pOmxBufferHeader,  //out
                            OMX_DECODE_OUTPUT_PORT,
                            NULL,
                            outSize,
                            (NvU8*)pOut);

 

 将分配好的pOut指针和他的大小outSize,配成一个OMX_BUF, 并给pOmxBufferHeader,这样就通过OMX_UseBuffer,来得到一个以后能给他用的Buffer,指针用我们分配的。

 

3:

 

 OMXErr = OMX_FillThisBuffer(hDecodeComp, pOmxBufferHeader);

 

让hDecodeComp将pOmxBufferHeader的数据准备好(就是输出数据),pOmxBufferHeader就是通过UseBuffer来组装的。

 

通过nFilledLen,可以得到具体数据填充情况。

如果OMX_FillThisBuffer是异步函数的话,那真正的返回是要靠:Callback_FillBufferDone 来设置真正数据ready信号

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android OMX介绍(总括) 的相关文章

  • ImageView 中的全尺寸图像

    我正在尝试在 ImageView 中绘制图像 但我希望它不缩放 并根据需要使用滚动条 我怎样才能做到这一点 现在我只有一个可绘制集作为 XML 中 ImageView 的 android src 这会自动缩放图像以适应屏幕宽度 我读到这可能
  • 为什么 Kotlin 数据类可以在 Gson 的不可空字段中包含空值?

    在 Kotlin 中你可以创建一个data class data class CountriesResponse val count Int val countries List
  • 如何改变android中menuItem的背景颜色?

    我正在以编程方式将菜单项添加到菜单中 我想在选择特定项目时添加背景颜色 如何为 menuItem 添加背景 您的回答将不胜感激 虽然其他答案提供了更改样式 这会影响all菜单项 据我了解 需要更改一个菜单项 我建议你使用android ac
  • 更改工具栏中汉堡图标的大小?

    我有两个问题 可能很奇怪 但无论如何 我有带有应用程序标题的工具栏 如何将其更改为非徽标的图片 下一个问题 是否可以设置 更改工具栏中汉堡图标的大小 我在下面的下一个代码的帮助下制作了经典的导航抽屉 我也使用了 ActionBarDrawe
  • android 谷歌+登录定制

    我正在创建一个 Android 应用程序 现在我正在实现社交网络登录 Facebook 按钮很好 但 google 按钮的语言与 Facebook 不同 另外 它只说 登录 我想让它说 用谷歌登录 我是 android 编程的新手 看到我需
  • 如何编辑 gradle 依赖项

    我正在开发一个 android 项目 该项目在我的 gradle 文件中使用以下依赖项 compile com mapzen on the road 1 1 1 我想编辑其中一个文件 以添加一些缺少的功能并为该项目做出贡献 如何下载该项目并
  • 无法合并 Dex - Android Studio 3.0

    当我在稳定频道中将 Android Studio 更新到 3 0 并运行该项目时 我开始收到以下错误 Error Execution failed for task app transformDexArchiveWithExternalLi
  • 更改 AChartEngine 中的图例大小

    我想专门更改饼图的图例大小输出 我已经尝试了所有可以找到的 AChartEngine 方法 但没有一个只能更改图例文本大小 我必须重写 onDraw 函数吗 如果是这样 怎么办 要设置图例高度 请使用 renderer setLegendH
  • 无法将 Tesseract OCR 模块添加到 Android Studio

    我按照此处找到的分步指南进行操作 https www codeproject com Articles 840623 Android Character Recognition https www codeproject com Artic
  • Android - 除了普通 SSL 证书之外还验证自签名证书

    我有一个通过 SSL 调用 Web 服务的 Android 应用程序 在生产中 我们将拥有由受信任的 CA 签名的普通 SSL 证书 但是 我们需要能够支持自签名证书 由我们自己的 CA 签名 我已经成功实施了接受自签名证书的建议解决方案
  • layout.xml 的用途是什么?

    人们为什么使用layout xml在他们的resources like
  • 如何在 Android 上的 HttpPost 中发送 unicode 字符

    我试图在我的应用程序中允许多语言支持 这会发出 HTTP post 来上传新消息 我需要做什么才能支持日语和其他非拉丁语语言 我的代码目前看起来像这样 note the msg string is a JSON message by the
  • 在 Android 中使用 iText 读取或打开 PDF 文件

    我是 Android 应用程序开发新手 使用 iText 我完成了 PDF 创建并在创建的文件上写入 现在我想阅读该 PDF 文件 如何使用 iText 打开或阅读 PDF 文件 例子将是可观的 那么提前 哪个是渲染 PDF 文件的最佳库
  • 如何覆盖日期选择器的高度和宽度以填充父布局

    我有一个活动包含一个日期选择器 我想设置DatePicker适合屏幕 我试过这个答案 https stackoverflow com questions 6674667 how to customize date pickers width
  • Facebook LoginActivity 未正确显示

    我有一个使用 Facebook 登录的应用程序 我有 FacebookSDK 并且使用 com facebook LoginActivity 问题是 在 10 英寸平板电脑上 当显示软键盘时 活动无法正确显示 我使用的是 Samsung G
  • 如何从SurfaceView绘制到Canvas?

    我正在尝试做简单的画家 问题是Android看起来有三个独立的Canvas并给我它来顺序绘制 我用以下方式制作了用户界面SurfaceView 把霍尔德从中拿走 Override protected void onCreate Bundle
  • Android应用程序kill事件捕获

    我想在我的应用程序被终止时执行一些操作 可以使用哪种方法来实现此目的 我正在开发 Android 5 0 这个问题的关键在于 您必须了解您的申请是否可以收到任何 当您的应用程序在任何情况下被终止时的额外回调 下面的答案是由德文连线 http
  • Amazon IAP 不会调用 onPurchaseResponse

    我有一个 Android 应用程序 它使用 IAP 我正在发送PurchasingManager initiateGetUserIdRequest 并得到用户识别成功 in onGetUserIdResponse 得到回复后Purchasi
  • 使用支持库中的 BottomSheet 时如何调暗背景?

    怎样才能让背景像显示的那样变暗here https material design storage googleapis com publish material v 8 material ext publish 0Bzhp5Z4wHba3
  • 尝试使用带有有效购买令牌的 Java Google Play Developer API v3 检索应用内购买信息时出现错误请求(无效值)

    当使用 Java Google Play Developer API 版本 3 并请求有效购买令牌的购买信息时 我收到以下异常 API 调用返回 400 Bad Request 响应以及以下消息 code 400 errors domain

随机推荐

  • Ubuntu18.04 安装完成后的开发配置

    Ubuntu18 04 安装完成后的开发配置 1 终端工具2 屏幕录制工具3 屏幕截图工具4 向日葵远程操作与开机自启动设置5 MarkDown笔记工具6 ROS 机器人操作系统安装7 编程开发工具8 机器人仿真环境Gazebo 安装Web
  • Ubuntu 20.04 安装 Latex 并使用 vscode 作为文本编辑器

    Ubuntu 20 04 安装 Latex 并使用 vscode 作为文本编辑器 1 Texlive 下载与安装1 1 镜像文件下载1 2 安装步骤1 3 查看是否安装成功1 4 相关依赖安装 2 安装 windows 字体3 vscode
  • Windows下Keil 4工程默认Keil 5打开的解决办法

    案例背景 xff1a 在安装Keil 4进行51系列单片机学习之后安装Keil 5进阶STM32系列单片机的学习 刚安装完后 xff0c 之前编辑的Keil 4工程还是默认Keil 4打开 xff0c Keil 5的工程默认Keil5打开
  • Python3 利用requests 库进行post携带账号密码请求数据

    span class hljs keyword import span urllib json requests url 61 span class hljs string 39 http 127 0 0 1 8000 account lo
  • Python爬虫 requests使用post请求登录需要验证码的网站

    具体代码为 xff1a import requests span class hljs built in from span bs4 import BeautifulSoup s 61 requests Session get url 61
  • WinSock API网络编程——UDP协议(http://www.impcas.ac.cn/usr/lujun/browse.asp?id=winsock_udp)

    WinSock API网络编程 UDP协议作者 xff1a 陆军 Email xff1a ldlujun 64 163 com 时间 xff1a 2004 11 14UDP协议 xff08 User Datagram Protocol xf
  • Raspberry 静态IP配置

    前言 Raspberry 在使用过程中 xff0c 需要手动设定静态IP地址 xff0c 但是深入下去发现不同的raspberry版本不同 xff0c 设置上也存在差异 etc network interfaces 在之前的文章 Raspb
  • 【硬件】调试经验:串口RS232不通,怎么办

    写作时间 xff1a 2020 07 24 目录 xff1a 1 关键词 2 坑坑坑 xff08 不要跳 xff09 3 小技巧与说明 正文 xff1a 1 关键词 串口 串口助手上位机 usb转232线缆 串口命令 RS232 2 检查点
  • 【Github】git bash无法复制粘贴

    参考教程https www cnblogs com slw0113 p 15602715 html 使用git bash时只能使用手工敲击所有命令 xff0c 非常不方便 1 在屏幕右键打开git bash命令窗口 2 在左上角右键 xff
  • 报错{“msg“:“invalid token“,“code“:401}问题的解决

    报错 msg invalid token code 401 问题的解决 xff1a 解决办法 xff1a 将精确的路由放在最上面 xff0c 模糊的路由放在最下面 xff0c 防止精确的路由被覆盖
  • Android 电池管理系统

    https blog csdn net bhj1119 article details 52947344 Android电池服务的源码结构 Framework base services java com android server Sy
  • eBPF技术介绍

    前言 eBPF起源于linux内核 xff0c 它可以以砂箱程序运行在操作系统内核的特权上下文 xff0c 高效 xff0c 安全 xff0c 易于扩展而不需要修改内核源码或者加载内核模块 操作系统一直是实现观测 xff0c 安全和网络功能
  • eBPF开发工具链

    有几个开发工具链可以帮助开发和管理eBPF程序 它们都满足了用户的不同需求 xff1a bcc BCC是一个框架 xff0c 使用户能够编写嵌入其中的eBPF程序的python程序 该框架主要针对涉及应用程序和系统分析 跟踪的用例 xff0
  • Off-CPU分析

    前言 性能问题可以分为两种类型 xff1a On CPU xff1a 线程花时间在CPU上运行的地方 xff1b Off CPU xff1a 在I O xff0c 锁 xff0c 计数器 xff0c 分页 交换上阻塞等待的时间 Off CP
  • uint8_t / uint16_t / uint32_t /uint64_t数据类型详解

    https blog csdn net bruce 0712 article details 72805903
  • 什么是系统调用?为什么要用系统调用?

    什么是系统调用 Linux内核中设置了一组用于实现各种系统功能的子程序 xff0c 称为系统调用 用户可以通过系统调用命令在自己的应用程序中调用它们 从某种角度来看 xff0c 系统调用和普通的函数调用非常相似 区别仅仅在于 xff0c 系
  • android的surfaceflinger原理学习

    概念 SurfaceFlinger是一个系统服务 xff0c 如 xff1a audioflinger xff0c audiopolicyservice等等 xff0c 系统的主要服务通过这个文章进行了解 xff0c Android的系统服
  • labview界面分隔和自定义窗口大小

    gt gt gt gt gt gt 我的博客目录导航 转自 statemic LabVIEW程序界面的布局 控件的显示效果与监视器是密切相关的 xff0c 因此在程序设计时需要考虑目标监视器的颜色 分辨率等因素 xff0c 并明确运行该应用
  • CAN通信矩阵的理解(CAN报文信号的属性)

    CAN通信矩阵 1 CAN通信矩阵是什么 CAN通信矩阵 xff08 CAN Communication Matrix xff09 通常由整车厂完成定义 xff0c 车辆网络中的各个节点需要遵循该通讯矩阵才能完成信息的交互和共享 我们知道C
  • Android OMX介绍(总括)

    一 OpenMax简介 xff08 缩写为 xff1a OMX xff09 OpenMAX是一个多媒体应用程序的标准 由NVIDIA公司和Khronos 在2006年推出 它是无授权费的 跨平台的C语言程序接口序列 xff0c 这些接口对音