返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >一文搞懂Codec2框架解析
  • 449
分享到

一文搞懂Codec2框架解析

2024-04-02 19:04:59 449人浏览 八月长安
摘要

目录1 前言–Codec2.0是什么2 Codec2.0框架3 流程解析3.1 初始化流程3.2 启动流程3.3 Input Buffer的回调3.4 Output Buffer的回

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。目录结构如下:


codec2
|--components  #具体编解码组件与组件接口层
|	|--base/SimpleC2Component.cpp
|	|--base/SimpleC2Interface.cpp
|	|--avc/C2SoftAvcDec.cpp	
|--core        #存在核心的头文件,譬如Buffer定义、Component定义、Config定义、Param定义
|--docs        #暂时存放doxygen配置文件与脚本
|--faultinjection
|--hidl        #与hidl调用相关的实现
	|--client/client.cpp
	|--1.0/utils/Component.cpp
	|--1.0/utils/ComponentInterface.cpp
	|--1.0/utils/ComponentStore.cpp
	|--1.0/utils/Configurable.cpp
	|--1.0/utils/include/codec2/hidl/1.0/Component.h
	|--1.0/utils/include/codec2/hidl/1.0/Configurable.h
	|--1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
|--sfplugin    #顶层接口与实现层
|	|--CCodec.cpp
|	|--CCodec.h
|	|--CBufferChannel.cpp
|	|--CBufferChannel.h
|--tests
|--vndk        #基础的util实现
|	|--C2Store.cpp

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


virtual std::shared_ptr<BufferChannelBase> getBufferChannel() override;
virtual void initiateAllocateComponent(const sp<AMessage> &msg) override;
virtual void initiateConfigureComponent(const sp<AMessage> &msg) override;
virtual void initiateCreateInputSurface() override;
virtual void initiateSetInputSurface(const sp<PersistentSurface> &surface) override;
virtual void initiateStart() override;
virtual void initiateShutdown(bool keepComponentAllocated = false) override;
virtual status_t setSurface(const sp<Surface> &surface) override;

virtual void signalFlush() override; virtual void signalResume() override;
virtual void signalSetParameters(const sp<AMessage> &params) override;
virtual void signalEndOfInputStream() override;
virtual void signalRequestIDRFrame() override;

void onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems);
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给编解码组件。


//client.cpp
	virtual Return<void> onInputBuffersReleased(
            const hidl_vec<InputBuffer>& inputBuffers) override {
        std::shared_ptr<Listener> listener = base.lock();
        if (!listener) {
            LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
            return Void();
        }
        for (const InputBuffer& inputBuffer : inputBuffers) {
            LOG(VERBOSE) << "onInputBuffersReleased --"
                            " received death notification of"
                            " input buffer:"
                            " frameIndex = " << inputBuffer.frameIndex
                         << ", bufferIndex = " << inputBuffer.arrayIndex
                         << ".";
            listener->onInputBufferDone(
                    inputBuffer.frameIndex, inputBuffer.arrayIndex);
        }
        return Void();
    }

在这里插入图片描述

onInputBuffersReleased究竟是怎么被触发的,目前仍未追踪到,在client.h中,有一段对Input Buffer管理的描述,说明了onInputBuffersReleased是一个IPC call。如下所示:


 * InputBufferManager holds a collection of records representing tracked buffers
 * and their callback listeners. Conceptually, one record is a triple (listener,
 * frameIndex, bufferIndex) where
 *
 * - (frameIndex, bufferIndex) is a pair of indices used to identify the buffer.
 * - listener is of type IComponentListener. Its onInputBuffersReleased()
 *   function will be called after the associated buffer dies. The argument of
 *   onInputBuffersReleased() is a list of InputBuffer objects, each of which
 *   has the following members:
 *
 *     uint64_t frameIndex
 *     uint32_t arrayIndex
 *
 * When a tracked buffer associated to the triple (listener, frameIndex,
 * bufferIndex) Goes out of scope, listener->onInputBuffersReleased() will be
 * called with an InputBuffer object whose members are set as follows:
 *
 *     inputBuffer.frameIndex = frameIndex
 *     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框架解析内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 一文搞懂Codec2框架解析

本文链接: https://lsjlt.com/news/135174.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 一文搞懂Codec2框架解析
    目录1 前言–Codec2.0是什么2 Codec2.0框架3 流程解析3.1 初始化流程3.2 启动流程3.3 Input Buffer的回调3.4 Output Buffer的回...
    99+
    2024-04-02
  • 一文搞懂Codec2解码组件
    目录1 前言2 组件的创建3 组件接口4 组件运行原理5 小结1 前言 在本篇中,我们将关注Codec 2.0以下几个问题: 1.从顶而下,一个解码组件是如何创建的 2.组件的接口有...
    99+
    2024-04-02
  • 一文了解JavaLog框架彻底搞懂Log4J,Log4J2,LogBack,SLF4J
    目录Log4J、Log4J2和LogBack的历史故事那slf4j和这些有什么关系?看看门面模式再说为什么要使用slf4j ?slf4j怎么和日志框架结合使用?现在为什么推荐Log4...
    99+
    2023-03-19
    Java Log框架 Log4J Log4J2 LogBack SLF4J
  • 一文搞懂Python爬虫解析器BeautifulSoup4
    本篇文章给大家带来了关于Python的相关知识,其中主要整理了爬虫解析器BeautifulSoup4的相关问题,Beautiful Soup是一个可以从HTML或XML文件中提取数据的Python库,它能够通过你喜欢的转换器实现惯用的文档导...
    99+
    2022-07-12
    python
  • C/S、B/S架构详解,一文带你搞懂
    一、CS、BS架构定义   CS架构(Client-Server Architecture)是一种分布式计算模型,其中客户端和服务器之间通过网络进行通信。在这种架构中,客户端负责向服务器发送请求,并接收服务器返回的响应。服务器则负责处理客...
    99+
    2023-09-05
    网络 服务器 前端
  • 一文搞懂HBA卡
    HBA卡是一个简称,准确叫法应该是:主机总线适配器(Host Bus Adapter,HBA),也叫做FC-HBA卡(俗称:光纤网卡)、iSCSI-HBA卡(RJ45接口)。这是一个在服务器和存储装置间提供输入/输出(I/O)处理和物理连接...
    99+
    2023-08-31
    服务器
  • 一文搞懂 Elasticsearch 之 Mapping
    作为 Elasticsearch 的“表结构定义”的 Mapping,你可能需要了解下! 这篇文章主要介绍 Mapping、Dynamic Mapping 以及 ElasticSearch 是如何自动判...
    99+
    2018-08-02
    一文搞懂 Elasticsearch Mapping
  • netstat命令,一文搞懂
    netstat命令是一个网络工具,用于显示计算机网络的连接状态和统计数据。它可以列出所有活动的网络连接,包括正在监听的端口、正在建立...
    99+
    2023-09-12
    netstat
  • Nginx详解(一文带你搞懂Nginx)
    前言 最近进入了新篇章的学习,Nginx,特写下详细笔记与大家共享。 目录 前言一、Nginx是什么?二、Nginx的反向代理(扩展:正向代理)三、Nginx的负载均衡什么是负载均衡? 四、Nginx的动静分离!五、Nginx的...
    99+
    2023-08-30
    nginx 服务器
  • 一文搞懂关于 sys.argv 的详解
    目录详解 sys.argvps:sys.argv[]的用法一、介绍二、简单的例子三、输入为 --numa=1  --numb=2 形式和  --numa...
    99+
    2023-01-15
    sys.argv 是什么 python sys.argv sys.argv[]的用法
  • 一文搞懂Map与Set的用法和区别解析
    目录前言1.基本概念1.1 Map(字典)1.2 Set(集合)2.基本使用2.1 Map 基本使用2.2 Set 基本使用3.Map和Set区别4.使用场景介绍4.1 Set对象使...
    99+
    2024-04-02
  • 一文搞懂MySQL预编译
    1、预编译的好处   大家平时都使用过JDBC中的PreparedStatement接口,它有预编译功能。什么是预编译功能呢?它有什么好处呢?   当客户发送一条SQL语句给服务器后,服务器总是需要校验SQL语句的语...
    99+
    2022-05-23
    MySQL 预编译 MySQL 编译
  • 一文搞懂Spring中的JavaConfig
    目录配置类注册组件扫描包配置事务注解驱动单元测试加载配置类properties配置文件加载(了解)aspectj注解开关传统spring一般都是基于xml配置的,不过后来新增了许多J...
    99+
    2024-04-02
  • 一文搞懂JSON(JavaScript Object Notation)
    目录JSON出现Json结构Json对象Json对象与JavaScript对象JSON 和 JavaScript 对象互转Json数组复杂数组类型复杂对象数组组合对象包含数组数组包含...
    99+
    2024-04-02
  • 一文搞懂MySQL中EXPLAIN解释命令
    本文主要给大家简单讲讲MySQL中EXPLAIN解释命令,相关专业术语大家可以上网查查或者找一些相关书籍补充一下,这里就不涉猎了,我们就直奔主题吧,希望MySQL中EXPLAIN解释命令这篇文章可以给大家带...
    99+
    2024-04-02
  • 一文搞懂Python Sklearn库使用
    目录1、LabelEncoder2、OneHotEncoder3、sklearn.model_selection.train_test_split随机划分训练集和测试集4、pipeline5 perdict...
    99+
    2022-06-03
    Python Sklearn库 Python Sklearn库使用
  • 一文搞懂MySQL事务特性
    本文主要给大家简单讲讲MySQL事务特性,相关专业术语大家可以上网查查或者找一些相关书籍补充一下,这里就不涉猎了,我们就直奔主题吧,希望MySQL事务特性这篇文章可以给大家带来一些实际帮助。事务特性ACID...
    99+
    2024-04-02
  • 一文搞懂UART通信协议
    目录 1、UART简介 2、UART特性 3、UART协议帧 3.1、起始位 3.2、数据位 3.3、奇偶校验位 3.4、停止位 4、UART通信步骤 1、UART简介 UART(Universal Asynchronous Receiv...
    99+
    2023-10-12
    UART协议 嵌入式 通信协议 单片机
  • 一文带你搞懂Java8的LocalDateTime
    目录前言LocalDateTime获取当前时间获取当前时间的年月日时分秒给LocalDateTime赋值时间与字符串相互转换时间运算:加上对应时间时间运算:减去对应时间两个时间比较利...
    99+
    2023-05-14
    Java8 LocalDateTime使用 Java8 LocalDateTime
  • 一文搞懂SQL注入攻击
    目录1. 前言2. SQL注入简介(1)SQL语言(2)SQL注入3. SQL注入步骤(1)发现漏洞(2)信息收集(3)攻击Web系统(猜解用户名和密码)(4)获取管理员权限4. 防范SQL注入(1)使用参数化查询或存储...
    99+
    2023-04-19
    SQL注入攻击 SQL注入
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作