简介
Codec HDI 提供了基于OpenMax(简称OMX)的一整套编解码接口,程序通过简单的几步,即可实现基于OMX的硬件编解码。本文主要介绍基于Codec HDI 开发的编解码功能,包括初始化,Buffer流转以及释放等。
CODEC HDI框架介绍

Codec HDI Interface (简称HDI)提供基于OpenMax 的标准接口,Media Service 调用这套接口实现硬件编解码能力。HDI 另外提供了实现Callback 机制的接口,Media Service 可以通过HDI 接口创建Callback 信息接收服务端(Codec HDI Callback Remote Service),并且通过SetCallback 方法将对应的客户端代理(Codec HDI Callback Client Proxy)传给OpenMax 实现层,OpenMax 在数据Buffer 处理过程中会通过此代理调用回调方法,告知Media Service 进行对应的数据处理。
目录
Codec HDI编解码实例
组件状态流转

1.通过调用CreateComponent函数,可以打开组件,并让组件进入OMX_StateLoaded 或OMX_StateWaitForResources 状态;
2.通过调用DestoryComponent函数,可以销毁处于OMX_StateLoaded状态的组件实例;
3.其它的状态变化,可以通过SendCommand(OMX_CommandStateSet,
)使组件进入相应的状态。
状态 |
描述 |
|---|
OMX_StateInvalid |
组件已损坏或者发生一个不能恢复的错误 |
OMX_StateLoaded |
组件已经加载,但是资源未申请 |
OMX_StateIdle |
组件已经申请到所有资源,但不会轮转任何buffer |
OMX_StateExecuting |
组件正在处理有效的数据 |
OMX_StatePause |
组件暂停处理数据,可以通过设置组件状态唤醒重新处理数据 |
OMX_StateWaitForResources |
组件正在等待所需要的 |
编解码流程简介

主要包含以下几步:
接口及回调初始化
组件初始化
设置编解码参数
申请输入输出Buffer
编解码
组件回调处理
组件释放
codec HDI编解码主要流程如上图显示,下面我们以解码流程来讲解。
接口及回调初始化
本步骤主要初始化了使用HDI接口必须使用的结构及初始化对应的回调函数。

组件初始化
组件初始化包含打开对应的编解码组件并获取组件的版本,后续会使用到该版本参数。

设置编解码参数
设置参数时会使用上一步获取到的版本信息,注意填写。
1.设置输入的宽和高

2.设置输出视频的宽和高以及格式

3.设置输入的格式和帧率

申请输入输出Buffer
参数设置完成后,我们需要设置输入输出端口的Buffer,需要调用UseBuffer 方法,注意该方法只有在组件处于OMX_StateLoaded 或OMX_StateWaitForResources 或者端口处于Disabled 状态才能使用。实例代码中的portIndex可以是输入端口PortIndex::kPortIndexInput, 也可以是输出端口PortIndex::kPortIndexOutput,两个都需要设置。
1.获取端口需要的buffer大小和数量以及enable状态

2.初始化多个Buffer并调用UseBuffer方法,注意返回的bufferId,后续操作都可以用bufferId来标识OmxCodecBuffer


3.调用完UseBuffer之后,我们需要判断端口是否处于enable状态,如果是非使能状态,需要发送命令使端口处于使能状态

4.Buffer 设置完成后,需要使组件进入OMX_StateIdle状态

编解码
组件进入IDLE状态之后,我们要先让组件进入OMX_StateExecuting 状态,组件即可正常编解码了。
1.发送命令,使组件进入OMX_StateExecuting 状态

2.先将输出Buffer传给组件,让组件填充这些buffer

3.读取H264 或 H265文件中的数据,让组件消费,这里请注意下,组件只支持已分帧的数据,我们读取文件时,需要按照start code(0x000001 或者 0x00000001)进行分帧


4.解码完成后,需要将组件设置为OMX_StateIdle 状态

组件回调处理
codec HDI 提供了3大回调,分别对应了omx组件的3个回调函数。
1.EventHandler, 包含状态变化,错误通知等等,具体参数含义请见下表格
eEvent |
data1 |
data2 |
eventData |
|---|
OMX_EventCmdComplete |
OMX_CommandStateSet |
OMX组件状态 |
NULL |
OMX_CommandFlush |
端口 |
NULL |
OMX_CommandPortDisable |
端口 |
NULL |
OMX_CommandPortEnable |
端口 |
NULL |
OMX_CommandMarkBuffer |
端口 |
NULL |
OMX_EventError |
Error Code |
0 |
NULL |
OMX_EventMark |
0 |
0 |
make buffer |
OMX_EventPortSettingsChanged |
端口 |
0 |
NULL |
OMX_EventBufferFlag |
端口 |
nFlags |
NULL |
OMX_EventResourcesAcquired |
0 |
0 |
NULL |
OMX_EventDynamicResourcesAvailable |
0 |
0 |
NULL |
Demo 中逻辑处理比较简单,只是对OMX_EventCmdComplete 做了简单处理

2.EmptyBufferDone, 输入buffer处理完毕通知
接收到此通知后,根据bufferId找到具体被消耗的OmxCodecBuffer,然后可以继续将待解码数据写入该buffer,通过调用EmptyThisBuffer将buffer传递给组件处理其数据。

3.FillBufferDone, 输出buffer填充完毕通知
接收到此通知后,根据bufferId找到具体被填充的OmxCodecBuffer,然后取出解码数据(如果需要的话),再调用FillThisBuffer将buffer传递给组件,组件解码成功一帧数据后,会将解码数据填充到此buffer,并再次出发该回调。


组件释放
编解码完成后,我们需要对使用的buffer进行销毁,同时,需要销毁接口相关的结构。
1.先发送命令让组件进入OMX_StateLoaded状态

2.释放所有使用的Buffer

3.释放所有buffer之后,等待组件真正进入OMX_StateLoaded 状态
enum OMX_STATETYPE status;
client_->GetState(client_, &status);
// wait loaded
if (status != OMX_StateLoaded) {
HDF_LOGI(“Wait for OMX_StateLoaded status”);
this->WaitForStatusChanged();
} else {
HDF_LOGI(" status is %{public}d", status);
}
4.组件进入Loaded状态,可以释放组件及接口相关实例

总结
本文只是简单的介绍了下视频编解码Codec HDI的解码过程,需要在正确的组件状态下调用相应的接口。