文章目录

  • 1. 概述
  • 2. Codec2Client
  • 3. SimpleC2Component
  • 4. SimpleC2Interface

1. 概述

Codec2框架内有多个类,关系并不容易一下子缕清,涉及到接口与实现、HIDL调用、组件化、工厂模式与建造者模式等内容。

先看一张UML图,大概描绘了Codec2框架的大多数类及其之间的关系,可能存在疏漏与错误。

最顶层为Codec2类,对接到MediaCodec,其代码文件为CCodec.h,主要实现编解码功能,它主要与三个类打交道,包括CCodecBufferChannel、Codec2Client以及CCodecConfig类。

CCodecBufferChannel类主要封装与Buffer相关的操作接口,其代码文件为CCodecBufferChannel.h,包括送输入数据、渲染、获取输入与输出缓冲区、操作surface以及处理底层回调上来的输入数据与输出数据事件响应。

CCodecConfig类主要封装与参数交互相关的操作接口,其代码文件为CCodecConfig.h,包括向下层组件配置参数、从下层组件获取参数以及更新参数配置等。

Codec2Client类继承于Codec2ConfigurableClient父类,从而具备参数交互的操作接口,而本身提供与组件(component, interface)创建相关的操作接口,它可以创建component,创建与component相关联的interface,可以获取ParamReflector。该类的代码文件为Client.h及Client.cpp。

Codec2Client::Listener类是用于回调消息到CCodec的,在CCodec类中,CCodec::ClientListener是继承于Codec2Client::Listener的。关于上下层如何进行回调的流程,可以参考《Codec2入门:框架解析》一文。

//Client.h
struct CCodec::ClientListener : public Codec2Client::Listener {explicit ClientListener(const wp<CCodec> &codec) : mCodec(codec) {}virtual void onWorkDone(const std::weak_ptr<Codec2Client::Component>& component,std::list<std::unique_ptr<C2Work>>& workItems) override {......codec->onWorkDone(workItems);}......virtual void onInputBufferDone(uint64_t frameIndex, size_t arrayIndex) override {sp<CCodec> codec(mCodec.promote());if (codec) {codec->onInputBufferDone(frameIndex, arrayIndex);}}
};

2. Codec2Client

CCodec调用Codec2Client::Component对象,而Codec2Client::Component对象是经由Codec2Client创建的。CCodec调用Codec2Client::Component对象进行的主要操作包括:

comp->start(),在 CCodec::start() 中调用。

comp->stop(),在CCodec::stop()中调用。

comp->release(),在CCodec::release()中调用。

comp->flush(),在CCodec::flush()中调用。

comp->query,在configure()中调用。

在Codec2Client中,ComponentStore对象mBase是如何来的呢?在std::shared_ptr Codec2Client::_CreateFromIndex(size_t index)函数中,创建Codec2Client对象的过程中,传入了ComponentStore对象。

//client.cpp
std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {std::string const& name = GetServiceNames()[index];LOG(INFO) << "Creating a Codec2 client to service \"" << name << "\"";//获取到ComponentStore服务,内部具体实现可能是software服务,也可能是default服务//即厂商提供的store,store可以理解为插件集,插件集可以由谷歌原生提供,也可以由厂商提供sp<Base> baseStore = Base::getService(name);CHECK(baseStore) << "Codec2 service \"" << name << "\""" inaccessible for unknown reasons.";LOG(INFO) << "Client to Codec2 service \"" << name << "\" created";return std::make_shared<Codec2Client>(baseStore, index);//在此创建了Codec2Client对象,并以baseStore传参
}

接下来,先讲ComponentStore,再讲Component。

ComponentStore类向上层Codec2Client提供store的接口,向下层连接IComponentStore/software或者IComponentStore/default服务,连接的桥梁为HIDL接口,可以看作是C/S模型。ComponentStore实现的是IComponentStore类的纯虚接口,调用的mStore对象,可以是C2PlatformComponentStore,也可以是厂商提供的C2VendorComponentStore,这两者都实现的是C2ComponentStore的纯虚接口。

以谷歌原生提供的C2PlatformComponentStore为例,这到底是什么个东西?我们可以把这个类理解为平台提供的Codec2组件集,每一个组件可以是解码器,也可以是编码器,这个组件集负责创建与管理这些组件。从该类的接口可以看出,这个组件集可以创建组件,可以创建Interface,可以向组件配置参数与获取参数,这些参数交互的接口确实令人郁闷。对比omx标准,setParameter/getParameter,setConfig/getConfig这些接口见名知义,通俗易懂,而下面这些接口,就令人费解。

//C2Component.h,该头文件有详细注释,但我还是看不懂,特别是params对象与fields对象
//设计这些接口的家伙一点都不友好!
//后缀sm表示可能有短时的阻塞,须在5ms内返回响应
//后缀nb表示non-blocking,须在1ms内返回响应
virtual c2_status_t query_sm(const std::vector<C2Param*> &stackParams,const std::vector<C2Param::Index> &heapParamIndices,std::vector<std::unique_ptr<C2Param>>* const heapParams) const = 0;
virtual c2_status_t config_sm(const std::vector<C2Param*> &params,std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
virtual c2_status_t querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const = 0;
virtual c2_status_t querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> &fields) const = 0;
//这个返回一个parameter reflector,只可意会,不可直译,只能意译为参数器对象
virtual std::shared_ptr<C2ParamReflector> getParamReflector() const = 0;

Component类与C2Component类之间的关系类似于ComponentStore与C2ComponentStore。Component调用C2Component类对象,其具体实现是SimpleC2Component,如果存在厂商的服务,则可以为VendorC2Component,SimpleC2Component与SimpleC2Interface相关联,SimpleC2Interface大部分工作由C2InterfaceHelper所完成,厂商在实现自己的组件集时,可以不必自主实现一个VendorC2Interface,直接借用SimpleC2Interface即可。SimpleC2Interface实现的是C2ComponentInterface的抽象接口,而SimpleC2Interface的子类SimpleC2Interface::BaseParams继承于C2InterfaceHelper,由此,SimpleC2Interface的基本工作都由C2InterfaceHelper完成。

3. SimpleC2Component

我们看一下C2Component类的定义。

//C2Component.h
class C2Component {public://监听类,用于回调事件到上层(Component类)class Listener {public:virtual void onWorkDone_nb(std::weak_ptr<C2Component> component,std::list<std::unique_ptr<C2Work>> workItems) = 0;virtual void onTripped_nb(std::weak_ptr<C2Component> component,std::vector<std::shared_ptr<C2SettingResult>> settingResult) = 0;virtual void onError_nb(std::weak_ptr<C2Component> component,uint32_t errorCode) = 0;// virtual void onTunnelReleased(<from>, <to>) = 0;// virtual void onComponentReleased(<id>) = 0;virtual ~Listener() = default;};//用于上层设置回调函数,相当于监听,上层其实就是Component类//如果mayBlock为true,则该监听对象可能为temporarily blocking(暂时性阻塞),须等待其他pending listener callback处理完//如果mayBlock为false,则该监听对象为non-blocking(非阻塞)virtual c2_status_t setListener_vb(const std::shared_ptr<Listener> &listener, c2_blocking_t mayBlock) = 0;//送一个work事务对象给component,work这个对象可以理解为事务对象,包含着输入、输出以及其他参数信息//上下层的数据沟通,基本通过work来进行virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) = 0;//暂时没有用virtual c2_status_t announce_nb(const std::vector<C2WorkOutline> &items) = 0;//冲刷当前数据,一般用于跳播与分辨率切换virtual c2_status_t flush_sm(flush_mode_t mode, std::list<std::unique_ptr<C2Work>>* const  flushedWork) = 0;//渲染virtual c2_status_t drain_nb(drain_mode_t mode) = 0;//开始运行组件virtual c2_status_t start() = 0;//停止运行组件virtual c2_status_t stop() = 0;//重置组件virtual c2_status_t reset() = 0;//释放组件virtual c2_status_t release() = 0;//这里是C2Component与C2ComponentInterface关联的地方virtual std::shared_ptr<C2ComponentInterface> intf() = 0;virtual ~C2Component() = default;
}

C2Component只是一个抽象类,其实现为SimpleC2Component。

//SimpleC2Component.h
class SimpleC2Component: public C2Component, public std::enable_shared_from_this<SimpleC2Component> {public:explicit SimpleC2Component(const std::shared_ptr<C2ComponentInterface> &intf);virtual ~SimpleC2Component();// C2Component// From C2Componentvirtual c2_status_t setListener_vb(const std::shared_ptr<Listener> &listener, c2_blocking_t mayBlock) override;virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) override;virtual c2_status_t announce_nb(const std::vector<C2WorkOutline> &items) override;virtual c2_status_t flush_sm(flush_mode_t mode, std::list<std::unique_ptr<C2Work>>* const flushedWork) override;virtual c2_status_t drain_nb(drain_mode_t mode) override;virtual c2_status_t start() override;virtual c2_status_t stop() override;virtual c2_status_t reset() override;virtual c2_status_t release() override;virtual std::shared_ptr<C2ComponentInterface> intf() override;
}

SimpleC2Component类实现的是各个组件的共同操作,相当于一个公共适配层,每一个组件都继承于SimpleC2Component类,譬如,C2SoftAvcDec类在构造的同时,父类SimpleC2Component亦构造。组件的创建过程可参考《Codec2入门:解码组件》一文,简单来说就是通过插件化与工厂模式创建具体的组件。

//C2SoftAvcDec.h
struct C2SoftAvcDec : public SimpleC2Component {class IntfImpl;C2SoftAvcDec(const char *name, c2_node_id_t id, const std::shared_ptr<IntfImpl> &intfImpl);virtual ~C2SoftAvcDec();// From SimpleC2Component//以下函数都是实现了父类SimpleC2Component的私有虚函数c2_status_t onInit() override;c2_status_t onStop() override;void onReset() override;void onRelease() override;c2_status_t onFlush_sm() override;//处理一个work事务//对于avc decoder而言,work中包含码流输入数据,当调用返回时,work将包含yuv解码数据void process(const std::unique_ptr<C2Work> &work,const std::shared_ptr<C2BlockPool> &pool) override;c2_status_t drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> &pool) override;}

4. SimpleC2Interface

SimpleC2Interface实现于C2ComponentInterface纯虚类,SimpleC2Interface的定义如下:

//SimpleC2Interface.h
/*** Wrap a common interface object (such as Codec2Client::Interface, or C2InterfaceHelper into* a C2ComponentInterface.** \param T common interface type*/
template <typename T>
class SimpleC2Interface : public C2ComponentInterface {public:SimpleC2Interface(const char *name, c2_node_id_t id, const std::shared_ptr<T> &impl): mName(name),mId(id),mImpl(impl) {}~SimpleC2Interface() override = default;// From C2ComponentInterfaceC2String getName() const override { return mName; }c2_node_id_t getId() const override { return mId; }//获取参数c2_status_t query_vb(const std::vector<C2Param*> &stackParams,const std::vector<C2Param::Index> &heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {return mImpl->query(stackParams, heapParamIndices, mayBlock, heapParams);}//配置参数c2_status_t config_vb(const std::vector<C2Param*> &params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {return mImpl->config(params, mayBlock, failures);}//暂时没有用c2_status_t createTunnel_sm(c2_node_id_t) override { return C2_OMITTED; }//暂时没有用c2_status_t releaseTunnel_sm(c2_node_id_t) override { return C2_OMITTED; }c2_status_t querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override {return mImpl->querySupportedParams(params);}c2_status_t querySupportedValues_vb(std::vector<C2FieldSupportedValuesQuery> &fields,c2_blocking_t mayBlock) const override {return mImpl->querySupportedValues(fields, mayBlock);}private:C2String mName;const c2_node_id_t mId;const std::shared_ptr<T> mImpl;
};

接下来讨论上述的一个问题,SimpleC2Component如何与SimpleC2Interface相关联。

我们看一下C2SoftAvcDecFactory类的定义。SimpleC2Component在构造的时候,SimpleC2Interface的一个成员类SimpleC2Interface::BaseParams被作为入参传递给了组件,组件继而可以调用该成员类的相关接口完成参数配置,主要是addParameter接口。

//C2SoftAvcDec.cpp
class C2SoftAvcDecFactory : public C2ComponentFactory {public:C2SoftAvcDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(GetCodec2PlatformComponentStore()->getParamReflector())) {}virtual c2_status_t createComponent(c2_node_id_t id,std::shared_ptr<C2Component>* const component,std::function<void(C2Component*)> deleter) override {//C2SoftAvcDec构造函数的一个入参为C2SoftAvcDec::IntfImpl类型成员//C2SoftAvcDec::IntfImpl是继承于SimpleInterface<void>::BaseParams的*component = std::shared_ptr<C2Component>(new C2SoftAvcDec(COMPONENT_NAME,id,std::make_shared<C2SoftAvcDec::IntfImpl>(mHelper)),deleter);return C2_OK;}virtual c2_status_t createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface>* const interface,std::function<void(C2ComponentInterface*)> deleter) override {//interface的创建来自于SimpleInterface对象的构建,该对象类型为C2SoftAvcDec::IntfImpl,//构造参数包括COMPONENT_NAME、id以及C2SoftAvcDec::IntfImpl对象//这个构造过程有点难懂......为什么SimpleInterface的类型为C2SoftAvcDec::IntfImpl??*interface = std::shared_ptr<C2ComponentInterface>(new SimpleInterface<C2SoftAvcDec::IntfImpl>(COMPONENT_NAME, id, std::make_shared<C2SoftAvcDec::IntfImpl>(mHelper)),deleter);return C2_OK;}virtual ~C2SoftAvcDecFactory() override = default;private:std::shared_ptr<C2ReflectorHelper> mHelper;
};

我们看一下组件如何调用SimpleC2Interface::BaseParams成员类的相关接口完成参数配置。

//C2SoftAvcDec.cpp
class C2SoftAvcDec::IntfImpl : public SimpleInterface<void>::BaseParams {public:explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper): SimpleInterface<void>::BaseParams(helper,COMPONENT_NAME,C2Component::KIND_DECODER,C2Component::DOMAIN_VIDEO,MEDIA_MIMETYPE_VIDEO_AVC) {noPrivateBuffers(); // TODO: account for our buffers herenoInputReferences();noOutputReferences();noInputLatency();noTimeStretch();......//省略部分// coded and output picture size is the same for this codec//配置默认解码输出宽高为320x240//这里采用了Builder模式,即建造者模式addParameter(DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE).withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240)).withFields({C2F(mSize, width).inRange(2, 4080, 2),C2F(mSize, height).inRange(2, 4080, 2),}).withSetter(SizeSetter).build());//配置默认的颜色信息addParameter(DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO).withConstValue(defaultColorInfo).build());//配置默认的颜色格式为HAL_PIXEL_FORMAT_YCBCR_420_888addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT).withConstValue(new C2StreamPixelFormatInfo::output(0u, HAL_PIXEL_FORMAT_YCBCR_420_888)).build());
}

C2SoftAvcDec::IntfImpl调用C2InterfaceHelper::addParameter完成默认参数配置,而正是由于SimpleInterface::BaseParams继承于C2InterfaceHelper(查看UML图),才得以调用父类的该接口。addParameter接口会将参数添加到参数器Reflector中,这样,上层通过参数器Reflector便可获知组件的默认配置,实现参数交互。

SimpleInterface::BaseParams属于SimpleInterface类,继承于C2InterfaceHelper。

//SimpleC2Interface.h
/*** Utility classes for common interfaces.*/
template<>
class SimpleC2Interface<void> {public:/*** Base Codec 2.0 parameters required for all components.*/struct BaseParams : C2InterfaceHelper {explicit BaseParams(const std::shared_ptr<C2ReflectorHelper> &helper,C2String name,C2Component::kind_t kind,C2Component::domain_t domain,C2String mediaType,std::vector<C2String> aliases = std::vector<C2String>());
}

其中第一个入参为C2ReflectorHelper类型,我们看一下它的定义。

//C2InterfaceHelper.h
/*** Helper class to implement parameter reflectors. This class is dynamic and is designed to be* shared by multiple interfaces. This allows interfaces to add structure descriptors as needed.*/
class C2ReflectorHelper : public C2ParamReflector {public:C2ReflectorHelper() = default;virtual ~C2ReflectorHelper() = default;virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex paramIndex) const override;/*** Adds support for describing the given parameters.** \param Params types of codec 2.0 structs (or parameters) to describe*/template<typename... Params>C2_INLINE void addStructDescriptors() {std::vector<C2StructDescriptor> structs;addStructDescriptors(structs, (_Tuple<Params...> *)nullptr);}/*** Adds support for describing a specific struct.** \param strukt descriptor for the struct that will be moved out.*/void addStructDescriptor(C2StructDescriptor &&strukt);
}

C2ReflectorHelper继承于C2ParamReflector类,并实现了C2ParamReflector唯一的虚函数describe。如何理解C2ReflectorHelper这个类呢?可以把它看作是一个参数器,它提供两个操作,一个是往参数器里添加参数对象,一个是从参数器里取出参数对象,这里的参数对象指的是structure descriptors,如注释。

Codec2类的解析相关推荐

  1. boost::program_options模块实现一个用户定义的类来解析 特定机制——不是默认使用的 iostream 操作的测试程序

    boost::program_options模块实现一个用户定义的类来解析 特定机制--不是默认使用的 iostream 操作的测试程序 实现功能 C++实现代码 实现功能 boost::progra ...

  2. 解析HTML文件 - 运用SgmlReader类来解析HTML文件

    运用.NET Framework类来解析HTML文件.读取数据并不是最容易的.虽然你可以用.NET Framework中的许多类(如StreamReader)来逐行解析文件,但XmlReader提供的 ...

  3. 深入OKHttp源码分析(二)----OkHttp任务调度核心类Dispatcher解析

    OkHttp任务调度核心类Dispatcher解析 上一篇我们分析了okhttp的同步和异步请求的执行流程并进行了源码分析,深入OKHttp源码分析(一)----同步和异步请求流程和源码分析 那么今天 ...

  4. php批量解析json,封装php类批量解析css成json格式_html/css_WEB-ITnose

    封装php类批量解析css成json格式 业务需求 我相信很多同学有过做一个自定义建站系统的想法,好比某空间的自定义拖拽组件,如果想要实现一个可视化建站系统,那CSS作为前端样式而言,是必须要存入到数 ...

  5. Class -- 10 -- Method类常用方法解析

    原文链接:Class – 10 – Method类常用方法解析 相关文章: Class – 01 – System类常用方法解析 Class – 02 – Arrays类常用方法解析 Class – ...

  6. Class -- 08 -- Parameter类常用方法解析

    原文链接:Class – 08 – Parameter类常用方法解析 相关文章: Class – 01 – System类常用方法解析 Class – 02 – Arrays类常用方法解析 Class ...

  7. JVM学习笔记(Ⅰ):Class类文件结构解析(带你读懂Java字节码,这一篇就够了)

    JVM学习笔记(Ⅰ):Class类文件结构解析,带你读懂Java字节码 前言:本文属于博主个人的学习笔记,博主也是小白.如果有不对的地方希望各位帮忙指出.本文主要还是我的学习总结,因为网上的一些知识分 ...

  8. Django Meta元数据类属性解析

    Django Meta元数据类属性解析 Model 是 Django ORM 的核心,它有许多特性,比如我们提到过的模型类继承,还有未讲到过的的元数据.每个 Model 都是一个 Python 类,且 ...

  9. Class -- 09 -- Field类常用方法解析

    原文链接:Class – 09 – Field类常用方法解析 相关文章: Class – 01 – System类常用方法解析 Class – 02 – Arrays类常用方法解析 Class – 0 ...

最新文章

  1. python中的 2%s何意_python中的%s%是什么意思
  2. node --- 在express中配置使用模板引擎(art-template)
  3. python 读取sqlite存入文件_如何通过python读取sqlite数据文件
  4. Linux使用笔记: 设置Samba服务器中新建文件/目录的权限
  5. [你必须知道的.NET]第十五回:继承本质论
  6. java 画多边形_javascript绘制一个多边形
  7. JVM学习手册(X):查看堆内存使用情况以及排错
  8. 用户模块 之 完成查询所有用户
  9. 375. 猜数字大小 II leetcode java
  10. Android知识点复习1(Activity与Fragment)
  11. 解决问题Uncaught SyntaxError: The requested module ‘/node_modules/hls.js/dist/hls.js‘ does not provide
  12. 做uni-app时,遇到后台返回base64码,将base64码转为图片,但是图片没有显示出来的解决方法
  13. signal(SIGPIPE, SIG_IGN)
  14. 甘特图——项目计划与实际进度比较与调整
  15. 苹果企业账号发布APP详解——通过自己网站分发应用
  16. 人脸识别助力网络支付实名制落地推进
  17. Python 3.6以后版本的格式化输出
  18. CentOS和Ubuntu有什么不同
  19. Android 打造形形色色的进度条 实现可以如此简单
  20. Scrapy中间件的使用-爬取豆瓣top250/PM2.5历史数据

热门文章

  1. 学Python该看什么书?所有方向的精华好书推荐,18年老程序员倾囊相授!
  2. 并购后仍不吭声的当当,下一步剑指何方?
  3. Supermap iDesktop处理导入CAD文件存在线型风格显示缺失问题
  4. c语言 宏定义 条件,c语言宏定义、条件编译
  5. Dism 错误: 1450
  6. IDEA java编译中出现了Exception in thread “main java.lang.UnsupportedClassVersionError
  7. SAP ECC连接SAP PI系统配置
  8. Unity之创建文件报错
  9. mongodb持久化
  10. 我的世界服务器地图文件丢失,我的世界地图被毁了或找不到了 ? 大神手把手教你奇迹恢复...