转载:openmax基本概念

https://yellowmax.blog.csdn.net/article/details/78080168

https://yellowmax.blog.csdn.net/article/details/78242464

https://yellowmax.blog.csdn.net/article/details/78997854

https://wenku.baidu.com/view/18472c1387c24028915fc3e9.html    OpenMax_IL_Bellagio_代码分析_-_台湾清华RTlab实验室_OpenMax_IL_代码分析)

组件

 从上图可以看出组件内部大概有这么几个组成部分:

1.组件句柄(组件的描述符,类似文件描述符一样)。
2.配置相关的结构体方法(set/get parameter/configuration)。
3.命令队列。
4.端口(port)。
5.端口的buffer管理。
6.组件事件句柄(用于向IL Client发送事件)。
7.buffer发送模块。

IL Clinet

顾名思义,IL Client就是指IL的客户端,可以在上图里面看到有IL Clinet的字样,对于组件来说,IL Client就是组件的管理者,Client通过组件内部提供的相关回调函数来对组件进行管理,应用程序可以调用Client的代码来操作组件,包括设置组件的状态、添加一个组件、销毁一个组件等等。

IL Client对组件的操作流程大概如下:

 端口

1.PORT(端口)是用来干什么的?
PORT充当了组件之间数据交流的代理人(驻外大使馆),通过PORT端口,两个组件之间可以互相传递数据,同时也可以进行其它的一些控制。
2.如何通过PORT(端口)来交换数据?
组件之间是可以进行绑定的,在组件绑定完成之后,绑定组件的双方PORT口里面就存放了绑定双方组件的实例化组件句柄以及绑定端口信息等数据,然后通过PORT来调用绑定组件的buffer相关的回调函数,这样就可以实现组件之间互相调用对方的内部方法来实现数据交换(包括数据发送与数据回收)。
3.如何定义一个PORT?
一个PORT的定义需要三个结构体来完成,在OpenMAX标准下,这三个结构体分别是:OMX_PARAM_PORTDEFINITIONTYPE,OMX_VIDEO_PARAM_PORTFORMATTYPE,OMX_PARAM_BUFFERSUPPLIERTYPE,其中第二个结构体是跟组件的PORT端口类型有关的,分别有video、image、audio等类型,这里给出的就是video类型。这三个结构体描述囊括了了PORT类型,端口号,COMP句柄等信息。
4.如何通过PORT建立连接?
调用组件的内部方法进行协商连接(协商建立外交),具体到OpenMAX里面就是OMX_SetupTunnel这个宏定义,在绑定组件的时候需要调用双方组件的这个宏定义,最终可以回调到双方组件内部的一个ComponentTunnelRequest方法来完成组件的绑定(该方法的具体代码内容需要自行实现)。

 两个组件通过port进行相互链接,然后组件内部自行协调进行数据交流。整个链接过程是由组件的管理者连续调用两个组件的链接函数完成的,组件的链接函数里面会判断两个port是否适合链接,如果适合的话就将对方port以及COMP的句柄信息记录下来,存放到一个port结构体描述当中,这样的话两个组件就可以通过port来进行通信以及数据传输了。

组件的事件句柄

组件在初始化的时候会向IL Client注册一个OMX_CALLBACKTYPE类型的回调函数集

里面的三个回调成员由IL Client实现,在组件内部可以通过某种事件触发这三种回调成员的回调,比如EventHandler回调成员就会在组件状态转换完成的时候被回调,其余两个则会在EmptyBuffer,FillThisBuffer操作完成的时候被调用,利用这几个回调函数,IL Client可以接收来自于组件内部的若干消息事件,从而达到某种同步以及接收组件的反馈。

buffer发送模块

1.tunnel模式

 由图中可以看出,如果组件A是数据的提供者,那么完整的一帧数据传递就是:

1.组件A调用组件B(通过PORT端口实现)的OMX_EmptyThisBuffer(B, pBuffer)宏来实现数据从A传递到B。
2.组件B调用组件A(通过PORT端口实现)的OMX_FillThisBuffer(A, pBuffer)宏来完成数据从B到A的还回过程。

2.Non-tunnel模式

 在该模式下,数据传递的双方变为IL Client与组件了,整个过程变成了:

1.IL Client通过OMX_FillThisBuffer(pHandle,1,pBufferOut)向组件A的Output端口提供一个空的buffer结构体以待填充,该宏是通过IL Core来最终完成对A组件的FillThisBuffer回调方法的调用的。
2.然后IL Client向组件A传递一个pBufferIn数据,这时组件A可以对pBufferIn内的buffer数据进行处理,然后处理完毕之后生成的新的buffer数据填充到上一步接收到的空pBufferOut的buffer结构体里。
3.等待组件A将pBufferOut里的buffer填充完毕,组件A就会调用OMX_FillBufferDone(pBufferOut)方法来通知IL Client接收处理后的数据。
4.IL Client数据处理完毕之后就会再次调用OMX_FillThisBuffer(pHandle,1,pBufferOut)来还回buffer到Output列表等待再次填充。
5.组件A处理完接收到的buffer数据之后就会调用OMX_EmptyBufferDone(pBufferIn)方法来通知IL Client,说明组件A已完成接收buffer的数据处理。

组件的状态转换

1.组件状态转换有什么作用?

状态转换用于控制组件运行、暂停、恢复、销毁等等。多个组件同时运行的时候状态转换就可以用来进行多组件之间的数据同步,协调组件之间的工作节奏。
2.由谁来进行状态转换控制,如何去实现控制
状态转换一般是由IL Client调用需要控制的组件的SendCommand来进行状态转换命令的发送,Cmd参数填充OMX_CommandStateSet枚举成员,nParam1参数填充需要转换的命令。当然除了IL Client的控制,组件内部也可能会主动给产生一些状态转换的命令,比如在组件发生严重错误的时候,此时组件内部就需要主动转入Invalid状态。组件内部需要实现OMX_CommandStateSet命令的获取与解析,通常在组件的内部线程里面完成,在接收到该命令之后,组件内部线程需要根据命令指定的状态进行相关的动作。
3.有哪些状态,分别对应什么场景
组件内部有6种状态,分别对应如下:
OMX_StateLoaded:该状态在组件被OMX_GetHandle调用初始化之后就转入,此时相关的buffer资源还没有被分配,IL Client可以使用OMX_SetParameter函数回调来进行参数的设定,使用OMX_SetupTunnel函数进行组件之间的绑定操作,最后控制组件从该状态转入OMX_StateIdle或者OMX_StateWaitForResources状态,后者是在组件尝试分配相关的buffer资源并转入OMX_StateIdle状态失败的时候才转入。
OMX_StateIdle:表明组件所有的资源都已经准备好了,正等待正式运行,该状态下,组件持有buffer,但是不传输也不处理buffer。当组件从OMX_StateExecuting或者OMX_StatePause状态转入该状态时需要归还所有处理完毕的buffer到buffer提供者。
OMX_StateExecuting:该状态下,组件持有buffer,传输同时处理buffer。此时组件应该接受其它组件对该组件的OMX_EmptyThisBuffer与OMX_FillThisBuffer函数回调,同时在非绑定的情况下使用EmptyBufferDone与FillBufferDone来归还Empty以及full buffer。绑定情况下就使用OMX_FillThisBuffer与OMX_EmptyThisBuffer来进行buffer的传递。
OMX_StatePause:该状态下,组件持有buffer,不传输也不理buffer,但是组件不必归还buffer到buffer的提供者。为了避免丢失数据,此时组件可以选择将接收到的数据存放到自己的buffer队列里面,但是不进一步传输也不去处理,当然也可以选择不去存放,这跟组件的具体类型与功能有关系。
OMX_StateWaitForResources:顾名思义,在该状态下,组件正在等待资源被分配并变得可用。通常情况下该状态由组件自己主动转入,原因前面说过,是因为资源分配失败导致。
OMX_StateInvalid:该状态是在组件发生不可修复的错误时转入,此时组件需要产生一个事件,类型为OMX_ErrorEvent,值为OMX_ErrorInvalidState,最后转入OMX_StateInvalid状态,当IL Client接收到该消息的时候就需要调用OMX_FreeHandle来释放所有组件持有的资源。
组件之间的状态转换图如下:

 

posted @ 2020-02-16 15:31  fellow_jing  阅读(572)  评论(0编辑  收藏  举报