1. MediaCodec/Codec2 初始化过程深度解析
在Android多媒体框架中,MediaCodec作为编解码的核心组件,其底层实现经历了从OMX到Codec2的架构演进。本文将聚焦Codec2架构中的CCodec初始化过程,深入剖析其核心组件交互与实现机制。
1.1 CCodec核心成员架构
CCodec作为CodecBase的子类,承担着连接上层MediaCodec API与底层Codec2实现的关键角色。其核心架构围绕四个关键成员展开:
class CCodec { std::shared_ptr<Codec2Client> mClient; // 与底层HAL交互的客户端 std::shared_ptr<Codec2Client::Listener> mClientListener; // 事件回调监听器 Mutexed<std::unique_ptr<CCodecConfig>> mConfig; // 线程安全的配置存储 std::shared_ptr<CCodecBufferChannel> mChannel; // 缓冲区通道管理器 };各成员的核心职责如下表所示:
| 成员对象 | 类型 | 核心职责 |
|---|---|---|
mClient | std::shared_ptr<Codec2Client> | 作为HIDL通信桥梁,创建和管理编解码组件实例 |
mClientListener | std::shared_ptr<Codec2Client::Listener> | 处理底层组件的事件回调(错误/Buffer状态) |
mConfig | Mutexed<std::unique_ptr<CCodecConfig>> | 线程安全的参数存储(MediaFormat/编码参数等) |
mChannel | std::shared_ptr<CCodecBufferChannel> | 管理输入/输出缓冲区的生命周期和数据流传递 |
1.2 构造函数初始化流程
CCodec的构造函数完成了基础架构的搭建:
CCodec::CCodec() : mChannel(new CCodecBufferChannel(std::make_shared<CCodecCallbackImpl>(this))), mConfig(new CCodecConfig) { }关键初始化步骤:
- 创建
CCodecBufferChannel实例,传入封装了CCodec指针的回调实现 - 初始化线程安全的配置存储
mConfig mClient和mClientListener将在后续allocate()阶段动态创建
设计意图:将可能阻塞的HAL层操作(如组件创建)延迟到
allocate阶段,确保构造函数快速完成,符合Android组件的生命周期管理要求。
2. 组件分配(Allocate)机制剖析
2.1 allocate触发入口
组件分配由kWhatAllocate消息触发,关键代码段:
case kWhatAllocate: { setDeadline(now, 1500ms, "allocate"); // 设置超时限制 sp<RefBase> obj; CHECK(msg->findObject("codecInfo", &obj)); allocate((MediaCodecInfo *)obj.get()); // 执行实际分配 break; }此处设置的1500ms超时约束源于HIDL规范要求createComponent()应在100ms内完成,框架层适当放宽限制以兼容不同厂商实现。
2.2 核心分配流程实现
allocate()方法完成以下关键操作:
void CCodec::allocate(MediaCodecInfo *codecInfo) { AString componentName = codecInfo->getCodecName(); // 创建Codec2客户端 std::shared_ptr<Codec2Client> client = Codec2Client::CreateFromService("default"); if (client) { SetPreferredCodec2ComponentStore( std::make_shared<Codec2ClientInterfaceWrapper>(client)); } // 创建对应组件 std::shared_ptr<Codec2Client::Component> comp; c2_status_t status = Codec2Client::CreateComponentByName( componentName.c_str(), mClientListener, &comp, &client); // 初始化组件通道 mChannel->setComponent(comp); // 配置初始化 status_t err = config->initialize(mClient->getParamReflector(), comp); config->queryConfiguration(comp); // 回调通知 mCallback->onComponentAllocated(componentName.c_str()); }2.2.1 服务发现机制
CreateFromService()通过HIDL的IServiceManager查询可用服务:
std::vector<std::string> const& Codec2Client::GetServiceNames() { static std::vector<std::string> sServiceNames{[]() { auto serviceManager = IServiceManager::getService(); serviceManager->listManifestByInterface( IComponentStore::descriptor, [](hidl_vec<hidl_string> const& instanceNames) { // 按default/vendor/other分类服务 }); return names; }()}; return sServiceNames; }服务分类逻辑:
- default:前缀为"default"的系统默认服务
- vendor:前缀为"vendor"的厂商定制服务
- other:其他特殊服务(如software软件实现)
2.2.2 组件创建过程
实际组件创建通过createComponent()链式调用:
HIDL层调用:
mBase1_0->createComponent(name, hidlListener, ClientManager::getInstance(), [](Status s, const sp<IComponent>& c) { // 回调处理 });平台Store实现:
c2_status_t C2PlatformComponentStore::createComponent( C2String name, std::shared_ptr<C2Component> *component) { std::shared_ptr<ComponentModule> module; findComponent(name, &module); // 查找组件模块 return module->createComponent(0, component); // 创建实例 }动态库加载:
c2_status_t ComponentModule::init(std::string libPath) { mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE); createFactory = (CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory"); mComponentFactory = createFactory(); }
3. 核心组件实现细节
3.1 Codec2Client架构设计
Codec2Client作为与HAL交互的入口,其类关系如下:
Codec2Client ├── Listener : 处理组件回调事件 ├── Configurable: 参数配置接口 ├── Interface : 组件功能接口 └── Component : 组件实例封装与HIDL的对应关系:
Codec2Client↔IComponentStoreListener↔IComponentListenerComponent↔IComponent
3.2 组件插件实现
原生软解组件(如AVC解码器)的实现模式:
class C2SoftAvcDec : public SimpleC2Component { public: c2_status_t start() override; c2_status_t stop() override; c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* items) override; // ...其他虚函数实现 }; extern "C" ::C2ComponentFactory* CreateCodec2Factory() { return new ::android::C2SoftAvcDecFactory(); }关键生命周期方法:
start()/stop(): 组件启停控制queue_nb(): 异步提交工作项flush_sm(): 同步刷新操作
3.3 服务注册机制
Android系统包含两类核心服务:
3.3.1 默认服务(default)
注册路径:frameworks/av/media/codec2/hal/services/vendor.cpp
sp<IComponentStore> store = new utils::ComponentStore( std::make_shared<StoreImpl>()); store->registerAsService("default");3.3.2 软件服务(software)
注册路径:frameworks/av/services/mediacodec/main_swcodecservice.cpp
std::shared_ptr<C2ComponentStore> store = android::GetCodec2PlatformComponentStore(); sp<V1_0::IComponentStore> storeV1_0 = new V1_0::utils::ComponentStore(store); storeV1_0->registerAsService("software");4. 关键问题排查指南
4.1 常见初始化失败场景
| 错误现象 | 可能原因 | 排查方法 |
|---|---|---|
| 组件创建超时 | HAL层实现未及时响应 | 检查HAL日志,确认createComponent耗时 |
| 服务查找失败 | 厂商未正确实现HIDL服务 | 验证manifest.xml中的服务声明 |
| 动态库加载失败 | 插件so路径错误/权限不足 | 检查LD_LIBRARY_PATH和selinux策略 |
| 参数配置异常 | C2Param反射器未正确实现 | 验证getParamReflector()返回值 |
4.2 性能优化建议
- 组件预热:对高频使用的编解码器,可提前创建实例并缓存
- 参数批处理:使用
C2ParamBundle减少HIDL调用次数 - 内存复用:通过
C2BlockPool实现跨进程内存共享 - 线程模型:为不同组件配置独立的work线程
5. 厂商定制实践
5.1 硬件加速实现路径
厂商需要完成以下关键实现:
实现自定义Store:
class VendorComponentStore : public C2ComponentStore { public: c2_status_t createComponent(C2String, std::shared_ptr<C2Component>*); // ...其他虚函数实现 };注册HIDL服务:
<!-- manifest_media_c2_V1_0_vendor.xml --> <hal> <name>android.hardware.media.c2</name> <transport>hwbinder</transport> <version>1.0</version> <interface> <name>IComponentStore</name> <instance>vendor</instance> </interface> </hal>实现组件插件:
class C2VendorVideoDec : public C2Component { protected: // 实现硬件加速解码逻辑 };
5.2 兼容性注意事项
- API版本适配:需要同时实现1.0/1.1/1.2接口
- 内存对齐:硬件加速器通常有特殊的内存对齐要求
- 格式支持:通过
querySupportedValues准确报告能力集 - 功耗管理:实现
C2PowerComponent接口进行功耗控制
在实际开发中,我们常遇到硬件编解码器与框架层参数不匹配的情况。这时需要仔细检查C2Param的派生类实现,确保所有字段的偏移量和大小与HAL层严格一致。一个实用的调试技巧是在copyForSort()方法中添加日志,跟踪参数的实际传输过程。