Android12 MultiMedia框架之MediaExtractorService

上节学到setDataSource()时会创建各种Source,source用来读取音视频源文件,读取到之后需要demux出音、视频、字幕数据流,然后再送去解码。那么负责进行demux功能的media extractor模块是在什么时候阶段创建的?这里暂时不考虑APP创建的情况,以前面学过的GenericSource为例,它是在prepare阶段被创建的。本节暂时不分析GenericSource创建extractor的流程,先来看看MediaExtractorService的启动过程。

mediaextractor

MediaExtractorService的服务名为mediaextractor:

//frameworks/av/services/mediaextractor/mediaextractor.rc
service mediaextractor /system/bin/mediaextractorclass mainuser mediaexgroup drmrpc mediadrmioprio rt 4writepid /dev/cpuset/foreground/tasks

直接看main函数:

//frameworks/av/services/mediaextractor/main_extractorservice.cpp
int main(int argc __unused, char** argv)
{#if __has_feature(hwaddress_sanitizer)ALOGI("disable media.extractor memory limits (hwasan enabled)");
#elseALOGI("enable media.extractor memory limits");limitProcessMemory("ro.media.maxmem", /* property that defines limit */SIZE_MAX, /* upper limit in bytes */20 /* upper limit as percentage of physical RAM */);
#endifsignal(SIGPIPE, SIG_IGN);//b/62255959: this forces libutis.so to dlopen vendor version of libutils.so//before minijail is on. This is dirty but required since some syscalls such//as pread64 are used by linker but aren't allowed in the minijail. By//calling the function before entering minijail, we can force dlopen.android::report_sysprop_change();SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);strcpy(argv[0], "media.extractor");sp<ProcessState> proc(ProcessState::self());sp<IServiceManager> sm = defaultServiceManager();MediaExtractorService::instantiate();ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool();
}

由于MediaExtractorService继承自模板类BinderService,所以直接调用它的instantiate()来创建service且加入service manager中:

//frameworks/native/include/binder/BinderService.h
static void instantiate() { publish(); }static status_t publish(bool allowIsolated = false,int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {sp<IServiceManager> sm(defaultServiceManager());return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,dumpFlags);
}

接下来主要看MediaExtractorService构造函数做了什么:

//frameworks/av/services/mediaextractor/MediaExtractorService.cpp
MediaExtractorService::MediaExtractorService() {MediaExtractorFactory::LoadExtractors();
}

其直接调用到MediaExtractorFactory中的LoadExtractors()方法:

//frameworks/av/media/libstagefright/MediaExtractorFactory.cpp
// static
void MediaExtractorFactory::LoadExtractors() {Mutex::Autolock autoLock(gPluginMutex);if (gPluginsRegistered) {return;}gIgnoreVersion = property_get_bool("debug.extractor.ignore_version", false);std::shared_ptr<std::list<sp<ExtractorPlugin>>> newList(new std::list<sp<ExtractorPlugin>>());android_namespace_t *mediaNs = android_get_exported_namespace("com_android_media");if (mediaNs != NULL) {const android_dlextinfo dlextinfo = {.flags = ANDROID_DLEXT_USE_NAMESPACE,.library_namespace = mediaNs,};RegisterExtractors("/apex/com.android.media/lib"
#ifdef __LP64__"64"
#endif"/extractors", &dlextinfo, *newList);} else {ALOGE("couldn't find media namespace.");}RegisterExtractors("/system/lib"
#ifdef __LP64__"64"
#endif"/extractors", NULL, *newList);RegisterExtractors("/system_ext/lib"
#ifdef __LP64__"64"
#endif"/extractors", NULL, *newList);newList->sort(compareFunc);gPlugins = newList;for (auto it = gPlugins->begin(); it != gPlugins->end(); ++it) {if ((*it)->def.def_version == EXTRACTORDEF_VERSION_NDK_V2) {for (size_t i = 0;; i++) {const char* ext = (*it)->def.u.v3.supported_types[i];if (ext == nullptr) {break;}gSupportedExtensions.push_back(std::string(ext));}}}gPluginsRegistered = true;
}

简单描述下这段代码所做的操作:

  • 创建一个list用来保存即将获取到的指向ExtractorPlugin对象的sp指针。
  • 依次到如下目录通过RegisterExtractors()方法逐个注册ExtractorPlugin到list中:
    • /apex/com.android.media/lib(64)/extractors
    • /system/lib(64)/extractors
    • /system_ext/lib(64)/extractors
  • 将list内的内容按extractor_name从小到大的顺序重新排序,并将其保存到gPlugins中。
  • 最后一个for循环,主要是将各个extractor所支持的mime type或者文件扩展名保存到gSupportedExtensions中,可用于后续查询。

再简单看看RegisterExtractors()方法:

//frameworks/av/media/libstagefright/MediaExtractorFactory.cpp
void MediaExtractorFactory::RegisterExtractors(const char *libDirPath, const android_dlextinfo* dlextinfo,std::list<sp<ExtractorPlugin>> &pluginList) {ALOGV("search for plugins at %s", libDirPath);DIR *libDir = opendir(libDirPath);if (libDir) {struct dirent* libEntry;while ((libEntry = readdir(libDir))) {if (libEntry->d_name[0] == '.') {continue;}String8 libPath = String8(libDirPath) + "/" + libEntry->d_name;if (!libPath.contains("extractor.so")) {continue;}void *libHandle = android_dlopen_ext(libPath.string(),RTLD_NOW | RTLD_LOCAL, dlextinfo);if (libHandle == nullptr) {ALOGI("dlopen(%s) reported error %s", libPath.string(), strerror(errno));continue;}GetExtractorDef getDef =(GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");if (getDef == nullptr) {ALOGI("no sniffer found in %s", libPath.string());dlclose(libHandle);continue;}ALOGV("registering sniffer for %s", libPath.string());RegisterExtractor(new ExtractorPlugin(getDef(), libHandle, libPath), pluginList);}closedir(libDir);} else {ALOGI("plugin directory not present (%s)", libDirPath);}
}

主要功能如下:

  • 遍历指定目录下的所有后缀为"extractor.so"的库并将其通过dlopen()打开。
  • 再通过dlsym()方法获取到GETEXTRACTORDEF()函数的指针。
  • 对于每一个extractor创建一个对应的ExtractorPlugin,然后将他们一个个的加入pluginList中。

到此,MediaExtractorService就启动完成了,所做的事情也是相当简单:加载目标目录下所有的extractor并保存到一个list中。

MediaExtractorService还提供了另外两个接口:makeExtractor()和makeIDataSource()。通过搜索code,大概总结一下:

  • makeIDataSource():提供给GenericSource调用,用于根据本地播放文件创建出一个IDataSource对象。这个对象进一步会被封装成一个TinyCacheSource对象,用于后面创建extractor。
  • makeExtractor():会被封装到MediaExtractorFactory::Create()方法中,该方法会被GenericSource调用,还会被JNI/JAVA调用来创建extractor。

简单以图来总结下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/41136.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深圳晶彩智能ESP32-2432S028R实时观察LVGL9效果

深圳晶彩智能ESP32-2432S028R概述&#xff1a; 深圳晶彩智能出品ESP32-32432S028R为2.8寸彩色屏采用分辨率320x240彩色液晶屏&#xff0c;驱动芯片是ILI9431。板载乐鑫公司出品ESP-WROOM-32&#xff0c;Flash 4M。型号尾部“R”标识电阻膜的感压式触摸屏&#xff0c;驱动芯片是…

基于MATLAB对线阵天线进行泰勒加权

相控阵天线——基于MATLAB对线阵进行泰勒加权 目录 前言 一、泰勒综合 二、单元间距的改变对泰勒阵列方向图的影响 三、单元数的改变对泰勒阵列激励分布的影响 四、副瓣电平SLL对泰勒阵列激励幅度的影响 五、副瓣电平SLL对泰勒阵列方向图的影响 六、泰勒阵列和切比雪夫阵…

ida动态调试-cnblog

ida动态调试 传递启动ida服务 android_server在ida\dbgsrv目录中 adb push android_server /data/local/tmp/chmod 755 /data/local/tmp/android_server /data/local/tmp/android_serveradb forward tcp:23946 tcp:23946ida报错:大多是手机端口被占用 报错提示&#xff1a; …

期末上分站——计组(3)

复习题21-42 21、指令周期是指__C_。 A. CPU从主存取出一条指令的时间 B. CPU执行一条指令的时间 C. CPU从主存取出一条指令的时间加上执行这条指令的时间。 D. 时钟周期时间 22、微型机系统中外设通过适配器与主板的系统总线相连接&#xff0c;其功能是__D_。 A. 数据缓冲和…

数据库可视化管理工具dbeaver试用及问题处理。

本文记录了在内网离线安装数据库可视化管理工具dbeaver的过程和相关问题处理方法。 一、下载dbeaver https://dbeaver.io/download/ 笔者测试时Windows平台最新版本为&#xff1a;dbeaver-ce-24.1.1-x86_64-setup.exe 二、安装方法 一路“下一步”即可 三、问题处理 1、问…

Truffle学习笔记

Truffle学习笔记 安装truffle, 注意: 虽然目前truffle最新版是 5.0.0, 但是经过我实践之后, 返现和v4有很多不同(比如: web3.eth.accounts; 都获取不到账户), 还是那句话: “nodejs模块的版本问题会搞死人的 !” 目前4.1.15之前的版本都不能用了, 只能安装v4.1.15 npm instal…

新手学Cocos报错 [Assets] Failed to open

两个都在偏好设置里面调&#xff08;文件下面的偏好设置&#xff09;&#xff1a; 1.设置中文&#xff1f; 2.报错 [Assets] Failed to open&#xff1f; 这样在点击打开ts文件的时候就不会报错&#xff0c;并且用vscode编辑器打开了&#xff0c; 同样也可以改成你们自己喜欢…

LabVIEW在图像处理中的应用

abVIEW作为一种图形化编程环境&#xff0c;不仅在数据采集和仪器控制领域表现出色&#xff0c;还在图像处理方面具有强大的功能。借助其Vision Development Module&#xff0c;LabVIEW提供了丰富的图像处理工具&#xff0c;广泛应用于工业检测、医学影像、自动化控制等多个领域…

Apache Seata应用侧启动过程剖析——RM TM如何与TC建立连接

本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 Apache Seata应用侧启动过程剖析——RM & TM如何与TC建立连接 前言 看过官网 README 的第…

Android最近任务显示的图片

Android最近任务显示的图片 1、TaskSnapshot截图1.1 snapshotTask1.2 drawAppThemeSnapshot 2、导航栏显示问题3、Recentan按键进入最近任务 1、TaskSnapshot截图 frameworks/base/services/core/java/com/android/server/wm/TaskSnapshotController.java frameworks/base/cor…

解决C++编译时的产生的skipping incompatible xxx 错误

问题 我在编译项目时&#xff0c;产生了一个 /usr/bin/ld: skipping incompatible ../../xxx/ when searching for -lxxx 的编译错误&#xff0c;如下图所示&#xff1a; 解决方法 由图中的错误可知&#xff0c;在编译时&#xff0c;是能够在我们指定目录下的 *.so 动态库的…

python函数和c的区别有哪些

Python有很多内置函数&#xff08;build in function&#xff09;&#xff0c;不需要写头文件&#xff0c;Python还有很多强大的模块&#xff0c;需要时导入便可。C语言在这一点上远不及Python&#xff0c;大多时候都需要自己手动实现。 C语言中的函数&#xff0c;有着严格的顺…

Java基础(六)——继承

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 ⚡开源项目&#xff1a; rich-vue3 &#xff08;基于 Vue3 TS Pinia Element Plus Spring全家桶 MySQL&#xff09; &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1…

【Web】

1、配仓库 [rootlocalhost yum.repos.d]# vi rpm.repo ##本地仓库标准写法 [baseos] namemiaoshubaseos baseurl/mnt/BaseOS gpgcheck0 [appstream] namemiaoshuappstream baseurlfile:///mnt/AppStream gpgcheck0 2、挂载 [rootlocalhost ~]mount /dev/sr0 /mnt mount: /m…

Vulnhub-Os-hackNos-1(包含靶机获取不了IP地址)

https://download.vulnhub.com/hacknos/Os-hackNos-1.ova #靶机下载地址 题目&#xff1a;要找到两个flag user.txt root.txt 文件打开 改为NAT vuln-hub-OS-HACKNOS-1靶机检测不到IP地址 重启靶机 按住shift 按下键盘字母"E"键 将图中ro修改成…

Vue 3集成krpano 全景图展示

Vue 3集成krpano 全景图展示 星光云全景系统源码 VR全景体验地址 星光云全景VR系统 将全景krpano静态资源文件vtour放入vue项目中 导入vue之前需要自己制作一个全景图 需要借助官方工具进行制作 工具下载地址&#xff1a;krpano工具下载地址 注意事项&#xff1a;vuecli…

Hook 实现 Windows 系统热键屏蔽(二)

目录 前言 一、介绍用户账户控制&#xff08;UAC&#xff09; 1.1 什么是 UAC &#xff1f; 2.2 UAC 运行机制的概述 2.3 分析 UAC 提权参数 二、 NdrAsyncServerCall 函数的分析 2.1 函数声明的解析 2.2 对 Winlogon 的逆向 2.3 对 rpcrt4 的静态分析 2.4 对 rpcrt4…

YOLOv8_obb数据集可视化[旋转目标检测实践篇]

先贴代码,周末再补充解析。 这个篇章主要是对标注好的标签进行可视化,虽然比较简单,但是可以从可视化代码中学习到YOLOv8是如何对标签进行解析的。 import cv2 import numpy as np import os import randomdef read_obb_labels(label_file_path):with open(label_file_path,…

清新简约之美,开源个人博客:Jekyll Theme Chirpy

Jekyll Theme Chirpy&#xff1a;简约不简单&#xff0c;Chirpy 让你的博客焕发新意- 精选真开源&#xff0c;释放新价值。 概览 Jekyll Theme Chirpy 是为Jekyll静态网站生成器设计的现代主题&#xff0c;以其清新、简约的设计风格和用户友好的交互体验受到开发者和博客作者的…

为企业知识库选模型?全球AI大模型知识库RAG场景基准测试排名

大语言模型常见基准测试 大家对于AI模型理解和推理能力的的基准测试一定非常熟悉了&#xff0c;比如MMLU&#xff08;大规模多任务语言理解&#xff09;、GPQA&#xff08;研究生级别知识问答&#xff09;、GSMSK&#xff08;研究生数学知识考察&#xff09;、MATH&#xff08…