承接上一章节分析:Android MediaPlayer整体架构源码分析 -【MediaCodec编解码器插件模块化注册和创建处理流程】【Part 1】
本系列文章分析的安卓源码版本:【Android 10.0 版本】
推荐涉及到的知识点:
Binder机制实现原理:Android C++底层Binder通信机制原理分析总结【通俗易懂】
ALooper机制实现原理:Android native层媒体通信架构AHandler/ALooper机制实现源码分析
Binder异常关闭监听:Android native层DeathRecipient对关联进程(如相关Service服务进程)异常关闭通知事件的监听实现源码分析
【本章节小节序号将重新开始】
MediaCodecList类声明和构造函数实现:
MediaCodecList类声明:【省略其他代码】
其实从声明就可以看出,MediaCodecList实现了Binder跨进程访问,其为Bn实现端即服务器端。
// [frameworks/av/media/libstagefright/include/media/stagefright/MediaCodecList.h]
struct MediaCodecList : public BnMediaCodecList {}
// [frameworks/av/media/libmedia/include/media/IMediaCodecList.h]
class BnMediaCodecList: public BnInterface<IMediaCodecList> {}
// [frameworks/av/media/libmedia/include/media/IMediaCodecList.h]
class IMediaCodecList: public IInterface {}
MediaCodecList类构造函数实现:
传入参数即为上面分析的”不同配置信息的编解码器创建工厂“实例集合
// [frameworks/av/media/libstagefright/MediaCodecList.cpp]
MediaCodecList::MediaCodecList(std::vector<MediaCodecListBuilderBase*> builders) {
// 全局配置信息
mGlobalSettings = new AMessage();
// MediaCodecInfo即媒体编解码器信息对象集合,此处清空
mCodecInfos.clear();
// 媒体编解码器读取参数值中的配置信息
MediaCodecListWriter writer;
for (MediaCodecListBuilderBase *builder : builders) {
if (builder == nullptr) {
ALOGD("ignored a null builder");
continue;
}
// for循环来执行所有创建工厂的该方法来读取编解码器配置信息并存入writer中返回。
// 见第1小节分析
mInitCheck = builder->buildMediaCodecList(&writer);
if (mInitCheck != OK) {
// 注意此处处理:若有一个builder执行失败则退出循环了
break;
}
}
// 通过上面第1小节中分析可知,此处将组件节点服务属性值(KV键值对)列表信息写入传入参数对象中。
// 见第2小节分析
writer.writeGlobalSettings(mGlobalSettings);
// 将第1小节中添加的编解码器配置信息全部放入在参入列表参数对象指针中返回。
// 见第3小节分析
writer.writeCodecInfos(&mCodecInfos);
// 将获取到的全部编解码器信息列表元素根据自身排序优先级来排序
std::stable_sort(
mCodecInfos.begin(),
mCodecInfos.end(),
[](const sp<MediaCodecInfo> &info1, const sp<MediaCodecInfo> &info2) {
// null is lowest
return info1 == nullptr
|| (info2 != nullptr && info1->getRank() < info2->getRank());
});
// 根据该系统属性值的设置,来判断是否应该移除重复编解码器配置信息实例元素,默认该属性未设置任何值。
// 因此此处的值默认为true,即需要去重,判重条件是编解码器组件名。
// remove duplicate entries
bool dedupe = property_get_bool("debug.stagefright.dedupe-codecs", true);
if (dedupe) {
std::set<std::string> codecsSeen;
for (auto it = mCodecInfos.begin(); it != mCodecInfos.end(); ) {
std::string codecName = (*it)->getCodecName();
if (codecsSeen.count(codecName) == 0) {
codecsSeen.emplace(codecName);
it++;
} else {
it = mCodecInfos.erase(it);
}
}
}
}
1、builder->buildMediaCodecList(&writer)实现分析:
for循环来执行每一个创建工厂的该方法来读取编解码器配置信息并存入writer中返回。
由前面流程中已有的分析可知,该集合中有两个对象:sOmxInfoBuilder 和 sCodec2InfoBuilder。
先分析sOmxInfoBuilder的该方法实现:
// [frameworks/av/media/libstagefright/OmxInfoBuilder.cpp]
status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
// Obtain IOmxStore
// 获取IOmxStore对象即Binder服务
// 见1.1小节分析
// 备注:有1.1小节分析后,可知该对象其实就是
// [frameworks/av/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h]文件中
// 定义的子类OmxStore对象的Binder服务即Bp代理端对象。
sp<IOmxStore> omxStore = IOmxStore::getService();
if (omxStore == nullptr) {
ALOGE("Cannot find an IOmxStore service.");
return NO_INIT;
}
// List service attributes (global settings)
Status status;
hidl_vec<IOmxStore::RoleInfo> roles;
// 通过Binder机制调用Bn实现端OmxStore的该方法。
// 在1.1中已分析过这中函数实现,也就是std::function类型匿名方法作为参数,作为回调方法,
// 让其回调指定内容,该实现其实相当于lambda表达式。
// 见1.2小节分析
auto transStatus = omxStore->listRoles(
[&roles] (
const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
// 回调值为inRoleList,在1.1中已分析过,其内容为插件编解码器组件节点角色信息列表。
roles = inRoleList;
});
// 检查方法执行状态
if (!transStatus.isOk()) {
ALOGE("Fail to obtain codec roles from IOmxStore.");
return NO_INIT;
}
hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
// 获取组件服务属性列表信息
// lambda表达式方式实现,传入接收参数和回调参数,然后赋值完成
// 该实现见1.3小节分析
transStatus = omxStore->listServiceAttributes(
[&status, &serviceAttributes] (
Status inStatus,
const hidl_vec<IOmxStore::ServiceAttribute>& inAttributes) {
status = inStatus;
serviceAttributes = inAttributes;
});
if (!transStatus.isOk()) {
ALOGE("Fail to obtain global settings from IOmxStore.");
return NO_INIT;
}
// 检查xml解析状态
if (status != Status::OK) {
ALOGE("IOmxStore reports parsing error.");
return NO_INIT;
}
// 组件节点服务属性值列表信息循环添加到write对象中
for (const auto& p : serviceAttributes) {
// 添加组件节点服务属性值(全局配置信息也就是此前分析过的音视频编解码器配置xml中相关信息)
// 见1.4小节分析
writer->addGlobalSetting(
p.key.c_str(), p.value.c_str());
}
// 下面将转换上面获得的组件节点信息对应到编解码器列表
// Convert roles to lists of codecs
// 定义map对象,缓存软硬编解码器名称与写入软硬编解码器信息对象的映射关系
// codec name -> index into swCodecs/hwCodecs
std::map<hidl_string, std::unique_ptr<MediaCodecInfoWriter>> codecName2Info;
// 获取系统属性默认的三种音视频编解码器排序类型
uint32_t defaultRank =
::android::base::GetUintProperty("debug.stagefright.omx_default_rank", 0x100u);
uint32_t defaultSwAudioRank =
::android::base::GetUintProperty("debug.stagefright.omx_default_rank.sw-audio", 0x10u);
uint32_t defaultSwOtherRank =
::android::base::GetUintProperty("debug.stagefright.omx_default_rank.sw-other", 0x210u);
// 此处处理从xml中获取到的组件节点角色信息列表值,将举例说明这些参数
// 备注:RoleInfo实际上就是xml配置文件中的每一个编解码器组件配置信息
for (const IOmxStore::RoleInfo& role : roles) {
// 音频或视频编解码器类型值,对应xml中的type标签值,例如 type="video/avc"
const hidl_string& typeName = role.type;
// 判断是否是编码器,该值通过xml中Encoders标签判断出来的
bool isEncoder = role.isEncoder;
// 判断该插件编解码器类型
// 类型值前缀是否包含[audio/]字符串,若包含则表示音频组件,否则为其它组件。
// hasPrefix() 方法实现,见1.5小节分析
bool isAudio = hasPrefix(role.type, "audio/");
// 判断是视频还是图像类型编解码器组件
bool isVideoOrImage = hasPrefix(role.type, "video/") || hasPrefix(role.type, "image/");
// NodeInfo 组件节点信息实际上就是每一个编解码器组件自身每个节点配置信息
for (const IOmxStore::NodeInfo &node : role.nodes) {
// 获取节点名称,例如 name="OMX.qcom.video.encoder.avc"
const hidl_string& nodeName = node.name;
// 由前面章节【OmxInfoBuilderg类构造函数实现】可知,mAllowSurfaceEncoders值为true。
// 而若为false则表明不能使用视频或图像编码器,
// 因为它的数据源是来自插件自身提供的Surface输入而非OMX的输入Surface,因此跳过该插件(组件)配置信息。
// 注意此处判断是放在内部for循环中的,主要就是打印该组件的所有节点信息。
// currently image and video encoders use surface input
if (!mAllowSurfaceEncoders && isVideoOrImage && isEncoder) {
ALOGD("disabling %s for media type %s because we are not using OMX input surface",
nodeName.c_str(), role.type.c_str());
continue;
}
// 是否是软编解码器,也就是Google实现的,以"OMX.google"开头的名称。
bool isSoftware = hasPrefix(nodeName, "OMX.google");
// 判断不同编解码器类型的排序类型
uint32_t rank = isSoftware
? (isAudio ? defaultSwAudioRank : defaultSwOtherRank)
: defaultRank;
// 获取节点信息中的属性排序值,一般无该配置
// get rank from IOmxStore via attribute
for (const IOmxStore::Attribute& attribute : node.attributes) {
if (attribute.key == "rank") {
uint32_t oldRank = rank;
char dummy;
if (sscanf(attribute.value.c_str(), "%u%c", &rank, &dummy) != 1) {
// 获取失败则记录默认排序
rank = oldRank;
}
break;
}
}
MediaCodecInfoWriter* info;
// 查找map中是否已缓存过该映射信息
auto c2i = codecName2Info.find(nodeName);
if (c2i == codecName2Info.end()) {
// end()为最后元素的下一位元素,其实就是表示未查找到该元素信息
// 创建和添加新的该编/解码器组件节点和组件信息的映射到map中
// writer->addMediaCodecInfo() 见1.6小节分析
// Create a new MediaCodecInfo for a new node.
c2i = codecName2Info.insert(std::make_pair(
nodeName, writer->addMediaCodecInfo())).first;
// 获取刚新创建的MediaCodecInfoWriter对象指针
info = c2i->second.get();
// 设置该插件(组件)节点名
info->setName(nodeName.c_str());
// 设置归属者,注意该值比较重要,在后续创建Codec时会用其归属来判断创建,
// 此处该值默认为"default",该值是在OmxStore章节赋值的。
info->setOwner(node.owner.c_str());
// 设置排序类型
info->setRank(rank);
typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
// 此处英文注释可知:所有vendor分区下的OMX编解码器都属于vendor,
// 但是"OMX.google"开头的组件名则将被视为不支持硬件加速和非vendor实现。
// all OMX codecs are vendor codecs (in the vendor partition), but
// treat OMX.google codecs as non-hardware-accelerated and non-vendor
if (!isSoftware) {
// 若是硬编解码器时,添加该属性,也就是表明该插件是vendor实现的,比如高通的实现。
attrs |= MediaCodecInfo::kFlagIsVendor;
// 此处使用了std::count_if功能即循环判断节点属性列表中匹配属性名为"attribute::software-codec"的个数。
// lambda表达式实现
if (!std::count_if(
node.attributes.begin(), node.attributes.end(),
[](const IOmxStore::Attribute &i) -> bool {
return i.key == "attribute::software-codec";
})) {
// 若不存在该节点属性时,则标记为支持硬件加速
attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
}
}
if (isEncoder) {
// 若是解码器时,添加该标记bit位
attrs |= MediaCodecInfo::kFlagIsEncoder;
}
// 设置缓存这些属性值
info->setAttributes(attrs);
} else {
// 若存在时即表明已添加过该映射信息,则直接获取value值info对象
// The node has been seen before. Simply retrieve the
// existing MediaCodecInfoWriter.
info = c2i->second.get();
}
// 添加和获取当前编解码器插件的性能/能力信息,也就是它支持的特性属性值
// 此方法实现不再详细分析,主要就是会根据编解码器类型名来匹配或创建该能力信息,然后缓存。
// MediaCodecInfo::Capabilities 能力信息属性声明,见1.7小节分析
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
info->addMediaType(typeName.c_str());
// 查询该codec的支持的能力信息,见1.8小节分析
if (queryCapabilities(
node, typeName.c_str(), isEncoder, caps.get()) != OK) {
ALOGW("Fail to add media type %s to codec %s",
typeName.c_str(), nodeName.c_str());
// 若失败,则移除该编解码器组件能力信息
info->removeMediaType(typeName.c_str());
}
}
}
return OK;
}
1.1、IOmxStore::getService()实现分析:
其实一开始我们是不能直接找到 IOmxStore.h 和 IOmxStore.cpp,它们并不存在。
其实我们全局搜索所有代码可以发现存在如下文件
hardware/interfaces/media/omx/1.0/IOmxStore.hal
从路径和名称其实可以知道,它是OMX的HAL硬件层方法访问接口定义,并且它还是使用了HIDL语言来实现的,这个语言和AIDL比较类似,其主要用于C++层来让编译器自动实现Binder跨进程功能,HIDL是安卓高版本为了更好的管理HAL层模块化以及高效而实现的新定义实现BInder服务的更简化功能,它会自动生成客户端和服务器端的相关.h头文件和.cpp实现文件,自动生成的文件其实就是自动实现了Binder跨进程功能。
HIDL这是一种新标准实现,可参考安卓官网关于此部分的介绍。
IOmxStore.hal 声明如下【这是HIDL新标准语言写成的,它将会被编译器自动生成Binder机制实现相关文件】
【hardware/interfaces/media/omx/1.0/目录下还有其它相关的HIDL文件声明】
package android.hardware.media.omx@1.0;
// 引用了frameworks/av/include/media/IOMX.h: IOMX头文件
import IOmx;
// 英文注释可知,IOmxStore接口服务的实现方将会有两个"platform" and "vendor",
// 并且在不同服务实现时都将加上该名称作为其接口名。
/**
* Ref: frameworks/av/include/media/IOMX.h: IOMX
*
* There will be two instances of IOmxStore: "platform" and "vendor".
*
* The IOmxStore service provided by the platform must present "platform" as the
* interface name.
*
* The IOmxStore service provided by the vendor must present "vendor" as the
* instance name.
*/
interface IOmxStore {
/**
* Attribute is a key-value pair of strings. The `value` member is generally
* a stringified value of the following:
* enum<v1,v2,...,vn>: v1 | v2 | ... | vn
* num: 0 | [1-9][0-9]*
* string: arbitrary string
* size: <num>x<num>
* ratio: <num>:<num>
* range<type>: <type> | <type>-<type>
* list<type>: <type> | <type>,<list<type>>
*/
// 存储KV键值对属性
struct Attribute {
string key;
string value;
};
/**
* Service attribute
*
* Optional service attributes:
* key: 'max-video-encoder-input-buffers', value-type: num
* key: 'supports-multiple-secure-codecs', value-type: enum<0,1>
* key: 'supports-secure-with-non-secure-codec', value-type: enum<0,1>
*
* For keys with prefix 'supports-', the value of 0 means "no" (not
* supported) while the value of 1 means "yes" (supported).
*/
// 可选服务属性,如英文注释很明确了,其实这些key将会对应后续分析到的media_codecs.xml编解码器配置文件的内容解析得到的。
typedef Attribute ServiceAttribute;
/**
* List attributes that are service-specific (not node-specific).
*
* @return attributes The list of `Attribute`s that are specific to this
* service.
*/
// 服务属性列表值
listServiceAttributes(
) generates (
Status status,
vec<ServiceAttribute> attributes
);
/**
* Node attribute
*
* Optional node attributes to describe supported values:
* key: 'bitrate-range', value-type: range<num>
* key: 'max-concurrent-instances', value-type: num
* key: 'max-supported-instances', value-type: num
*
* Optional node attributes for audio nodes to describe supported values:
* key: 'max-channel-count', value-type: num
* key: 'sample-rate-ranges', value-type: list<range<num>>
*
* Optional node attributes for video nodes to describe supported values:
* key: 'alignment', value-type: size
* key: 'block-aspect-ratio-range', value-type: range<ratio>
* key: 'block-count-range', value-type: range<num>
* key: 'block-size', value-type: size
* key: 'blocks-per-second-range', value-type: range<num>
* key: 'feature-can-swap-width-height', value-type: enum<0,1>
* key: 'frame-rate-range', value-type: range<num>
* key: 'pixel-aspect-ratio-range', value-type: range<ratio>
* key: 'size-range', value-type: range<size>
*
* Required node attributes for video nodes that are required by Android to
* describe measured values for this device:
* key: 'measured-frame-rate-<width>x<height>-range',
* value-type: range<num>; where width: num, height: num
*
* Optional node attributes for decoders to describe supported values:
* key: 'feature-adaptive-playback', value: enum<0,1>
* key: 'feature-secure-playback', value: enum<0,1>
* key: 'feature-tunneled-playback', value: enum<0,1>
*
* Optional node attributes for video decoders to describe supported values:
* key: 'feature-partial-frame', value: enum<0,1>
*
* Optional node attributes for encoders to describe supported values:
* key: 'complexity-default', value-type: num
* key: 'complexity-range', value-type: range<num>
* key: 'feature-bitrate-modes', value-type: list<enum<VBR,CBR,CQ>>
* key: 'feature-intra-refresh', value-type: enum<0,1>
* key: 'quality-default', value-type: num
* key: 'quality-range', value-type: range<num>
* key: 'quality-scale', value-type: string
*
* For keys with prefix 'feature-' and value type enum<0,1>, the value of 0
* means "optional", while the value of 1 means "required".
*/
// 节点属性值,也就是对应于media_codecs.xml中每个编解码器所持有的各种配置属性值【如英文注释中的key值】
typedef Attribute NodeAttribute;
/**
* Information for an IOmxNode node.
*/
// 节点(属性值)信息
struct NodeInfo {
/**
* Name of this node.
*
* `name` can be supplied to `IOmx::allocateNode` of a
* corresponding `IOmx` instance to create the node.
*/
string name;
/**
* Name of the `IOmx` instance that can create this node.
*
* To obtain the `IOmx` instance, call `getOmx(owner)`.
*/
string owner;
/**
* List of node attributes.
*/
vec<NodeAttribute> attributes;
};
/**
* Information about nodes provided for a supported node role
*/
// 支持的节点角色提供的节点信息
struct RoleInfo {
/**
* Standard OMX node role.
*/
string role;
/**
* Corresponding media type (as defined in MediaFormat.MIMETYPE_*
* constants for types required by Android).
*/
string type;
/**
* Whether this role is for an encoder or a decoder.
*/
bool isEncoder;
/**
* Whether to prefer platform nodes for this role.
*/
bool preferPlatformNodes;
/**
* List of nodes that support this role, ordered by preference.
*/
vec<NodeInfo> nodes;
};
/**
* Return the prefix of names of supported nodes.
*
* @return prefix The prefix of the names of all nodes supported by this
* service.
*/
// 获取支持的节点名前缀
getNodePrefix(
) generates (
string prefix
);
/**
* List roles of supported nodes.
*
* The name of each node inside `NodeInfo` must start with the prefix
* returned by `getNodePrefix()`.
*
* @return roleList The list of `RoleInfo`s.
*
* @see RoleInfo
*/
// 支持的节点角色信息列表信息
listRoles(
) generates (
vec<RoleInfo> roleList
);
/**
* Obtain an `IOmx` instance with a specified name.
*
* @param name The name of the instance.
* @return omx The `IOmx` interface associated with `name`. This must be
* null if the name is not found.
*/
// 获取一个指定名称的IOmx实例
getOmx(
string name
) generates (
IOmx omx
);
};
上面声明其实可以看到并没有我们需要的getService()方法声明,因此可以断定肯定是自动生成的头文件里包含了。
然后我们再看一下编译之后生成的对应头文件:【out目录下】
/out/xxx/.intermediates/hardware/interfaces/media/omx/1.0/android.hardware.media.omx@1.0_genc++_headers/gen/android/hardware/media/omx/1.0/IOmxStore.h【xxx为具体平台】
可以看到其放在自动生成C++头目录中。其实我们可以在该目录下发现更多使用HIDL而自动生成的头文件。
其自动生成的头文件声明:省略其他代码,此处只查看我们关注的getService()方法声明,如下由几种重载方法。
关于其父类IBase的声明实现将不分析,其声明在【system/libhidl/transport/base/1.0/IBase.hal】
namespace android {
namespace hardware {
namespace media {
namespace omx {
namespace V1_0 {
/**
* Ref: frameworks/av/include/media/IOMX.h: IOMX
*
* There will be two instances of IOmxStore: "platform" and "vendor".
*
* The IOmxStore service provided by the platform must present "platform" as the
* interface name.
*
* The IOmxStore service provided by the vendor must present "vendor" as the
* instance name.
*/
struct IOmxStore : public ::android::hidl::base::V1_0::IBase {
/**
* Fully qualified interface name: "android.hardware.media.omx@1.0::IOmxStore"
*/
static const char* descriptor;
// Forward declaration for forward reference support:
struct Attribute;
struct NodeInfo;
struct RoleInfo;
/**
* Attribute is a key-value pair of strings. The `value` member is generally
* a stringified value of the following:
* enum<v1,v2,...,vn>: v1 | v2 | ... | vn
* num: 0 | [1-9][0-9]*
* string: arbitrary string
* size: <num>x<num>
* ratio: <num>:<num>
* range<type>: <type> | <type>-<type>
* list<type>: <type> | <type>,<list<type>>
*/
struct Attribute final {
::android::hardware::hidl_string key __attribute__ ((aligned(8)));
::android::hardware::hidl_string value __attribute__ ((aligned(8)));
};
/**
* This gets the service of this type with the specified instance name. If the
* service is not in the VINTF manifest on a Trebilized device, this will return
* nullptr. If the service is not available, this will wait for the service to
* become available. If the service is a lazy service, this will start the service
* and return when it becomes available. If getStub is true, this will try to
* return an unwrapped passthrough implementation in the same process. This is
* useful when getting an implementation from the same partition/compilation group.
*/
// 该方法将是我们上面调用的方法,未传入参数,因此参数为默认值。
static ::android::sp<IOmxStore> getService(const std::string &serviceName="default", bool getStub=false);
/**
* Deprecated. See getService(std::string, bool)
*/
static ::android::sp<IOmxStore> getService(const char serviceName[], bool getStub=false) { std::string str(serviceName ? serviceName : ""); return getService(str, getStub); }
/**
* Deprecated. See getService(std::string, bool)
*/
static ::android::sp<IOmxStore> getService(const ::android::hardware::hidl_string& serviceName, bool getStub=false) { std::string str(serviceName.c_str()); return getService(str, getStub); }
/**
* Calls getService("default", bool). This is the recommended instance name for singleton services.
*/
static ::android::sp<IOmxStore> getService(bool getStub) { return getService("default", getStub); }
}
} // namespace V1_0
} // namespace omx
} // namespace media
} // namespace hardware
} // namespace android
其实从上面的分析可以知道,其实现其实和AIDL类似,通过HIDL自身定义的数据类型来转换和声明定义这些实现,最终实现其Binder跨进程访问机制。
因此此处我们不再分析HIDL的具体实现和调用原理,可以自行参考安卓官方网站的介绍。
直接跳到这些自动生成的头文件被引入后的具体实现处:
注意由上面分析可知,它将上面hal文件中声明的package路径自动生成为了namespace命名空间嵌套路径,有点类似与应用层AIDL的包名。因此访问时也必须应该引入命名空间才能访问。
如下可以看出,该自动生成的头文件和命名空间引入方式,如下 【省略其他代码】
【我们可以根据这种和普通的头文件不太相同的引入方式来确定该头文件是否是HIDL文件实现的Binder机制功能】
备注:HIDL实现的文件将在编译后自动生成一个so库,名称与package路径声明一致,如此处的so库将是【android.hardware.media.omx@1.0.so】
// [frameworks/av/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h]
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXSTORE_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXSTORE_H
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
// 自动生成的头文件引入方式
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxStore.h>
#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
// 与自动生成的头文件一样,再次声明子命名空间
namespace android {
namespace hardware {
namespace media {
namespace omx {
namespace V1_0 {
namespace implementation {
// 命名空间使用其声明实现
using ::android::hardware::media::omx::V1_0::IOmxStore;
using ::android::hardware::media::omx::V1_0::IOmx;
using ::android::hardware::media::omx::V1_0::Status;
using ::android::hidl::base::V1_0::IBase;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
using ::android::wp;
struct OmxStore : public IOmxStore {}
} // namespace implementation
} // namespace V1_0
} // namespace omx
} // namespace media
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXSTORE_H
getService()实现:
当我们分析cpp实现时发现并没有上面自动生成的getService()方法实现,其实和AIDL类似,该方法实现是HIDL机制自动实现的,并且返回的具体service对象就是当前实现的OmxStore对象,因为它就是实现了 IOmxStore 接口的子类。
【关于OmxStore服务是如何启动的,后续有时间再详细分析一下吧】
因此我们需要先分析下OmxStore类构造函数声明和构造函数实现,如下
OmxStore类构造函数声明
// [frameworks/av/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h]
struct OmxStore : public IOmxStore {
OmxStore(
const sp<IOmx> &omx = nullptr,
const char* owner = "default",
// 搜索(xml文件的)目录列表
const std::vector<std::string> &searchDirs =
MediaCodecsXmlParser::getDefaultSearchDirs(),
// xml文件名列表
const std::vector<std::string> &xmlFiles =
MediaCodecsXmlParser::getDefaultXmlNames(),
// xml分析结果路径
const char *xmlProfilingResultsPath =
MediaCodecsXmlParser::defaultProfilingResultsXmlPath);
}
声明中每个参数都有其默认值,其中MediaCodecsXmlParser相关的三个方法实现如下:
均在MediaCodecsXmlParser.h文件中声明定义的。
// [frameworks/av/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h]
// Treblized media codec list will be located in /odm/etc or /vendor/etc.
// 搜索(xml文件的)目录列表
// 备注:其实在我们的pad里面只有一个路径下有该目标xml文件
// 即 /vendor/etc/media_codecs.xml 和 / /vendor/etc/media_codecs_performance.xml,
// 其他两个目录下不存在。
static std::vector<std::string> getDefaultSearchDirs() {
return { "/odm/etc", "/vendor/etc", "/etc" };
}
// 默认的xml文件名列表
// 这两个文件很重要,其大致说明见下面的分析
static std::vector<std::string> getDefaultXmlNames() {
return { "media_codecs.xml", "media_codecs_performance.xml" };
}
// 默认的xml分析结果路径
// 备注:【其实该文件默认未创建和启用】
static constexpr char const* defaultProfilingResultsXmlPath =
"/data/misc/media/media_codecs_profiling_results.xml";
media_codecs.xml 配置文件格式内容如下:【示例配置】
media_codecs.xml:该文件即是安卓平台编解码器信息参数的配置文件。
该文件在系统代码路径为:
device//common/media/media_codecs.xml 和 hardware//media/conf_files//media_codecs.xml
【vendor名比如qcom(高通),产品名称】
注意:这两个文件的区别,后一个路径是生成了特定产品的编解码配置信息(会多出一些在当前系统下测试出的编解码器性能参数配置值比如支持的最大分辨率、帧率),因此后一个是包含前一个的内容的。一般只需要看后一个。
备注:这些标签key值都将会在后续的编解码器配置信息加载过程中读取处理的。
由于本章节接下来内容篇幅过长,因此必须放入另一章节分析,请查看:
Android MediaPlayer整体架构源码分析 -【MediaCodec编解码器插件模块化注册和创建处理流程】【Part 2-B】