【转载】OpenMAXIL介绍与其体系
1 OpenMAX IL介绍与其体系
这一部分的文档描述 OpenMAX IL的特性与体系。
1.1 OpenMAX IL 简述
OpenMAX IL 软件接口层定义了一套API,用于访问系统中的组件。OpenMAX IL软件层的目的:可以对系统中的组件采用不同的初始化值和不同的命令集合;同时还能提供一套统一的命令集合和方法来构建和销毁组件。
1.1.1 体系概览
考虑一个系统要实现四个多媒体处理功能模块,分别标记为 F1, F2, F3, 和F4。这四个功能模块中的任何一个都可能由不同的厂商或者同一个组织的不同部门所开发。每一个功能模块的构建和销毁都可能有不同的要求。同时,每一个模块的配置和数据传输都有不同的方式。 OpenMAX IL API可以将这些功能模块封装成一个组件,既可以每个模块一个组件或者在逻辑上相关的模块组成一个组件。OpenMAX IL API提供一套标准的协议,可以让来自不同的厂商或者组织的组件互相交换数据,同时组件本身也可被另一个组件替换。
与OpenMAX IL API通信的实体称之为IL client, 一般是多媒体框架或者应用层。IL client可以使用 OpenMAX core来加载和卸载组件,在两个组件之间建立通信机制和访问组件的功能函数。
IL client通过IL core和组件之间进行通信。大多数情况下,IL client通过调用IL core所定义的宏来与组件通信,这些宏展开之后就直接调用一个组件的函数。例外情况是,IL client直接调用IL core的函数来加载和销毁组件,建立和撤销组件之间的隧道化连接。
组件代表着多媒体处理的一个单元或者多个单元的集合。尽管这份规范清晰的定义了OpenMAX core的功能,但是具体的功能还是由各个组件提供者负责实现。根据组件输出的参数数据类型的不同,把组件操作的数据类型分为四种:audio 数据,video数据 ,image数据,和其他数据(比如时间或者同步数据)。
通过组件句柄可以访问一个 OpenMAX 组件所提供的一系列标准方法。这些方法允许client取得和设置组件以及组件中port的配置参数,取得和设置组件的状态,给组件发送命令,接收时间通知,分配buffer,和组件的一个port建立通信,以及在两个组件port之间建立通信。
一个OpenMAX组件必须至少有一个port,以满足 OpenMAX 的一致性标准。尽管厂商可能提供一个与OpenMax兼容的,不含有任何port的组件,但是大量的一致性测试都是基于组件含有至少一个port。 OpenMAX所定义的四种类型的port对应于port可能传输的四种数据类型;audio port,video port,image port和其他port。根据port是消费buffer还是生产buffer,可以把一个port分为input类型和output类型。
在一个包含F1,F2,F3,F4四个多媒体处理功能模块的系统中,系统实现者可能会为每一个功能模块提供一个标准的OpenMax 组件,也可以简单的采取任何组合而提供一个组件。组件中的单独功能模块的区分就依赖于组件中的port。
图1-1展现了一些OpenMAX组件的实现方式:
图1-1 OpenMax组件的部分可能实现
1.1.2 关键词汇
本节讲述用于描述OpenMAX IL API的常用缩略语和定义。
1.1.2.1 缩写
表1-1列出了描述 OpenMAX IL API的常用缩写:
缩写词汇 |
含义 |
IPC |
处理器间的通信 |
OMX |
OpenMAX中的函数和数据结构的前缀。比如一个组件可能处于 OMX_StateExecuting的状态 |
表1-1 缩写词汇
1.1.2.2 关键定义
表1-2 列出了用于描述OpenMax API的关键定义:
关键词汇 |
含义 |
Accelerated component |
某一部分功能运行在加速器上的组件。加速组件有自己的特性,比如支持多种类型的隧道化 |
Accelerator |
用于加快某些功能处理速度的硬件 |
AMR |
adaptive multimedia retrieval的缩写,3GGP consortium中的一种adaptive multi-rate编码器 |
Host processor |
多核心系统中用于控制多媒体加速的处理器 |
IL client |
调用OpenMax core或者组件方法的软件层 |
Main memory |
host processor和accelerator所使用的外部内存 |
OpenMAX component |
包装有目标系统所要求的功能的组件 |
OpenMAX core |
与特定平台相关代码,用于定位和加载组件到主存中,同时core也负责从主存中卸载组件,当应用层指明这个组件不再需要的时候 |
Resource manager |
管理硬件资源的软件单元 |
RTP |
real-time protocol的简称,网络标准协议用于传输实时数据,包括音频和视频 |
Synchronization |
同步机制 |
Tunnels/Tunneling |
建立和使用一种标准的数据通道,这个数据通道直接被两个组件所管理。 |
表1-2 关键词汇定义
1.1.3 系统组件
图1-2描述了OpenMAX所支持的多种类型的交流机制。每一个组件可以有任意数目的port用于数据交换。只有一个output port的组件称为source component;只有一个input port的组件称为sink component;组件所有的功能运行在host processor上的称为host component;运行在accelerator上的组件称之为 accelerator component。OpenMAX既可以直接和应用层交流,也可以整合到多媒体框架中去。
接下来描述三种通信机制。Non-tunneled communication 定义了在IL client和组件之间交换数据buffer的通信机制;Tunneling 定义了组件之间直接进行数据buffer交换的标准机制;Proprietary communication描述了两个组件之间直接进行数据交流的机制,
1.1.3.1 Component Profile
OpenMax的组件按照功能分为两类:base profile 和 interop profile。
base profile的组件应该要支持non-tunneled的通信机制。base profile可能支持proprietary communication机制。base profile组件不支持tunneled communication。
interop profile是base profile的超集。一个interop profile组件应该要支持non-tunneled和tunneled communication机制,可能支持proprietary communication机制
interop profile 和base profile最主要的不同点是前者支持tunneled communication机制。base profile的存在主要是为了简化OpenMax实现者的工作。
1.1.4 组件的状态
如图1-3 所示,一个组件可能要经历一系列的状态变化。假设每一个组件的初始状态是unloaded。应用层通过调用OpenMax core的函数来加载组件。与组件之间的直接交流可以使组件变为其他的状态。
当状态变化的时候使用了无效的数据,组件可能会进入到 invalid state。当IL cilent检测到组件处于invalid state的时候,应该对组件进行如下动作:stop, de-initialize, unload, reload。
图1-2描述了从任何状态都可以变迁为invalid state,但是要想退出 invalid state只有通过unload和reload组件。
图1-3 组件状态
当组件状态进入 IDLE state的时候可能会失败,因为在IDLE state下,必须为组件分配好所有的资源。当从LOADED到IDLE转换失败的时候,IL client可能会重试一次,或者将组件的状态变迁为WAIT FOR RESOURCES 。当组件进入WAIT FOR RESOURCES状态,它便向厂商指定的资源管理单元注册,一旦资源变为可用的时候,组件就会收到通知。资源管理单元随后将组件的状态变更为IDLE state。IL client向组件发送的命令控制着除INVALID state以外的其他状态的变化。
IDLE state状态表明组件已经拥有了所有它需要的资源,但是还没有开始处理数据。EXECUTING state表明组件准确接收buffer去处理数据,并且会调用对应的callback。当组件处于PAUSED state 状态的时候,组件保持着处理buffer数据的环境,但是没有处理数据或者交换buffer。从PAUSED状态变化为EXECUTING状态将使组件从上次暂停的地方开始处理buffer数据。从EXECUTING或者PAUSED状态变化为IDLE状态,将会导致丢失buffer处理的环境,这就意味着数据流的处理开始点需要重新指定。从IDLE变化为LOADED将会导致失去可操作的资源,比如通信buffer。
1.1.4 组件体系结构
图1-4描述了组件的体系结构。组件的入口点只有一个(通过组件的具体来访问一组标准函数),但是组件可能有多个向外的调用,这取决于组件有多少个port。每一个组件也会通过event handler来调用IL client的函数。每一个port也会发起对外部函数的调用。每一个port都有一个与之关联的指向buffer header的指针队列。命令函数所发送的命令也在组件内部对应一个命令队列。所有的参数和配置调用,都有一个特有的index和与之关联的数据结构。
图 1-4 OpenMAX IL API组件体系结构
一个port必须支持callback调用到IL client,如果是支持interop profile 的组件,同时还要支持与其他组件的port之间的交流。
1.1.6 通信行为
一旦从 OpenMAX core接收到了组件的句柄,就可以完成组件的配置工作。一旦组件的port配置完毕,每个port指定了其数据格式,并且组件进入合适的状态,就可以与组件进行数据通信调用了,这种调用是非阻塞的。数据通信特定于组件的一个port。IL client通过 OMX_EmptyThisBuffer函数来与Input port进行通信。IL client通过OMX_FillThisBuffer函数来与output port进行通信。在相同的上下文实现中,OMX_EmptyBufferDone或者 OMX_FillBufferDone callback将会在IL client 调用函数返回之前被调用。图1-5显示了相同上下文和不同上下文两种情况下对上述过程的不同实现。注意,IL client不要臆断组件的callback/return的时序。
图 1-5不同的上下文与相同上下文中不同的操作
和组件的数据通信一般直接发生在组件指定的port。每一个port都有一个它应该分配或者使用的组件自定义的最小的buffer数目。一个port将一个buffer header与一个buffer关联。一个buffer header有成员指向了buffer中的数据,并且提供与buffer中内容相关联的元数据。每一个组件port都应该有能力分配它自己的buffer,或者使用预先分配的buffer。
1.1.7 Tunneled Buffer的分配和共享
这节描述tunneling component buffer的分配和buffer共享。对于一个tunnel,一个port提供buffer,它称为supplier port,然后把这些buffer传递给另一个port,这个port称为non-supplier port。在最简单的情况下,supplier 负责分配buffer,然而,复杂点的情况下, tunneling component可以选择复用另外一个组件port的buffer,以避免内存的拷贝和优化内存的使用。这种情况下称之为buffer分享。
任何两个port之间的一个tunnel,代表这两个port之间的依赖关系。buffer分享机制,扩展了这种依赖,以便所有分享同一buffer集的port可以形成一条隐式的依赖链。准确的说,这条依赖链上的一个port分配buffer,其他的port共享这些buffer。
buffer共享在一个组件内实现,然后把这种共享关系传递到另外一个组件。一个non-supplier port不会知道supplier 组件的提供的buffer是自己分配的还是复用的此组件其他port上的buffer。更进一步说,supplier组件也不知道是否non-supplier组件会复用它所提供的buffer。
严格来说,一个组件仅有义务服从它所需的外部语义,并且可以实现这些语义背后的buffer共享。更具体的,外部语义要求一个组件做以下事情:
• 在它的所有supplier port上提供buffer。
• 准确的传达port 上 buffer的要求。
• 使用OMX_EmptyThisBuffer调用将一个buffer从output port传递到input port
• 使用OMX_FillThisBuffer函数调用将一个buffer从input port返回到output buffer。
如果一个组件选择共享buffer,那么它可能需要执行以下操作来满足这些要求:
• 在supplier port上提供复用的buffer。
• 当在port上传达buffer的要求时,准确的记下需要分享buffer 的port的数目
• 在内部使用OMX_EmptyThisBuffer函数调用将一个buffer从一个input port传递到output port,对应的会有一个 OMX_EmptyBufferDone 回调。
1.1.7.1 相关条款
这一节描述在tunneled buffer分配和共享中用到的相关条款。图1-6展示了总的概念图:
图1-6 buffer分配和共享关系的例子
一对tunneling port,主动发起UseBuffer调用的是supplier port。一个 buffer supplier port 并不一定要分配buffer,它可能复用同一个组件内其他port的buffer。图1-6中 port a,c是 supplier port。接收相邻port 的UseBuffer函数调用的port,称之为 non-supplier port。图中b,d是 non-supplier port。
一个port的tunneling port是与之相邻的,共享同一条tunnel的port。port b是port a的tunnelping port。同样的,port a也是port b的tunneling port。
一个allocator port 是一个自己分配buffer的 supplier port。图中只有port a是allocator port。
同一个组件中复用其他port的buffer的称之为 sharing port 。port c是一个sharing port。
至少使用了一条tunnel的组件称之为tunneling component。
一个port的 buffer requirement包括需要的buffer的数目和每一个buffer的size。一个port通过在它的 tunneled port上调用 OMX_GetParameter,可以获得一个 OMX_PORTDEFINITIONTYPE数据结构,这个数据结构表示了buffer的requirement。注意一个port也可以从共享它buffer的port获得buffer requirement而不用调用OMX_GetParameter,因为这两个port可以位于同一个组件内。
1.1.7.2 IL Client Component Setup
为了构建一个tunneling component,IL client 需要遵循以下步骤:
1.加载所有tunneling component,并且在这些组件之间建立tunnel;
2.给所有的组件发送命令,以便组件的状态从loaded state 变为idle state;
如果IL client不按照上述步骤执行,组件可能由于彼此之间的依赖关系而导致永远都不会进入到idle 状态。
1.1.7.3 共享buffer组件从Loaded转变为Idle State
在 OMX_SetupTunnel被调用的时候,将会确认一条tunnel的两个port中哪一个(input或者output)是buffer supplier。因此当一个组件接收命令从loaded转换为idle的时候,它应该清楚的知道它所有的组件的角色:supplier或者 non-supplier 。
当接收命令从loaded转换为idle,组件按顺序执行以下操作:
1.组件确定采取拿一种方式实现buffer共享,遵循以下规则:
a) 组件可以复用buffer采取如下两种方式:复用一个input的buffer到一个或者多个output port上;或者复用一个output的buffer到一个input上。
b) 只有 supplier port才可以复用另一个port的buffer。
c) 当一个组件中有多个output port分享buffer的时候,port的buffer属性为只读。
如图1-7 所示:
图1-7 允许的buffer分享关系
2.组件确定supplier port,以及哪些supplier port是allocator port。只有当一个supplier port不复用同一个组件的non-supplier port的buffer的时候,它就是 allocator port。图1-8中,箭头背向的port是supplier port,箭头指向的port为non-supplier port。一个port指出来的箭头表示共享关系。带有盒子的port代表 allocator port。
3.一个组件按照以下操作给它的每一个allocator port分配buffer:
a) allocator port确定 buffer requirement 根据每一个复用buffer的port。参见下面的A
b) allocator port通过调用OMX_GetParameter来确认每一个tunneled port的buffer requirement。参见条款B
c) allocator port根据自己的buffer requirement,tunneled port的buffer requirement,以及sharing port的buffer requirement来确定应该分配buffer的最大数目。
d) allocator port告知与之tunneling的non-supplier port的实际buffer数目。通过调用 OMX_SetParameter函数,参数OMX_IndexParamPortDefinition,以此来设置nBufferCountActual的合适参数。见条款E
e) allocator port 和每一个与之关联的sharing port共享它的buffer。见条款D
f) 每一个已经分配的buffer,allocator port都要调用OMX_UseBuffer来传递buffer到tunneling port。见条款C
一个组件应该满足以下条款:
A. 确定一个sharing port的requirement的时候,它应该首先在它的tunneled port上调用OMX_GetParameter查询requirement,然后返回它自己的requirements和查询所得的requirements的最大值。
B. 当 non-supplier port 接收 OMX_GetParameter调用,查询它的buffer requirements的时候,non-supplier port应该首先查询所有复用它的buffer的port的requirements,然后返回自己的requirements和查询到的requirements中的最大值。
C. 当一个 non-supplier port接收到它的tunneled port所发起的OMX_UseBuffer调用时,non-supplier port 应该给和自己所在组件的复用它buffer的port共享这个buffer。
D. 在同一个组件上,A和B共享一块buffer,当B复用这块buffer的时候,它应该首先调用 OMX_UseBuffer,把这块buffer传递给它的 tunneled port。
E. 当一个non-supplier port接收到来自它的tunneled port发起的针对OMX_IndexParamPortDefinition 的OMX_SetParameter 调用时,它应该把参数nBufferCountActual传递给任何复用它buffer的port。同样的,每一个 supplier port通过这种方式接收到 nBufferCountActual的时候,应该通过执行OMX_SetParameter (OMX_IndexParamPortDefinition)调用把 nBufferCount传递给它的 tunneled port。通过这种方式,依赖链中实际使用的buffer的数目得以传递下去。
当所有enable的port都得到了他们所需要的buffer的时候,组件可以从loaded状态变为idle状态
1.1.7.4 使用共享内存的协议
当一个input port通过 OMX_EmptyThisBuffer接收一个共享buffer的时候,这个input port可能和一个output port通过以下机制共享这块buffer:
• 在input port 调用 OMX_EmptyBufferDone 作为对它的tunneling port的回复之前,output port在它的tunneling port上调用 OMX_EmptyThisBuffer。
• input port直到所有和它共享buffer的output已经分享了这块buffer之后才调用 OMX_EmptyBufferDone
1.1.7.5 不共享buffer组件从Loaded转变为Idle状态
如果组件不共享内存,比起共享组件的实现,将会减少很多步骤和所遵循的条款。非共享内存组件从loaded转变为idle,按照以下步骤:
1.确定buffer共享实现的方式。在这种case下,不用进行这一步。
2.确定哪一些supplier port是 allocator port。全部都是。
3.按照如下步骤为每一个 allocator port分配内存:
a. 因为没有共享内存,所以不用询问sharing port对buffer的要求;
b. allocator port 通过调用OMX_GetParameter来取得tunneled port对buffer的要求;
c. 根据allocator和与之关联的tunneling port的buffer requirement的最大值,来分配内存;
d. 因为没有内存共享,所以不用向sharing port传递buffer.
e. 对每一块分配的内存,allocator port 在tunneling port上调用 OMX_UseBuffer。
1.1.8 port重连
port重连允许一个tunneled 组件被另一个tunneled组件替换,而不用破环其他的组件。在图1-10,组件B1被组件B2替换。为了达到这点,组件A的output port和组件B的input port首先要通过port 禁止命令设置为不可用。一旦分配的buffer被返回给它们的拥有者并被释放,组件A的output port就可以连接到组件B2。接下来组件B1的output port和组件C的input port也要采取类似的方式禁用。当所有的分配的buffer都返回给它们的拥有者然后被释放,组件C的input port可以连接到组件B2的output port。所有的port可以被允许使用通过发送使能命令。
图1-10 port重连
在某些情况下,比如音频,当重连一个组件到另一个组件的时候,可能希望新组件的数据采取fade-in的方式,而原始的组件的数据采取fade-out的方式(即淡入淡出)。图1-11 说明了这是如何做到的。第一步,组件A发送数据到组件B1,组件B1发送数据到组件C;组件A和组件C都有一个额外的port处于禁用状态。第二步,IL client首先为A和B2建立tunnel,然后为B2和C建立tunnel。然后使能两条tunnel上的所有port。假设组件C是audio组件,那么C就可以将组件B1和B2的数据采用变化的增益参数进行混合。在第三步,从组件A和C连接B1的port被禁用。
图1-11 重连组件
图1-11 重连组件
1.1.9 命令队列和buffer刷新
组件内独立的命令队列可以使组件刷新那些还没有处理的buffer,把它们归还给IL client,当采取 non-tunneled通信机制的时候,或者归还给与之关联的tunneled port,当采取的是tunneled通信机制。图1-12 假设组件有一个port使用了IL client分配的buffer。在这个例子中,client发送了5块buffer给组件,在发送刷新命令之前。当组件处理刷新命令的时候,会按照原始的顺序把未处理的buffer返回给client,然后触发它的 event handler 发送event通知client。在接收到刷新命令之前,已经处理了两块buffer。连同为处理的三块buffer,组件会按照接收顺序,全部返还给client。
图1-12 刷新buffer
1.1.10 标记Buffer
IL client也可以通过标记buffer触发产生一个事件。在一个buffer的buffer header中可以标记这块buffer。在OpenMax的组件链中,标记从一个input port传递到一个output port。标记允许一个组件发送一个事件给IL client,当这个组件遇到一个标记buffer。图1-13 解释了这个过程:
图1-13 标记buffer
IL client发送一条命令标记一个buffer。组件的output要发送的下一个buffer被标记,图中为B1。组件B处理B1的数据,然后把结果填入到B2,同时还带上标记。当组件C通过它的input port接收到B2,组件不会触发它的event handler,直到它已经处理完毕这块buffer。
1.1.11 事件和callback
组件发送给IL client 6种事件:
• 错误事件
• 命令处理完成通知事件
• 标记buffer事件
• port设置变化通知事件
• buffer flag 事件,当遇到流的结尾
• 资源请求事件,当组件等待它所需要的资源的时候
1.1.12 Buffer Payload
port的配置定义了port上传输的buffer的数据格式,但是配置并没有说明数据在buffer中是如何存放的。一般来说有三种case来描述一块buffer如何被数据填充,这三种case都有各自的好处。在三种case中,buffer中有效数据的范围和起点由buffer header中的pBuffer,nOffset,和nFilledLength三个参数来决定。pBuffer指向buffer中有效数据的起始点。nOffset表示buffer 起始点到有效数据起始点的偏移量。nFilledLength表明有效数据的长度。因此buffer中有效数据位于 pBuffer +nOffset 到 pBuffer + nOffset + nFilledLength的范围内。下面的case,描述了在解码或者编码中,buffer中的压缩数据流进或者流出一个组件。在所有的case下,buffer只是为数据的传递提供了一种机制,而对buffer中的内容没有特殊的要求。对于数据的要求定义在port的配置中。buffer中的阴影部分表示数据,空白部分表示没有数据。case 1:buffer被部分或者全部填充。在这种case下,buffer中含有压缩数据帧,使用f1到fn来标记。
case 1为播放解码数据提供了便利。一个buffer可以含有多个帧,减少了为了达到解码所要求的数据量而导致的buffer传递的次数。然后,这种情况下,需要decoder自己去buffer中解析帧数据。同时组件需要有一个帧buffer,这个buffer中存放解析数据或者存放一部分的帧数据,因为完整的帧数据可能存在于下一个buffer中。
case 2 每一个buffer中填充的是完整的帧。
case 2和case 1不同,因为case 1可能只含有一帧的部分数据。共同点都是需要解码器从buffer中分析出一块帧数据。
case 3 每一块buffer都只含有一帧完整的数据。
case 3的好处是不需要解码器解析帧数据了,解析帧数据的工作放在了 source component。但是每次只能传输一帧数据也可能会对性能造成很大的冲击。
作为基本的要求,解码器或者编码器都应该支持case 1.
1.1.13 Buffer Flags和时间戳
Buffer flags 表示着buffer数据中的某些属性。时间戳描述着buffer中的数据在显示时候的时间信息。一旦一个buffer的时间戳被 clock component组件所确定,任何的组件都不能为了速率控制或者同步而修改这个值。
Buffer中的元数据(即标志和时间戳),适用于buffer中的第一个新的逻辑单元。因此,对于一个buffer中含有多个逻辑单元,buffer的元数据适用于buffer起始边界以后的逻辑单元。除非另有说明,否则当一个组件接收到标记了flag或者时间戳的逻辑输入单元,它应该将这些元数据复制到逻辑输出单元中去。
1.1.14 同步
通过clock component的同步port可以到达同步的目的。clock component和它的port被划分在 其他组件中。clock component内部含有一个根据audio或者video的参考时钟来记录流媒体播放位置的多媒体时钟。clock component可以通过同步port传输带有时间信息的buffer到client 组件。client组件可能给某个操作打上时间戳(例如一个视频帧的呈现),通过请求clock component发送时间戳信息,来匹配媒体时钟。图1-14 展示了这一过程:
1.1.15 速率控制
clock component通过提供一系列的配置来改变媒体时钟,以此实现所有的速率控制。IL client可以通过改变媒体时钟的比例系数(有效的改变媒体时钟变化的方向和速度),来实现播放,快进,暂停,后退,以及慢放。IL client也可以通过这些配置来启动或者暂停媒体时钟,以此来改变媒体时钟的状态。clock component通过在同步port上发送带有新的比例系数和媒体时钟状态的媒体时钟变化通知,来告知所有的client组件,媒体时钟的比例系数和状态发生了变化。尽管一个组件可能并不会以改变buffer的时间戳来应对媒体时钟比例系数的变化,但是它可能改变它相应的处理。
1.1.16 组件注册
静态链接或者动态加载。
1.1.17 资源管理
这一节描述OpenMax IL 中用于资源管理的API。
1.1.17.1 资源管理的必要
当一个组件因为缺少资源而不允许变迁为idle状态时,IL client没有必要知道缺少的资源,也没有必要知道是哪一个组件在使用这些资源。
OpenMAX的一个目标是通过提供IL 层,是IL 层以上的软件层与硬件无关。通过指定下面这些关于资源管理的条款,以使OpenMax达到与硬件无关。
• 一个IL client没有必要知道IL 实现的细节或者IL 组件在使用哪一种资源
• 如果发生资源冲突,IL client能够依赖组件的一致行为而不用管IL的实现和具体的硬件平台
• 一个IL client不应该和硬件厂商的资源管理器直接交互,有以下两个原因:
• 和硬件无关原则相违反
• 和硬件资源管理器的具体工作大多数都是由IL client来处理,这会影响IL client在多种多媒体平台上的表现
虽然资源管理在 OpenMAX IL API 1.0版本中解决,但是作为资源管理的“钩子”已经以行为准则,组件的优先级,资源管理相关的组件状态而落实。这些钩子将会使在以后的版本中全面解决资源管理奠定基础。
在继续之前,资源管理和政策的定义会使下面的讨论收益:
• Resource management负责组件访问有限的资源。一个资源管理者要知道,当前有多少具体的资源可用,当前使用资源的组件,当前的组件使用了多少资源。一个资源管理器应该制定策略,当资源发生冲突的时候,哪一个组件可以优先使用。
• Policy 负责管理组件链。根据 resource managemen提供的信息,或者系统配置,或者应用层的请求,或者其他的因素,策略管理者应该能够决定哪一个组件链可以运行或者恢复运行。
1.1.17.2 体系假设
下面有两种关于 OpenMAX IL层的体系假设:
假设1:在应用层和 OpenMAX IL之间存在一个framework层,包含有策略管理者。
假设2:一个系统可能有多个硬件平台供OpenMAX 组件使用,这些硬件平台由硬件厂商指定的资源管理者管理。
1.1.17.3 组件优先级
每一个组件有一个由IL client设置的优先级(OMX_U32整形)。具体的优先级的范围可以留给平台去实现,但是优先级的目的是很重要的,并且能够在不同的IL 实现上表现一致。组件的优先级按照数值从高到低越来越重要,0表示最高优先级。当两个组件拥有相同的优先级,最近被拥有过资源的组件被认为具有较高的优先级。
1.1.17.4 行为规范
在IL 层定义了如下行为规范:
• 只有当一个组件进入idle状态没有足够的资源或者一个组件不能释放占用的资源,将会产生OMX_ErrorInsufficientResources错误。
• 当组件进入idle状态的时候,它并不知道已经有人抢占了资源,或者低优先级的组件需要释放资源。
• 一个组件已经占据了的资源被抢占,当它从Executing或者Paused进入Idle的时候,要发送OMX_ErrorResourcesPreempted 给IL client,或者当它从Idle进入Loaded的时候,要发送 OMX_ErrorResourcesLost给IL client。
• 如果IL client想知道什么时候与组件相关的流可以启动或者恢复,它就应该请求得到一个通知,当组件的资源变为可用的时候。当把组件的状态置为OMX_StateWaitForResources state,当资源可用,client就会收到通知。
1.1.17.5 硬件厂商相关的资源管理
为了实现上述规范,需要一个位于IL层之下与硬件厂商相关的资源管理者执行下面的功能:
• 实现管理等待队列
• 记录可利用的资源
• 记录使用资源的组件,以及他们使用的是什么资源
• 当一个高优先级的组件需要资源的时候通知一个或者多个组件释放他们所占用的资源
【转载】OpenMAXIL介绍与其体系的更多相关文章
- OpenMAX IL介绍与其体系
1 OpenMAX IL介绍与其体系 这一部分的文档描写叙述 OpenMAX IL的特性与体系. 1.1 OpenMAX IL 简述 OpenMAX IL 软件接口层定义了一套API.用于訪问系统 ...
- 转载 VPN介绍
转载原地址: http://aajs800.blog.51cto.com/519255/239724 原作者 aajs800 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者 ...
- [转载]Scikit-learn介绍几种常用的特征选择方法
#### [转载]原文地址:http://dataunion.org/14072.html 特征选择(排序)对于数据科学家.机器学习从业者来说非常重要.好的特征选择能够提升模型的性能,更能帮助我们理解 ...
- [转载]Masonry介绍与使用实践(快速上手Autolayout)
原博地址 http://adad184.com/2014/09/28/use-masonry-to-quick-solve-autolayout/ 前言 1 MagicNumber -> aut ...
- 转载 WebBrowser介绍——Javascript与C++互操作
注:本文来自于 http://www.cnblogs.com/lucc/archive/2010/11/24/1886087.html WebBrowser控件是Microsoft提供的一个用于网页浏 ...
- 转载:简单介绍Python中的try和finally和with方法
用 Python 做一件很平常的事情: 打开文件, 逐行读入, 最后关掉文件; 进一步的需求是, 这也许是程序中一个可选的功能, 如果有任何问题, 比如文件无法打开, 或是读取出错, 那么在函数内需要 ...
- 转载 GUID介绍
转载 http://www.cnblogs.com/illele/archive/2008/02/25/1080554.html GUID(Global unique identifier)全局唯一标 ...
- 【转载】介绍“Razor”— ASP.NET的一个新视图引擎
最近在做一个项目,用的MVC razor 视图,因为之前没用这个视图做过,于是查阅文档资料,共享一下. https://msdn.microsoft.com/zh-cn/ff849693 内容主要是讲 ...
- 转载:介绍AD另外一种奇葩的多通道复用的方法
原文链接:http://www.eda365.com/forum.php?_dsign=74fe4957&mod=viewthread&page=1&tid=110710 在设 ...
随机推荐
- MDK5.13新建工程步骤
http://www.stmcu.org/module/forum/thread-600249-1-1.html 本人也是接触stm32没多久,之前用的MDK是5.1,现在用的是5.13,MDK5.0 ...
- tf.slice函数解析
tf.slice函数解析 觉得有用的话,欢迎一起讨论相互学习~Follow Me tf.slice(input_, begin, size, name = None) 解释 : 这个函数的作用是从输入 ...
- 倍增求lca模板
倍增求lca模板 https://www.luogu.org/problem/show?pid=3379 #include<cstdio> #include<iostream> ...
- cin.getline()与getline()
C++中有两个getline函数, cin.getline()与getline() 这两个函数相似,但是 这两个函数分别定义在不同的头文件中. cin.getline()属于istream流,而 ...
- 小程序 mcrypt加密拓展在php7.1 废弃 使用openssl替代方案
原加密方法 使用mcrypt //获得16位随机字符串,填充到明文之前 $random = $this->getRandomStr(); $text = $random . pack(" ...
- CodeForces - 999C
You are given a string ss consisting of nn lowercase Latin letters. Polycarp wants to remove exactly ...
- node、npm及node_modules中依赖的版本更新
好久没用node了,想重新拾起来发现node还有相关模块的版本都太低了,使用npm install全是报版本低的警告. 这里记录一下,版本管理和node_modules更新的方法. 我用的是Windo ...
- canvas h5制作写字板
<!DOCTYPE html><html><head> <meta charset="utf-8"> <script type ...
- flask插件系列之flask_celery异步任务神器
现在继续学习在集成的框架中如何使用celery. 在Flask中使用celery 在Flask中集成celery需要做到两点: 创建celery的实例对象的名字必须是flask应用程序app的名字,否 ...
- 前端nginx时,让后端tomcat记录真实IP【转】
对于nginx+tomcat这种架构,如果后端tomcat配置保持默认,那么tomcat的访问日志里,记录的就是前端nginx的IP地址,而不是真实的访问IP.因此,需要对nginx.tomcat做如 ...