文章目录
- 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入门:框架解析》一文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //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对象。
1 2 3 4 5 6 7 8 9 10 11 12 | //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这些接口见名知义,通俗易懂,而下面这些接口,就令人费解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //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*> ¶ms, 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类的定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | //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。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //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 C2Component virtual 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入门:解码组件》一文,简单来说就是通过插件化与工厂模式创建具体的组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //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的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | //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 C2ComponentInterface C2String 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*> ¶ms, 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接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | //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成员类的相关接口完成参数配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | //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 here noInputReferences(); 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_888 addParameter( 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。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //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类型,我们看一下它的定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | //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,如注释。