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);
}
}
};
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*> ¶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完成。
我们看一下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(, ) = 0;
// virtual void onComponentReleased() = 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 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入门:解码组件》一文,简单来说就是通过插件化与工厂模式创建具体的组件。
//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;
}
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 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接口。
//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::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 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。
//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,如注释。