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品质标准应运而生。这些标准涵盖了多个方面,包括性能、安全性、可访问性、用户体验等。本文将详细介绍这些标准,并探讨它们在实际开发中的应用。 …...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...
Linux基础开发工具——vim工具
文章目录 vim工具什么是vimvim的多模式和使用vim的基础模式vim的三种基础模式三种模式的初步了解 常用模式的详细讲解插入模式命令模式模式转化光标的移动文本的编辑 底行模式替换模式视图模式总结 使用vim的小技巧vim的配置(了解) vim工具 本文章仍然是继续讲解Linux系统下的…...
