OpenMAX——数据格式OMX输入缓冲

news2025/1/13 13:18:10

开放多媒体加速层(英语:Open Media Acceleration,缩写为OpenMAX),一个不需要授权、跨平台的软件抽象层,以C语言实现的软件接口,用来处理多媒体。它是由Khronos Group提出的标准,也由他们来维持,目标在于创造一个统一的接口,加速大量多媒体资料的处理。

1、数据格式和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[4i] = size of the i-th NAL (data is declared as byte array – so offset is 4i, 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组件,组件使用合适的回调函数返回缓冲区。

注意:

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输入输出缓冲。

7 端口刷新(如果可用) 端口刷新调用一般用于重新配置解码器组件,这样会清空所有数据。在此情况下,PV框架将:

1)通过“OMX_SendCommand”调用发送刷新全部端口指令。 2)等待输入缓冲的输出缓冲的两个EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。

刷新命令来了之后,PV框架立刻停止向OMX组件发送输入/输出缓冲。当组件接收到2个回调函数后,PV框架开始恢复发送输入/输出缓冲。端口刷新的顺序和通告并不相关。

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

8 停止/变化到“IDLE”状态 为了停止处理过程,PV框架将:

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

一些设想: 当命令完成“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调用,释放组件句柄。

注意:在向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 */

以上就是OpenMAX中的——数据格式及OMX输入缓冲细节解析,更多音视频核心技术学习参考《音视频精通学习笔记》;音视频开发很难必须需要系统性的学习,网上的音视频资料很多大多数比较杂乱,没有比较全面的因此。我从音视频开发网易大牛手上拿到这份笔记。按照音视频高工所记录的笔记,希望能够帮助到大家。

补充:

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信号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/94286.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[整型/浮点型二分算法详解]二分查找算法真的很简单吗

🏖️作者:malloc不出对象 ⛺专栏:《初识C语言》 👦个人简介:一名双非本科院校大二在读的科班编程菜鸟,努力编程只为赶上各位大佬的步伐🙈🙈 目录前言一、二分查找是什么二、二分查找…

html大作业【NBA篮球介绍 22个页面】学生网页设计源码

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…

python教你如何跳过验证识别登录并自动发送弹幕

前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 开发环境: Python 3.8 Pycharm 2021.2 谷歌浏览器 谷歌驱动 模块使用: selenium >>> pip install selenium3.141.0 指定版本安装 time 打码平台 安装python第三方模块: win R 输…

程序猿的福音——猿如意使用有感

猿如意介绍: 猿如意是一款面向开发者的辅助开发工具箱,包含了效率工具、开发工具下载,教程文档,代码片段搜索,全网博文搜索等功能模块。帮助开发者提升开发效率,帮你从“问题”找到“答案”。 猿如意的下…

KEIL5软件仿真支持的器件

问题的提出 用KEIL进行软件仿真,想观察一下处理器STM32F091RCY的I2C和DAC引脚输出的波形,发现无法向波形中添加信号,如下图所示 当在命令行中输入 dir vtreg 指令时,仅仅能够显示内核的寄存器,外设的寄存器无法输出&a…

【DevOps实战系列】第九章:详解Sonarqube搭建及集成Jenkins环境

个人亲自录制全套DevOps系列实战教程 :手把手教你玩转DevOps全栈技术 质量安全审计:Sonarqube Sonarqube(声呐)大家应该不陌生,通过扫描代码分析代码质量与代码安全,方便我们快速定位代码缺陷、潜在风险。 个人建议:…

希尔贝壳邀您参加 ISCSLP 2022 Program

第十三届中文口语语言处理国际会议将于2022年12月11-14日(本周日~下周三)正式开启,本次会议中的部分Session将通过语音之家视频号进行线上直播,欢迎大家参加! 官网:www.iscslp2022.org 大会简介 中文口语…

别再秃头背锅了,这个小技巧统计第三方接口耗时很安逸

前言 之前我有写过一篇记录生产环境事故的文章,获得了不少好评。 后续,我们团队有做过一些讨论,为了支撑运营维护,搭建了更好的日志平台 GranfaLoki,也引入了 SkyWalking 做链路追踪。 但过程中也遇到了一些问题&#…

30多个Flatsome主题优秀电商网站案例

想知道您可以使用 WordPress Flatsome WooCommerce主题(最畅销的电子商务主题之一)制作什么样的网站吗? 我们已经浏览了使用这个非常受欢迎的电商主题尽可能多的案例(近1000个),并汇总了30个Flatsome主题优…

windows安装es、kibana教程

目录 前言 第一个部分:安装ES的包 1.安装成功的截图 2.下载es的安装包 3.检查本地的jdk的安装是否存在问题 4.修改config文件夹下面的配置 第二部分:windows 安装Kibana可视化工具 1.下载安装包 2.安装过程中遇到的问题 3.安装6.0.0的版本是可以…

【Android】BlueTooth开发记录

Ble开发中,存在着两个角色:中心设备角色和外围设备角色。 外围设备:一般指非常小或者低功耗设备,更强大的中心设备可以连接外围设备为中心设备提供数据。外设会不停的向外广播,让中心设备知道它的存在。 例如小米手环。中心设备:可…

学习周报-20221216

文章目录一 centos6和centos7系统的服务启动与关闭二 Linux下的/etc/pam.d/system-auth配置文件参数各列参数说明1)第一列2)第二列3)第三列和第四列常用类说明三 Linux用户密码过期策略一 相关文件二 修改密码三 设置密码过期策略四 Linux中使…

将渲染计算搬到云端,开启低成本、强交互、沉浸式体验

云渲染可以解放本地计算需求,这意味着生产力的大幅提升。 云渲染的基本原理是将3D渲染应用部署到云端,接收本地的控制指令发送到云端,云端启动游戏引擎并进行画面渲染,编码成视频流传输到本地。 不难看出,云渲染技术的…

3节点Fate集群实战记录(全网最详细)--横向联邦学习

集群配置 集群的三台服务器分别部署了fate-10000, fate-9999, fate-9998命名空间,集群的具体部署情况请转:link查看。 文章后面以命名空间名来区分操作所在的节点(注意节点的实际名字不等于命名空间名)。集群的配置信息如下&…

【嵌入式开源库:cJSON】 一个轻量级C语言JSON数据解析库用法详解

cJSON简介 cJSON是使用C语言编写,用来创建、解析JSON文件的库。cJSON特点就是工程文件简单,只有一个.c和一个.h,但提供函数接口功能齐全,麻雀虽小五脏俱全,使得在嵌入式工程中使用起来得心应手。 cJSON获取 https:/…

小程序本地 存储/获取值以及删除本地的值

场景:小程序本地存储的方法 wx.setStorageSync:直接给定key和value值 wx.setStorage:需指定key及value,然后再指定相应的值 小程序获取本地值的方法 wx.getStorageSync:直接指定key值获取到对应的数据 wx.getStorage&a…

Node.js模块系统的实现机制简析

目录nodejs模块系统简介C版native模块的定义和加载加载过程JavaScript接口层万能的binding机制JavaScript版native模块的定义和加载js2c技术NativeModule的工作原理Node启动时构造NativeModule对象,完成name到source的映射懒加载机制总结nodejs模块系统简介 Node.j…

[附源码]Nodejs计算机毕业设计基于的校园商城Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置: Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分…

Linux系统编程2——进程介绍

文章目录前言一、程序和进程二、并行和并发三、进程控制块PCB进程状态四、创建进程相关函数1、fork函数fork函数总结2、getpid/getppid3、exec函数族3.1、execl函数3.2、execlp函数3.3、exec函数族原理介绍五、进程回收1、为什么要进行进程资源回收2、孤儿进程3、僵尸进程4、进…

传奇GEE引擎版本架设

传奇GEE引擎版本架设 我是艾西今天给大家分享下传奇GEE引擎版本的架设教程 (仅做参考,以下内容为显示素材打码部分请读者理解遵守平台GZ) 传奇GEE引擎版本我们架设游戏需要用到的工具: 版本(游戏类型服务端&#xf…