这节来了解下MediaCodecList相关代码路径:

frameworks/av/media/libstagefright/MediaCodecList.cpp

frameworks/av/media/libstagefright/OmxInfoBuilder.cpp

frameworks/av/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp

参考MediaCodec中的使用方法:

const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();

sp<IMediaCodecList> MediaCodecList::getInstance() {
Mutex::Autolock _l(sRemoteInitMutex);
if (sRemoteList == nullptr) {
sMediaPlayer = defaultServiceManager()->getService(String16("media.player"));
sp<IMediaPlayerService> service =
interface_cast<IMediaPlayerService>(sMediaPlayer);
if (service.get() != nullptr) {
sRemoteList = service->getCodecList();
if (sRemoteList != nullptr) {
sBinderDeathObserver = new BinderDeathObserver();
sMediaPlayer->linkToDeath(sBinderDeathObserver.get());
}
}
if (sRemoteList == nullptr) {
// if failed to get remote list, create local list
sRemoteList = getLocalInstance();
}
}
return sRemoteList;
}

MediaCodecList使用的是单例模式,MediaCodecList有它对应的Bp和Bn,原先以为是一个binder service,其实并不是,这样定义只是方便了使用mediaplayerservice来获取一个MediaCodecList对象。

sp<IMediaCodecList> MediaCodecList::getLocalInstance() {
Mutex::Autolock autoLock(sInitMutex); if (sCodecList == nullptr) {
MediaCodecList *codecList = new MediaCodecList(GetBuilders());
if (codecList->initCheck() == OK) {
sCodecList = codecList; if (isProfilingNeeded()) {
ALOGV("Codec profiling needed, will be run in separated thread.");
pthread_t profiler;
if (pthread_create(&profiler, nullptr, profilerThreadWrapper, nullptr) != 0) {
ALOGW("Failed to create thread for codec profiling.");
}
}
} else {
// failure to initialize may be temporary. retry on next call.
delete codecList;
}
} return sCodecList;
}

getLocalInstance获取创建一个MediaCOdecList实例,它有一个参数GetBuilders():

std::vector<MediaCodecListBuilderBase *> GetBuilders() {
std::vector<MediaCodecListBuilderBase *> builders;
// if plugin provides the input surface, we cannot use OMX video encoders.
// In this case, rely on plugin to provide list of OMX codecs that are usable.
sp<PersistentSurface> surfaceTest = CCodec::CreateInputSurface();
if (surfaceTest == nullptr) {
ALOGD("Allowing all OMX codecs");
builders.push_back(&sOmxInfoBuilder);
} else {
ALOGD("Allowing only non-surface-encoder OMX codecs");
builders.push_back(&sOmxNoSurfaceEncoderInfoBuilder);
}
builders.push_back(GetCodec2InfoBuilder());
return builders;
}

GetBuilders方法返回一个MediaCodecListBuilderBase指针数组,数组中有sOmxInfoBuilder和Codec2InfoBuilder两个成员

OmxInfoBuilder sOmxInfoBuilder{true /* allowSurfaceEncoders */};
MediaCodecListBuilderBase *GetCodec2InfoBuilder() {
Mutex::Autolock _l(sCodec2InfoBuilderMutex);
if (!sCodec2InfoBuilder) {
sCodec2InfoBuilder.reset(new Codec2InfoBuilder);
}
return sCodec2InfoBuilder.get();
}

接下来就正式看看MediaCodecList的构造函数做了什么事情。

    MediaCodecListWriter writer;
for (MediaCodecListBuilderBase *builder : builders) {
if (builder == nullptr) {
ALOGD("ignored a null builder");
continue;
}
auto currentCheck = builder->buildMediaCodecList(&writer);
if (currentCheck != OK) {
ALOGD("ignored failed builder");
continue;
} else {
mInitCheck = currentCheck;
}
}

构造函数遍历了入参数组,并调用了他们的buildMediaCodecList方法,我们先看sOmxInfoBuilder:

sOmxInfoBuilder

它主要加载的是厂商提供的硬解组件信息

status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
// 1、Obtain IOmxStore
sp<IOmxStore> omxStore = IOmxStore::getService(); Status status;
hidl_vec<IOmxStore::RoleInfo> roles;
// 2、listRoles
auto transStatus = omxStore->listRoles(
[&roles] (
const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
roles = inRoleList;
}); // 3、listServiceAttributes
hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
transStatus = omxStore->listServiceAttributes(
[&status, &serviceAttributes] (
Status inStatus,
const hidl_vec<IOmxStore::ServiceAttribute>& inAttributes) {
status = inStatus;
serviceAttributes = inAttributes;
});
// 4、addGlobalSetting
for (const auto& p : serviceAttributes) {
writer->addGlobalSetting(
p.key.c_str(), p.value.c_str());
} 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);
// 5、将roles转化为list
for (const IOmxStore::RoleInfo& role : roles) {
const hidl_string& typeName = role.type;
bool isEncoder = role.isEncoder;
bool isAudio = hasPrefix(role.type, "audio/");
bool isVideoOrImage = hasPrefix(role.type, "video/") || hasPrefix(role.type, "image/"); for (const IOmxStore::NodeInfo &node : role.nodes) {
const hidl_string& nodeName = node.name; 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;
} bool isSoftware = hasPrefix(nodeName, "OMX.google");
uint32_t rank = isSoftware
? (isAudio ? defaultSwAudioRank : defaultSwOtherRank)
: defaultRank;
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;
auto c2i = codecName2Info.find(nodeName);
if (c2i == codecName2Info.end()) {
c2i = codecName2Info.insert(std::make_pair(
nodeName, writer->addMediaCodecInfo())).first;
info = c2i->second.get();
info->setName(nodeName.c_str());
info->setOwner(node.owner.c_str());
info->setRank(rank); typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
if (!isSoftware) {
attrs |= MediaCodecInfo::kFlagIsVendor;
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) {
attrs |= MediaCodecInfo::kFlagIsEncoder;
}
info->setAttributes(attrs);
} else {
info = c2i->second.get();
}
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
info->addMediaType(typeName.c_str());
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;
}

OmxInfoBuilder::buildMediaCodecList大致可分为4步:

1、获取IOmxStore

2、调用IOmxStore的listRoles方法

3、调用IOmxStore的listServiceAttributes

4、addGlobalSetting

5、将listRoles返回结果转化为MediaCodecInfo

IOmxStore

IOmxStore是一个HIDL service,它和IOmx Service是在同一个地方注册的,参考frameworks/av/services/mediacodec/main_codecservice.cpp,

    sp<IOmxStore> omxStore = new implementation::OmxStore(
property_get_int64("vendor.media.omx", 1) ? omx : nullptr);
if (omxStore == nullptr) {
LOG(ERROR) << "Cannot create IOmxStore HAL service.";
} else if (omxStore->registerAsService() != OK) {
LOG(ERROR) << "Cannot register IOmxStore HAL service.";
}

如果去看Omx.cpp的构造函数就可以发现,Omx service中持有一个OMXStore成员,注意这个OMXStore和我们这边的OmxStore是完全不同的两个东西!OMXStore加载了厂商提供的硬解组件。

我们这里用的OmxStore是加载了系统中可用的codec组件信息,接下来就看看OmxStore的构造函数做了什么?创建OmxStore时只传了一个参数,其实他还有5个默认参数

    OmxStore(
const sp<IOmx> &omx = nullptr,
const char* owner = "default",
const std::vector<std::string> &searchDirs =
MediaCodecsXmlParser::getDefaultSearchDirs(),
const std::vector<std::string> &xmlFiles =
MediaCodecsXmlParser::getDefaultXmlNames(),
const char *xmlProfilingResultsPath =
MediaCodecsXmlParser::defaultProfilingResultsXmlPath);

默认参数和MediaCodecsXmlParser公用的,看看都是些什么值

    static std::vector<std::string> getDefaultSearchDirs() {
return { "/product/etc",
"/odm/etc",
"/vendor/etc",
"/system/etc" };
} std::vector<std::string> MediaCodecsXmlParser::getDefaultXmlNames() {
static constexpr char const* prefixes[] = {
"media_codecs",
"media_codecs_performance"
};
static std::vector<std::string> variants = {
android::base::GetProperty("ro.media.xml_variant.codecs", ""),
android::base::GetProperty("ro.media.xml_variant.codecs_performance", "")
};
static std::vector<std::string> names = {
prefixes[0] + variants[0] + ".xml",
prefixes[1] + variants[1] + ".xml", // shaping information is not currently variant specific.
"media_codecs_shaping.xml"
};
return names;
} static constexpr char const* defaultProfilingResultsXmlPath = "/data/misc/media/media_codecs_profiling_results.xml";

意思就是从/product/etc /odm/etc /vendor/etc /system/etc下面去查找media_codecs.xml和media_codecs_performance.xml这两个文件并解析出来,最后保存到mRoleList当中。注意到构造NodeInfo时有一个owner,根据创建IOmxStore service的传值为default。

再回到OmxInfoBuilder中来,调用IOmxStore的listRoles和listServiceAttributes方法拿到roles和serviceAttributes之后(由于没有阅读parse xml的过程,所以暂不清楚他们的值是如何组织的)接下来需要将数据转化为MediaCodecInfo

            MediaCodecInfoWriter* info;
auto c2i = codecName2Info.find(nodeName);
if (c2i == codecName2Info.end()) {
// Create a new MediaCodecInfo for a new node.
c2i = codecName2Info.insert(std::make_pair(
nodeName, writer->addMediaCodecInfo())).first;
info = c2i->second.get();
info->setName(nodeName.c_str());
info->setOwner(node.owner.c_str());
info->setRank(rank); typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
// all OMX codecs are vendor codecs (in the vendor partition), but
// treat OMX.google codecs as non-hardware-accelerated and non-vendor
if (!isSoftware) {
attrs |= MediaCodecInfo::kFlagIsVendor;
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) {
attrs |= MediaCodecInfo::kFlagIsEncoder;
}
info->setAttributes(attrs);
} else {
// The node has been seen before. Simply retrieve the
// existing MediaCodecInfoWriter.
info = c2i->second.get();
}
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
info->addMediaType(typeName.c_str());
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());
}

Codec2InfoBuilder

它主要解析的是google提供的软解组件

    parser.parseXmlFilesInSearchDirs(
{ "media_codecs.xml", "media_codecs_performance.xml" },
{ "/apex/com.android.media.swcodec/etc" });

解析的是 /apex/com.android.media.swcodec/etc/media_codecs.xml,例如:

        <MediaCodec name="c2.android.vp9.decoder" type="video/x-vnd.on2.vp9" variant="slow-cpu,!slow-cpu">
<Alias name="OMX.google.vp9.decoder" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
<Variant name="!slow-cpu">
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="block-count" range="1-16384" />
<Limit name="blocks-per-second" range="1-500000" />
<Limit name="bitrate" range="1-40000000" />
</Variant>
<Variant name="slow-cpu">
<Limit name="size" min="2x2" max="1280x1280" />
<Limit name="block-count" range="1-3600" /> <!-- max 1280x720 -->
<Limit name="blocks-per-second" range="1-108000" />
<Limit name="bitrate" range="1-5000000" />
</Variant>
<Feature name="adaptive-playback" />
</MediaCodec>

其实看到这儿,也没看出个什么名堂!只知道了MediaCodecInfo中加载的是厂商的硬解组件信息(/vendor/etc/media_codecs.xml)和google软解组件信息(/apex/com.android.media.swcodec/etc/media_codecs.xml),加载的信息如何组织起来的也不清楚,其实通过dumpsys命令就可以看到支持的MediaCodecInfo了

$ dumpsys media.player
Media type 'video/x-vnd.on2.vp8':
Decoder "c2.android.vp8.decoder" supports
aliases: [
"OMX.google.vp8.decoder" ]
attributes: 0x4: [
encoder: 0,
vendor: 0,
software-only: 1,
hw-accelerated: 0 ]
owner: "codec2::software"
rank: 512
profile/levels: [
1/ 1 (Main/V0) ]
colors: [
0x7f420888 (YUV420Flexible),
0x13 (YUV420Planar),
0x15 (YUV420SemiPlanar),
0x14 (YUV420PackedPlanar),
0x27 (YUV420PackedSemiPlanar) ]
details: AMessage(what = 0x00000000) = {
string measured-frame-rate-1280x720-range = "29-100"
string measured-frame-rate-1920x1080-range = "11-44"
string measured-frame-rate-320x240-range = "250-300"
string measured-frame-rate-640x360-range = "130-300"
string alignment = "2x2"
string bitrate-range = "1-40000000"
string block-count-range = "1-8192"
string block-size = "16x16"
string blocks-per-second-range = "1-1000000"
int32_t feature-adaptive-playback = 0
string size-range = "2x2-2048x2048"
}

最后来看下MediaCodecList和相关类的关系,MediaPlayerService进程中有一个MediaCodecList全局变量,使用getCodecList获取的就是该全局变量。另外也可以通过直接调用MediaCodecList中的静态方法getLocalInstance或者getInstance方法来获取一个MediaCodecList对象,获取的也是MediaPlayerService进程中的全局变量。

Android 12(S) MultiMedia(十二)MediaCodecList & IOmxStore的更多相关文章

  1. Android图表库MPAndroidChart(十二)——来点不一样的,正负堆叠条形图

    Android图表库MPAndroidChart(十二)--来点不一样的,正负堆叠条形图 接上篇,今天要说的,和上篇的类似,只是方向是有相反的两面,我们先看下效果 实际上这样就导致了我们的代码是比较类 ...

  2. Android特效专辑(十二)——仿支付宝咻一咻功能实现波纹扩散特效,精细小巧的View

    Android特效专辑(十二)--仿支付宝咻一咻功能实现波纹扩散特效,精细小巧的View 先来看看这个效果 这是我的在Only上添加的效果,说实话,Only现在都还只是半成品,台面都上不了,怪自己技术 ...

  3. Android小项目之十二 设置中心的界面

    ------- 源自梦想.永远是你IT事业的好友.只是勇敢地说出我学到! ---------- 按惯例,写在前面的:可能在学习Android的过程中,大家会和我一样,学习过大量的基础知识,很多的知识点 ...

  4. Gradle 1.12 翻译——第十二章 使用Gradle 图形用户界面

    有关其他已翻译的章节请关注Github上的项目:https://github.com/msdx/gradledoc/tree/1.12,或访问:http://gradledoc.qiniudn.com ...

  5. Xamarin.Android开发实践(十二)

    Xamarin.Android之ContentProvider 一.前言 掌握了如何使用SQLiteOpenHelper之后,我们就可以进行下一步的学习.本章我们将会学习如何使用ContentProv ...

  6. Android实战技巧之十二:Android Studio导入第三方类库、jar包和so库

    第三方类库源码 将一网友的XMPP代码从ADT转到AS时,发现其使用了第三方类库,源码放在了lib下,直接在AS中Import project,第三方类库并没有自动导入进来,看来需要自己动手了. 项目 ...

  7. Android学习笔记(十二)——实战:制作一个聊天界面

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 运用简单的布局知识,我们可以来尝试制作一个聊天界面. 一.制作 Nine-Patch 图片 : Nine-Pa ...

  8. android 项目学习随笔十二(ListView加脚布局)

    1.ListView加脚布局 头布局initHeaderView,在onTouchEvent事件中进行显示隐藏头布局切换 脚布局initFooterView,实现接口OnScrollListener, ...

  9. Android学习笔记(十二)BroadcastReceiver的有序广播和优先级

    前两篇博文中简单整理了普通广播,其实还有有序广播,有序广播在开发中也是比不可少的,可以给广播接收者设定优先级来控制接受顺序,并却可以中断广播传递等等. 一.两种Broadcast: · 普通广播(No ...

  10. Android OpenGL ES(十二):三维坐标系及坐标变换初步 .

    OpenGL ES图形库最终的结果是在二维平面上显示3D物体(常称作模型Model)这是因为目前的打部分显示器还只能显示二维图形.但我们在构造3D模型时必须要有空间现象能力,所有对模型的描述还是使用三 ...

随机推荐

  1. 实例讲解昇腾 CANN YOLOV8 和 YOLOV9 适配

    本文分享自华为云社区<昇腾 CANN YOLOV8 和 YOLOV9 适配>,作者:jackwangcumt. 1 概述 华为昇腾 CANN YOLOV8 推理示例 C++样例 , 是基于 ...

  2. Python 潮流周刊第 46 期(摘要)+ 赠书 7 本

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  3. Signalr断线重连机制

    前言 Signalr 即时消息发布到服务器后发现链接老是自动断开,导致无法发送广播后面百度搜了一下,signalr有个超时的机制 解决办法(js) //链接到自己的hub var connection ...

  4. Vue 项目 invalid host header 问题 配置 disableHostCheck:true报错

    项目场景:解决 Vue 项目 invalid host header 问题disableHostCheck:true报错 问题描述使用内网穿透时出现 invalid host header找了好多都是 ...

  5. 文本溢出显示省略号css

    项目中常常有这种需要我们对溢出文本进行"..."显示的操作,单行多行的情况都有(具体几行得看设计师心情了),这篇随笔是我个人对这种情况解决办法的归纳,欢迎各路英雄指教. 单行 语法 ...

  6. 编译 OpenCV 的 Python 依赖

    这一次编译 OpenCV 的 Python 依赖为了方便运行我们使用 Docker 进行编译,环境准备如下: 系统依赖:Ubuntu 18.04 Python 版本:3.6,Ubuntu 18.04 ...

  7. 【Oracle】使用case when语句导致SQL查询速度很慢的情况

    [Oracle]使用case when语句导致SQL查询速度很慢的情况 很多时候会使用到case when语句去对SQL的多种情况进行处理,decode也用的多,但是通常decode会用在固定值的数据 ...

  8. Apache RocketMQ 的 Service Mesh 开源之旅

    作者 | 凌楚   阿里巴巴开发工程师 导读:自 19 年底开始,支持 Apache RocketMQ 的 Network Filter 历时 4 个月的 Code Review(Pull Reque ...

  9. 深度解密|基于 eBPF 的 Kubernetes 问题排查全景图发布

    ​简介:通过 eBPF 无侵入地采集多语言.多网络协议的黄金指标/网络指标/Trace,通过关联 Kubernetes 对象.应用.云服务等各种上下文,同时在需要进一步下钻的时候提供专业化的监测工具( ...

  10. 漫画 | 一口气搞懂 Serverless !

    ​简介: 第二届云原生编程挑战赛为热爱技术的年轻人提供一个挑战世界级技术问题的舞台,希望用技术为全社会创造更大价值. 作者 | 刘欣 呃,我可能是别人眼中所说的不用奋斗的一代. 大家喜欢听的什么多姿多 ...