请选择 进入手机版 | 继续访问电脑版

[C 语言] 一文搞懂Codec2框架剖析

[复制链接]
查看82 | 回复17 | 2021-9-12 18:21:53 | 显示全部楼层 |阅读模式
目次

1 前言 –Codec2.0是什么

在Android Q之前,Android的两套多媒体框架分别为MediaPlayer与MediaCodec,后者只负责解码与渲染工作,解封装工作由MediaExtractor代劳,MediaCodec经过 ACodec层调用第三方编解码标准接口OpenMAX IL,实现硬件编解码。芯片厂商只必要 支持上Khronos 订定 的OpenMAX接口,就可以实现MediaCodec的硬件编解码。谷歌在Android Q上推出了Codec2.0,指在于代替 ACodec与OpenMAX,它可以看作是一套新的对接MediaCodec的中心 件,往上对接MediaCodec Native层,往下提供新的API标准供编解码使用 ,相当 于ACodec 2.0。

2 Codec2.0框架

Codec2.0的代码目次 位于/frameworks/av/media/codec2。目次 布局 如下:

  1. codec2
  2. |--components #具体编解码组件与组件接口层
  3. | |--base/SimpleC2Component.cpp
  4. | |--base/SimpleC2Interface.cpp
  5. | |--avc/C2SoftAvcDec.cpp
  6. |--core #存在核心的头文件,譬如Buffer定义、Component定义、Config定义、Param定义
  7. |--docs #暂时存放doxygen配置文件与脚本
  8. |--faultinjection
  9. |--hidl #与hidl调用相关的实现
  10. |--client/client.cpp
  11. |--1.0/utils/Component.cpp
  12. |--1.0/utils/ComponentInterface.cpp
  13. |--1.0/utils/ComponentStore.cpp
  14. |--1.0/utils/Configurable.cpp
  15. |--1.0/utils/include/codec2/hidl/1.0/Component.h
  16. |--1.0/utils/include/codec2/hidl/1.0/Configurable.h
  17. |--1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
  18. |--sfplugin #顶层接口与实现层
  19. | |--CCodec.cpp
  20. | |--CCodec.h
  21. | |--CBufferChannel.cpp
  22. | |--CBufferChannel.h
  23. |--tests
  24. |--vndk #基础的util实现
  25. | |--C2Store.cpp
复制代码

sfplugin/CCodec.cpp是顶层实现,它提供的接口为MediaCodec Native层所调用,与libstagefright/ACodec接口同等 ,都继承于CodecBase,如下所示:

  1. virtual std::shared_ptr<BufferChannelBase> getBufferChannel() override;
  2. virtual void initiateAllocateComponent(const sp<AMessage> &msg) override;
  3. virtual void initiateConfigureComponent(const sp<AMessage> &msg) override;
  4. virtual void initiateCreateInputSurface() override;
  5. virtual void initiateSetInputSurface(const sp<PersistentSurface> &surface) override;
  6. virtual void initiateStart() override;
  7. virtual void initiateShutdown(bool keepComponentAllocated = false) override;
  8. virtual status_t setSurface(const sp<Surface> &surface) override;
  9. virtual void signalFlush() override; virtual void signalResume() override;
  10. virtual void signalSetParameters(const sp<AMessage> &params) override;
  11. virtual void signalEndOfInputStream() override;
  12. virtual void signalRequestIDRFrame() override;
  13. void onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems);
  14. void onInputBufferDone(uint64_t frameIndex, size_t arrayIndex);
复制代码

CCodec类中最紧张 的成员对象包括mChannel、mClient、mClientListener。mChannel是CCodecBufferChannel类,重要 负责buffer的传递。mClient是Codec2Client类,提供了Codec 2.0的最精要的接口,它包括了四个子类,Listener、Configurable、Interface以及Component。Client.h头文件对此有一段简要的形貌 ,可翻阅之。

Listener用于input buffer、output buffer以及error的回调。Interface提供设置 与参数的交互接口,在component与CCodec之间。Component则是具体 decoder/encoder component的代表。Interface与Component都是经过 ComponentStore创建而来,ComponentStore可以看作是对接Codec2Client的组件,该组件可以由不同的插件实现,原生实现的是C2PlatformComponentStore,厂商可以通过实现本身 的Store插件对接到ComponentStore,则完成了硬件编解码在Codec 2.0的对接。

3 流程分析

CCodec类的对象关系如下图所示:

在这里插入图片形貌

Codec2Client的成员Component通过C2PlatformComponent而创建,C2ComponentStore是接口类。而在ClientListener这条通路上,是一条回调通路,从底往上回调,分别颠末 SimpleC2Component、Component::Listener、HidlListener以及ClientListener,到达CCodec,再回调到MediaCodec。

3.1 初始化流程

CCodec的初始化接口为initiateAllocateComponent,调用到内部函数allocate,allocate做了很多 工作,起首 是调用到Codec2Client的接口CreateFromService,尝试创建了一个服务名为default的Codec2Client客户端(服务名为default的Codec2Client是厂商的Codec2Client),否则则创建服务名为software的Codec2Client,这是谷歌的原生Codec2Client,即,基于C2PlatformComponentStore的codec 2插件。假如 可以或许 创建default Codec2Client,则会调用SetPreferredCodec2ComponentStore,将厂商的ComponentStore设置为默认的codec 2插件。如许 子,codec2.0就不会走谷歌原生的软编解码器,而会走芯片厂商提供的编解码器,通常是硬编硬解。

在这里插入图片形貌

3.2 启动流程

mChannel是MCodecBufferChannel类,它的start接口实现轻微 复杂,重要 是获取AllocatorStore,再为input buffer与output buffer创建BlockPool,完成之后通过CCodec::mCallback回调告诉MediaCodec。接下来,初始化input buffer,开始调用queue接口送数据进编解码组件,原生组件为SimpleC2Component,具体 可以送到C2SoftAvcDec,也可以送到C2SoftHevcDec,等等。

在这里插入图片形貌

3.3 Input Buffer的回调

当input buffer数据被斲丧 以后,onInputBuffersReleased通过IPC被调用,HidlListener继而开始回调onInputBufferDone,Codec2Client是个接口类,实现类为CCodec::ClientListener,因而回调到了CCodec::ClientListener,以后 通过CCodec,CCodecBufferChannel,CCodecBufferChannel在完成onInputBufferReleased与expireComponentBuffer之后,调用feedInputBufferAvailable继续送空闲的Input Buffer给编解码组件。

  1. //client.cpp
  2. virtual Return<void> onInputBuffersReleased(
  3. const hidl_vec<InputBuffer>& inputBuffers) override {
  4. std::shared_ptr<Listener> listener = base.lock();
  5. if (!listener) {
  6. LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
  7. return Void();
  8. }
  9. for (const InputBuffer& inputBuffer : inputBuffers) {
  10. LOG(VERBOSE) << "onInputBuffersReleased --"
  11. " received death notification of"
  12. " input buffer:"
  13. " frameIndex = " << inputBuffer.frameIndex
  14. << ", bufferIndex = " << inputBuffer.arrayIndex
  15. << ".";
  16. listener->onInputBufferDone(
  17. inputBuffer.frameIndex, inputBuffer.arrayIndex);
  18. }
  19. return Void();
  20. }
复制代码

在这里插入图片形貌

onInputBuffersReleased毕竟 是怎么被触发的,现在 仍未追踪到,在client.h中,有一段对Input Buffer管理的形貌 ,阐明 白 onInputBuffersReleased是一个IPC call。如下所示:

  1. * InputBufferManager holds a collection of records representing tracked buffers
  2. * and their callback listeners. Conceptually, one record is a triple (listener,
  3. * frameIndex, bufferIndex) where
  4. *
  5. * - (frameIndex, bufferIndex) is a pair of indices used to identify the buffer.
  6. * - listener is of type IComponentListener. Its onInputBuffersReleased()
  7. * function will be called after the associated buffer dies. The argument of
  8. * onInputBuffersReleased() is a list of InputBuffer objects, each of which
  9. * has the following members:
  10. *
  11. * uint64_t frameIndex
  12. * uint32_t arrayIndex
  13. *
  14. * When a tracked buffer associated to the triple (listener, frameIndex,
  15. * bufferIndex) goes out of scope, listener->onInputBuffersReleased() will be
  16. * called with an InputBuffer object whose members are set as follows:
  17. *
  18. * inputBuffer.frameIndex = frameIndex
  19. * inputBuffer.arrayIndex = bufferIndex
复制代码

3.4 Output Buffer的回调

这一条路就有点长了,难点在于Codec2Client::Listener与IComponentListener是接口类,分别由CCodec::ClientListener与Codec2Client::Component::HidlListener实现,这会让不认识 C++的人一时半会摸不着头脑。从这一条通路可以看出不同模块的层次,HidleListener毗连 沟通了SimpleC2Component与Codec2Client,而Codec2Client是CCodec所调用的对象,CCodec将Buffer的管理都将由CodecBufferChannel打理,而CodecBufferChannel直接反馈于MediaCodec。

在这里插入图片形貌

在这里插入图片形貌

我们来看一下这条回调路上几个类的关系。譬如,Component::Listener回调的时间 ,调用的是IComponentListener的接口,而IComponentListener现实 由Codec2Client::Component::HidlListener继承实现,以是 ,现实 上是调用到了HidlListener,故而用实线表示,虚函数的调用用虚线表示。

在这里插入图片形貌

4 总结

在CCodec的几个接口中,初始化、启动、参数与设置 交互、回调交互是比较复杂的流程,对于参数与设置 交互,在OMX中是采用SetParameter、SetConfig、GetParameter、GetConfig来实现的,而在Codec2中,由ComponentInterface、C2Param一起完成,这块留作下次研究。我们从顶至下,先明白 顶层CCodec的接口,通过几个接口的流程追踪,梳理出各个类的关系,也相识 了数据的回调流向,云云 一来,后续分析代码就有了框架层的认识 ,不会陷入细节绕得团团转。

到此这篇关于一文搞懂Codec2框架分析 的文章就先容 到这了,更多相干 Codec2框架分析 内容请搜索 脚本之家从前 的文章或继续欣赏 下面的相干 文章渴望 大家以后多多支持脚本之家!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

avatar 123457287 | 2021-9-18 19:03:10 | 显示全部楼层
admin楼主的帖子实在是写得太好了。文笔流畅,修辞得体!
回复

使用道具 举报

avatar 大龙山草 | 2021-9-22 05:22:26 | 显示全部楼层
最近压力山大啊!
回复

使用道具 举报

avatar 俺乃小潜mg | 2021-9-26 04:25:19 | 显示全部楼层
顶顶更健康!
回复

使用道具 举报

avatar 一段或九段肝 | 2021-9-27 14:14:35 | 显示全部楼层
刚看见一个妹子,很漂亮!
回复

使用道具 举报

avatar 厕层柴 | 2021-9-28 03:23:15 | 显示全部楼层
每天顶顶贴,一身轻松啊!
回复

使用道具 举报

avatar 0Zombies0 | 2021-10-10 23:18:40 | 显示全部楼层
论坛的帖子越来越有深度了!
回复

使用道具 举报

avatar 白龙江左岸 | 2021-10-13 14:27:16 | 显示全部楼层
今天不想骂人!
回复

使用道具 举报

avatar 纆g | 2021-10-15 20:27:05 | 显示全部楼层
突然觉得admin楼主说的很有道理,赞一个!
回复

使用道具 举报

没人理我,好伤心啊!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则