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。
简单以图来总结下:

相关文章:
Android12 MultiMedia框架之MediaExtractorService
上节学到setDataSource()时会创建各种Source,source用来读取音视频源文件,读取到之后需要demux出音、视频、字幕数据流,然后再送去解码。那么负责进行demux功能的media extractor模块是在什么时候阶段创建的?这里暂时不考虑APP创建…...
Chapter 8 Feedback
Chapter 8 Feedback 这一章我们介绍feedback 反馈运放的原理. 负反馈是模拟电路强有力的工具. 8.1 General Considerations 反馈系统如下图所示 Aolamp open-loop gain即开环增益. Aolxo/xi β \beta β 是 feedback factor, 注意方向. β x f x o \beta\frac{x_{f}}{x_{o…...
Administrators就最高了???system是什么??本地用户提权内网学习第三天 你知道uac是什么??
我们今天来说说本地用户提权的操作,我们在有webshell过后我们要进行进一步的提权操作,要不然对我们后期的内网渗透会有一些阻碍的操作。比如说我们使用mimikatz来进行抓取密码,就不能够成功。 Administrators与system的区别 我们来说说Admin…...
回溯 | Java | LeetCode 39, 40, 131 做题总结(未完)
Java Arrays.sort(数组) //排序 不讲究顺序的解答,都可以考虑一下排序是否可行。 39. 组合总和 错误解答 在写的时候需要注意,sum - candidates[i];很重要,也是回溯的一部分。 解答重复了。是因为回溯的for循环理解错了。 class Solutio…...
Linux系统上部署Whisper。
Whisper是一个开源的自动语音识别(ASR)模型,最初由OpenAI发布。要在本地Linux系统上部署Whisper,你可以按照以下步骤进行: 1. 创建虚拟环境 为了避免依赖冲突,建议在虚拟环境中进行部署。创建并激活一个新…...
申请一张含100个域名的证书-免费SSL证书
挑战一下,申请一张包含100个域名的证书 首先,我们访问来此加密网站,进入登录页面,输入我的账号密码。 登录后,咱们就可以开始申请证书,首先说一下,咱账号是SVIP哦,只有SVIP才可以申…...
爬数据是什么意思?
爬数据的意思是:通过网络爬虫程序来获取需要的网站上的内容信息,比如文字、视频、图片等数据。网络爬虫(网页蜘蛛)是一种按照一定的规则,自动的抓取万维网信息的程序或者脚本。 学习一些爬数据的知识有什么用呢&#x…...
Pytorch实战(二)
文章目录 前言一、LeNet5原理1.1LeNet5网络结构1.2LeNet网络参数1.3LeNet5网络总结 二、AlexNext2.1AlexNet网络结构2.2AlexNet网络参数2.3Dropout操作2.4PCA图像增强2.5LRN正则化2.6AlexNet总结 三、LeNet实战3.1LeNet5模型搭建3.2可视化数据3.3加载训练、验证数据集3.4模型训…...
wordpress 付费主题modown分享,可实现资源付费
该主题下载地址 下载地址 简介 Modown是基于Erphpdown 会员下载插件开发的付费下载资源、付费下载源码、收费附件下载、付费阅读查看隐藏内容、团购下载的WordPress主题,一款针对收费付费下载资源/付费查看内容/付费阅读/付费视频/VIP会员免费下载查看/虚拟资源售…...
【INTEL(ALTERA)】NIOS II调试器中的重新启动按钮不起作用
目录 说明 解决方法 说明 在 Nios II SBT 调试Eclipse时,如果单击 重新启动 图标, 执行被暂停, 以下错误消息: Dont know how to run. Try "help target." 解决方法 终止程序,再次下载,并启…...
Hive On Spark语法
内层对象定义之特殊数据类型 Array DROP TABLE IF EXISTS test_table_datatype_array; CREATE TABLE test_table_datatype_array (ids array<INT> ) LOCATION test/test_table_datatype_array;SELECTnames,names[1]array(names[2],names[3])names[5],names[-1],array_c…...
利用 fail2ban 保护 SSH 服务器
利用 fail2ban 保护 SSH 服务器 一、关于 fail2ban1. 基本功能与特性2. 工作原理 二、安装与配置1. Debian/Ubuntu系统:2. CentOS/RHEL系统: 三、保护 SSH四、启动 fail2ban 服务五、测试和验证六、查看封禁的 IP 地址七、一些配置八、注意事项 作者&…...
在TkinterGUI界面显示WIFI网络摄像头(ESP32s3)视频画面
本实验结合了之前写过的两篇文章Python调用摄像头,实时显示视频在Tkinter界面以及ESP32 S3搭载OV2640摄像头释放热点(AP)工作模式–Arduino程序,当然如果手头有其他可以获得网络摄像头的URL即用于访问摄像头视频流的网络地址&…...
Yolov8训练时遇到报错SyntaxError: ‘image_weights‘ is not a valid YOLO argument.等问题解决方案
报错说明 line 308, in check_dict_alignmentraise SyntaxError(string CLI_HELP_MSG) from e SyntaxError: image_weights is not a valid YOLO argument. v5loader is not a valid YOLO argument. fl_gamma is not a valid YOLO argument. 解决方法 将训练文件中model.tr…...
javaweb(四)——过滤器与监听器
文章目录 过滤器Filter基本概念滤波器的分类: 时域和频域表示滤波器类型1. 低通滤波器(Low-Pass Filter)2. 高通滤波器(High-Pass Filter)3. 带通滤波器(Band-Pass Filter)4. 带阻滤波器(Band-Stop Filter) 滤波器参数1. 通带频率(Passband Frequency)2. 截止频率(Cutoff Frequ…...
冗余电源的应用,哪些工作站支持冗余电源
冗余电源是一种通过多组电源模块进行备份的技术手段,采用热备插拔式设计,使备用电源在主要电源失效时自动启动,从而确保电源供应不间断。 冗余电源通常应用于对电力要求极高的关键设备和系统,如医疗设备、核电站、数据中心等。在…...
[信号与系统]IIR滤波器与FIR滤波器相位延迟定量的推导。
IIR滤波器与FIR滤波器最大的不同:相位延迟 IIR滤波器相位延迟分析 相位响应和延迟 这里讨论一下理想延迟系统的相位延迟。 对于一个给定的系统频率响应 H ( e j w ) H(e^{jw}) H(ejw)可以表示为 H ( e j w ) ∣ H ( e j w ) ∣ e Φ ( w ) H(e^{jw}) |H(e^{jw…...
Python海量数据处理脚本大集合:pyWhat
pyWhat:精简海联数据,直达数据弱点要害- 精选真开源,释放新价值。 概览 pyWhat是Github社区上一款比较实用的开源Python脚本工具。它能够快速提取信息中的 IP 地址、邮箱、信用卡、数字货币钱包地址、YouTube 视频等内容。当你遇到了一串莫名…...
postgresql搭建
搭建postgresql-11.3,和客户端工具 1,准备对应的包,右键直接下一步安装完即可, 将postgresql设置为本地服务,方便启动, 2,用对应客户端软件连接,新建一个数据库controlDB 新建用户…...
Web 品质标准
Web 品质标准 引言 随着互联网的快速发展,Web应用已经渗透到我们生活的方方面面。为了确保Web应用的质量,提高用户体验,Web品质标准应运而生。这些标准涵盖了多个方面,包括性能、安全性、可访问性、用户体验等。本文将详细介绍这些标准,并探讨它们在实际开发中的应用。 …...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving
地址:LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂,正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...
