承接上一章节分析:Android MediaPlayer整体架构源码分析 -【MediaCodec编解码器插件模块化注册和创建处理流程】【Part 2】
本系列文章分析的安卓源码版本:【Android 10.0 版本】
推荐涉及到的知识点:
Binder机制实现原理:Android C++底层Binder通信机制原理分析总结【通俗易懂】
ALooper机制实现原理:Android native层媒体通信架构AHandler/ALooper机制实现源码分析
Binder异常关闭监听:Android native层DeathRecipient对关联进程(如相关Service服务进程)异常关闭通知事件的监听实现源码分析
【本章节小节序号将重新开始】
分析sCodec2InfoBuilder的buildMediaCodecList(&writer)实现分析:
读取编解码器配置信息并存入writer中返回。
根据前面流程中的分析可知,它的实现是在Codec2InfoBuilder.cpp中,如下
其实根据下面的实现,可以看到它的实现和前面已分析的另一个Builder实现类似的处理。
// [frameworks/av/media/codec2/sfplugin/Codec2InfoBuilder.cpp]
status_t Codec2InfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
// TODO: Remove run-time configurations once all codecs are working
// properly. (Assume "full" behavior eventually.)
//
// debug.stagefright.ccodec supports 5 values.
// 0 - No Codec 2.0 components are available.
// 1 - Audio decoders and encoders with prefix "c2.android." are available
// and ranked first.
// All other components with prefix "c2.android." are available with
// their normal ranks.
// Components with prefix "c2.vda." are available with their normal
// ranks.
// All other components with suffix ".avc.decoder" or ".avc.encoder"
// are available but ranked last.
// 2 - Components with prefix "c2.android." are available and ranked
// first.
// Components with prefix "c2.vda." are available with their normal
// ranks.
// All other components with suffix ".avc.decoder" or ".avc.encoder"
// are available but ranked last.
// 3 - Components with prefix "c2.android." are available and ranked
// first.
// All other components are available with their normal ranks.
// 4 - All components are available with their normal ranks.
//
// The default value (boot time) is 1.
//
// Note: Currently, OMX components have default rank 0x100, while all
// Codec2.0 software components have default rank 0x200.
// 该系统属性值此前章节中已介绍过,并可根据英文注释更清晰了解其作用。
// 默认该值通常为4,该值的作用其实就是一个编解码器列表信息的排序模式。规定如何排序它们。
int option = ::android::base::GetIntProperty("debug.stagefright.ccodec", 4);
// 获取特征属性列表信息,其实就是系统中可用组件服务的组件列表信息
// 见第1小节分析
// Obtain Codec2Client
std::vector<Traits> traits = Codec2Client::ListComponents();
// 如下解析音视频编解码器xml配置信息。
// 下面的解析处理流程,请参考前面流程已分析过程,此处只是从不同的路径下加载配置文件而已,
// 但是也会加载前面已分析的default默认xml配置文件信息
// parse APEX XML first, followed by vendor XML
MediaCodecsXmlParser parser;
parser.parseXmlFilesInSearchDirs(
parser.getDefaultXmlNames(),
{
"/apex/com.android.media.swcodec/etc" });
// 若组件移动到了默认文件中,它将会删除c2即Codec2特殊配置文件信息中值
// TODO: remove these c2-specific files once product moved to default file names
parser.parseXmlFilesInSearchDirs(
{
"media_codecs_c2.xml", "media_codecs_performance_c2.xml" });
// 加载默认配置文件
// parse default XML files
parser.parseXmlFilesInSearchDirs();
// 注意:解析状态未完成时也返回OK
if (parser.getParsingStatus() != OK) {
ALOGD("XML parser no good");
return OK;
}
// 获取已解析的服务属性设置映射信息
MediaCodecsXmlParser::AttributeMap settings = parser.getServiceAttributeMap();
for (const auto &v : settings) {
if (!hasPrefix(v.first, "media-type-")
&& !hasPrefix(v.first, "domain-")
&& !hasPrefix(v.first, "variant-")) {
// 若不是以这三个开头的属性值,那么将其添加到全局属性值设置信息列表中,见前面章节流程中已有分析
writer->addGlobalSetting(v.first.c_str(), v.second.c_str());
}
}
for (const Traits& trait : traits) {
C2Component::rank_t rank = trait.rank;
// Interface must be accessible for us to list the component, and there also
// must be an XML entry for the codec. Codec aliases listed in the traits
// allow additional XML entries to be specified for each alias. These will
// be listed as separate codecs. If no XML entry is specified for an alias,
// those will be treated as an additional alias specified in the XML entry
// for the interface name.
// 获取(插件编解码器)组件名或其别名列表信息
std::vector<std::string> nameAndAliases = trait.aliases;
nameAndAliases.insert(nameAndAliases.begin(), trait.name);
// for循环处理每一个编解码器配置信息
for (const std::string &nameOrAlias : nameAndAliases) {
// 若不相同则表示当前组件名为别名
bool isAlias = trait.name != nameOrAlias;
// 根据指定组件名创建编解码器客户端代理接口对象
// 见第2小节分析
std::shared_ptr<Codec2Client::Interface> intf =
Codec2Client::CreateInterfaceByName(nameOrAlias.c_str());
if (!intf) {
// 若接口创建失败,那么将跳过该编解码器组件(配置信息)
ALOGD("could not create interface for %s'%s'",
isAlias ? "alias " : "",
nameOrAlias.c_str());
continue;
}
if (parser.getCodecMap().count(nameOrAlias) == 0) {
// 由前面流程已对该方法的分析可知,若为0表示该组件名或别名,在xml配置信息中未找到
if (isAlias) {
// 若是别名,则查找该组件名对应的MediaCodecInfoWriter信息对象
std::unique_ptr<MediaCodecInfoWriter> baseCodecInfo =
writer->findMediaCodecInfo(trait.name.c_str());
if (!baseCodecInfo) {
// 若不存在则表示xml中未找到系统中可用服务组件名的编解码器配置信息,那么将会跳过该组件别名信息处理
ALOGD("alias '%s' not found in xml but canonical codec info '%s' missing",
nameOrAlias.c_str(),
trait.name.c_str());
} else {
// 找到该信息,则缓存该编解码器别名到对应的MediaCodecInfoWriter信息对象中
ALOGD("alias '%s' not found in xml; use an XML <Alias> tag for this",
nameOrAlias.c_str());
// merge alias into existing codec
baseCodecInfo->addAlias(nameOrAlias.c_str());
}
} else {
ALOGD("component '%s' not found in xml", trait.name.c_str());
}
// 然后进行下一个组件信息【已经存储该组件信息了,因此不需要下面处理再次缓存了】
continue;
}
// 注意:此为标准组件名
std::string canonName = trait.name;
// 接下来处理排序问题,此处就不详细分析了。
// TODO: Remove this block once all codecs are enabled by default.
switch (option) {
case 0:
// 不需要重新排序,因此直接接跳过该组件,处理下一个组件信息
continue;
case 1:
if (hasPrefix(canonName, "c2.vda.")) {
break;
}
if (hasPrefix(canonName, "c2.android.")) {
if (trait.domain == C2Component::DOMAIN_AUDIO) {
rank = 1;
break;
}
break;
}
if (hasSuffix(canonName, ".avc.decoder") ||
hasSuffix(canonName, ".avc.encoder")) {
rank = std::numeric_limits<decltype(rank)>::max();
break;
}
continue;
case 2:
if (hasPrefix(canonName, "c2.vda.")) {
break;
}
if (hasPrefix(canonName, "c2.android.")) {
rank = 1;
break;
}
if (hasSuffix(canonName, ".avc.decoder") ||
hasSuffix(canonName, ".avc.encoder")) {
rank = std::numeric_limits<decltype(rank)>::max