zoukankan      html  css  js  c++  java
  • Android Opencore OpenMAX学习

    Android Opencore OpenMAX学习(1

    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;

    动态加载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 wrongFrame1+Frame2 part

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

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

    2.1 AVC NAL模式与AVC Frame模式
    通过设置iOMXComponentUsesFullAVCFrame标志位,可以决定AVC数据使用哪种模式解码。
    默认使用NAL模式,此种模式下OpenCORE框架同时提供完整单帧和部分帧输入缓冲区。
    Frame模式下,OpenCORE框架积累NALs并提供完整单帧给输入缓冲区。
    OMX_OTHER_EXTRADATA
    结构体用来区分NAL边界。
    如果iOMXComponentUsesFullAVCFrameiOMXComponentUsesNALStratCodes都被置为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模式,包含2NAL,包含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 YUVRGB数据格式Android Opencore OpenMAX学习 - wangshh03 - 王世宏的博客
     
    OMX
    编码组件中,生肉提供YUV或者RGB格式,OpenCORE框架将提供一帧完成的YURRGB数据给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.

    2PV框架列举所有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.,通过同步调用)。

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

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

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

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

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

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

    8iOMXComponentUsesFullAVCFrames ——默认值OMX_FALSE
    这个标志位决定AVC解码中使用NAL模式还是frame模式。AVC数据可由以上两种模式提供给OMX组件。默认为NAL模式(设置为OMX_FALSE),此模式下OpenCore框架可以为OMX输入缓冲同时提供完整或者部分AVC NALFrame模式下(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编码器组件应当能够输出frameNAL的比特流划分到多个输出缓冲区去。老调重弹,最后一个部分缓冲区使用“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)。

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

    过程如图5

    Android Opencore OpenMAX学习 - wangshh03 - 王世宏的博客
     

    注意:

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

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

    暂停
    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

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

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

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

    过程如图7

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

    停止/变化到“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()

    翻译 from openmax_call_sequences.pdf

    来自/external/opencore/doc/omx_core_integration_guide.pdf

  • 相关阅读:
    【玩转开源】制作Docker镜像
    【玩转开源】Linux C 检测网口热插拔
    【玩转开源】BananaPi R2 —— 第四篇 Openwrt Luci 初探
    【玩转开源】BananaPi R2 —— 第二篇 Openwrt 网口配置分析
    .NET Core 中AutoMapper使用配置
    ElementUI 中控件 Select 大数据量渲染处理
    Echart处理X轴显示不全问题
    C#WebAPI中中log4net的配置步骤
    iis7.5 部署WebAPI
    core2.2部署IIS
  • 原文地址:https://www.cnblogs.com/weinyzhou/p/2970295.html
Copyright © 2011-2022 走看看