Codec2Client隐藏了Codec2 HAL的调用细节,并在HAL接口的基础上重新做了抽象和封装然后提供给sfPlugin使用,在这一篇文章中我们将对Codec2Client的设计结构进行简单分析。
1、Codec2Client
Codec2Client有一段注释:Codec2Client是核心类,它包含四个重要内部类,分别为Listener、Configurable、Interface和Component。Codec2框架的设计者可能是希望做到大一统,所有HAL API的封装都以Codec2Client内部类的形式来定义,本篇文章的目标是理清一个核心类和四个内部类的作用与联系。
Codec2Client的定义如下:
struct Codec2Client : public Codec2ConfigurableClient {
typedef ::android::hardware::media::c2::V1_0::IComponentStore Base1_0;
typedef ::android::hardware::media::c2::V1_1::IComponentStore Base1_1;
typedef ::android::hardware::media::c2::V1_2::IComponentStore Base1_2;
typedef Base1_0 Base;
typedef ::android::hardware::media::c2::V1_0::IConfigurable IConfigurable;
struct Listener;
typedef Codec2ConfigurableClient Configurable;
struct Component;
struct Interface;
typedef Codec2Client Store;
typedef Codec2ConfigurableClient Configurable;
static std::shared_ptr<Codec2Client> CreateFromService(
char const* name,
bool setAsPreferredCodec2ComponentStore = false);
protected:
sp<Base1_0> mBase1_0;
sp<Base1_1> mBase1_1;
sp<Base1_2> mBase1_2;
}
Codec2Client封装的是Codec2 Service的API,CreateFromService方法的第一个参数name可以用来控制获取SW还是HW Codec2 Service。首先来看GetServiceNames方法,该方法用于获取平台上所有的Codec2服务:
std::vector<std::string> const& Codec2Client::GetServiceNames() {
static std::vector<std::string> sServiceNames{[]() {
using ::android::hardware::media::c2::V1_0::IComponentStore;
using ::android::hidl::manager::V1_2::IServiceManager;
while (true) {
sp<IServiceManager> serviceManager = IServiceManager::getService();
std::vector<std::string> defaultNames; // Prefixed with "default"
std::vector<std::string> vendorNames; // Prefixed with "vendor"
std::vector<std::string> otherNames; // Others
Return<void> transResult;
transResult = serviceManager->listManifestByInterface(
IComponentStore::descriptor,
[&defaultNames, &vendorNames, &otherNames](
hidl_vec<hidl_string> const& instanceNames) {
for (hidl_string const& instanceName : instanceNames) {
char const* name = instanceName.c_str();
if (strncmp(name, "default", 7) == 0) {
defaultNames.emplace_back(name);
} else if (strncmp(name, "vendor", 6) == 0) {
vendorNames.emplace_back(name);
} else {
otherNames.emplace_back(name);
}
}
});
// ...
}
}()};
// 所有的服务会记录到全局变量中
return sServiceNames;
}
GetServiceNames的做法是从HW ServiceManager中查找descriptor为android.hardware.media.c2@1.0::IComponentStore的所有服务,拿到所有正在运行的服务名称。SW Codec Service的名称为software,一般情况HW Codec Service的名称为default。
所有的service都会记录到全局变量sServiceNames中,创建组件时,会查询指定的service名称时候包含在sServiceNames列表中,如果包含就获取指定的服务。
std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
const char* name,
bool setAsPreferredCodec2ComponentStore) {
// 查询是否包含在sServiceNames
size_t index = getServiceIndex(name);
if (index == GetServiceNames().size()) {
return nullptr;
}
// 获取服务,创建Codec2Client
std::shared_ptr<Codec2Client> client = _CreateFromIndex(index);
if (setAsPreferredCodec2ComponentStore) {
SetPreferredCodec2ComponentStore(
std::make_shared<Client2Store>(client));
}
return client;
}
std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
std::string const& name = GetServiceNames()[index];
// 获取服务
sp<Base> baseStore = Base::getService(name);
// 获取Configurable
Return<sp<IConfigurable>> transResult = baseStore->getConfigurable();
sp<IConfigurable> configurable = static_cast<sp<IConfigurable>>(transResult);
// 创建Codec2Client实例
return std::make_shared<Codec2Client>(baseStore, configurable, index);
}
Base在Codec2Client定义为::android::hardware::media::c2::V1_0::IComponentStore,所以baseStore实际上是一个IComponentStore对象。拿到服务后,首先调用IComponentStore的getConfigurable方法,然后使用IComponentStore和IConfigurable对象一起创建Codec2Client实例。
Codec2Client::Codec2Client(sp<Base> const& base,
sp<IConfigurable> const& configurable,
size_t serviceIndex)
: Configurable{configurable},
mBase1_0{base},
mBase1_1{Base1_1::castFrom(base)},
mBase1_2{Base1_2::castFrom(base)},
mServiceIndex{serviceIndex} {
Return<sp<IClientManager>> transResult = base->getPoolClientManager();
if (!transResult.isOk()) {
LOG(ERROR) << "getPoolClientManager -- transaction failed.";
} else {
mHostPoolManager = static_cast<sp<IClientManager>>(transResult);
}
}
Codec2Client的构造函数会干两件事情:
- 调用父类Codec2ConfigurableClient的构造函数,将IConfigurable对象做为参数传入;
- 调用IComponentStore的getPoolClientManager方法,要记住有这个动作,后续会用到。
Codec2Client的创建到这里就结束了,如果CreateFromService的第二个参数为true,还会额外调用SetPreferredCodec2ComponentStore方法:
void SetPreferredCodec2ComponentStore(std::shared_ptr<C2ComponentStore> componentStore) {
static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex); // don't interleve set-s
// update preferred store
{
std::lock_guard<std::mutex> lock(gPreferredComponentStoreMutex);
gPreferredComponentStore = componentStore;
}
// update platform allocator's store as well if it is alive
std::shared_ptr<C2PlatformAllocatorStoreImpl> allocatorStore;
{
std::lock_guard<std::mutex> lock(gPlatformAllocatorStoreMutex);
allocatorStore = gPlatformAllocatorStore.lock();
}
if (allocatorStore) {
allocatorStore->setComponentStore(componentStore);
}
}
SetPreferredCodec2ComponentStore的作用是将创建的Codec2Client封装为C2ComponentStore,然后使用全局变量记录下来。
2、Codec2ConfigurableClient
在Codec2中,ComponentStore、Component和Interface是携带有参数配置的模块,上层可以调用接口query、config等方法请求或者修改这些模块内部定义的参数。框架设计者将操作可配置模块的功能抽象出来,构造了Codec2ConfigurableClient这个类,上述三个携带有参数配置的模块都需要继承自Codec2ConfigurableClient。
struct Codec2ConfigurableClient {
typedef ::android::hardware::media::c2::V1_0::IConfigurable Base;
const C2String& getName() const;
c2_status_t query(
const std::vector<C2Param*>& stackParams,
const std::vector<C2Param::Index> &heapParamIndices,
c2_blocking_t mayBlock,
std::vector<std::unique_ptr<C2Param>>* const heapParams) const;
c2_status_t config(
const std::vector<C2Param*> ¶ms,
c2_blocking_t mayBlock,
std::vector<std::unique_ptr<C2SettingResult>>* const failures);
c2_status_t querySupportedParams(
std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
) const;
c2_status_t querySupportedValues(
std::vector<C2FieldSupportedValuesQuery>& fields,
c2_blocking_t mayBlock) const;
// base cannot be null.
Codec2ConfigurableClient(const sp<Base>& base);
protected:
sp<Base> mBase;
C2String mName;
friend struct Codec2Client;
};
Codec2ConfigurableClient提供了以下功能:
3、Codec2Client::Component
原文阅读:
Android Codec2(十)Codec2Client
扫描下方二维码,关注公众号《青山渺渺》阅读音视频开发内容。