Android12 MultiMedia框架之MediaExtractorService

news2024/12/29 7:42:20

上节学到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/mediaextractor
    class main
    user mediaex
    group drmrpc mediadrm
    ioprio rt 4
    writepid /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)");
#else
    ALOGI("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 */);
#endif

    signal(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.coloradmin.cn/o/1884738.html

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

相关文章

6 月份获得了 10000 星的开源项目!

01 开源学习资源的宝库 在这个信息爆炸的时代&#xff0c;想要深入学习一项技术&#xff0c;却常常被海量资源淹没。别担心&#xff0c;Build Your Own X 项目来帮你&#xff01; 这是一个集合了各种技术主题的开源学习资源库&#xff0c;旨在引导开发者通过实践来掌握核心概念…

提升入住率|智慧酒店解决方案,打造有温度的居住体验!

近年来&#xff0c;智慧酒店被越来越多的人关注&#xff0c;由生物识别、物联网技术和互联网技术融合产生的智慧酒店解决方案&#xff0c;不仅可以提升顾客在酒店的入住体验&#xff0c;还可以帮助酒店降低运营成本&#xff0c;这也让越来越的酒店选择了智慧酒店的赛道&#xf…

【windows|012】光猫、路由器、交换机详解

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 ​ &#x1f3c5;阿里云ACE认证高级工程师 ​ &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社…

CV每日论文--2024.6.28

1、On Scaling Up 3D Gaussian Splatting Training 中文标题&#xff1a;扩展 3D 高斯泼溅训练 简介&#xff1a;3D高斯点描(3DGS)由于其卓越的视觉质量和渲染速度,越来越受欢迎用于3D重建。然而,3DGS的训练目前仅在单个GPU上进行,由于内存限制,它的处理高分辨率和大规模3D重建…

基于C语言+控制台的学生信息管理系统

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、Php、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

Python:Python环境搭建

二、Python环境搭建 1.Python安装指南 &#xff08;1&#xff09;打开文件夹双击python-3.8.5-amd64.exe&#xff0c;进入安装页面&#xff0c;选择自定义安装&#xff0c;并且勾选环境变量。 &#xff08;2&#xff09;自定义安装时&#xff0c;跳出窗口&#xff0c;所有功能…

大力出奇迹:大语言模型的崛起与挑战

随着人工智能&#xff08;AI&#xff09;技术的迅猛发展&#xff0c;特别是在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;大语言模型&#xff08;LLM&#xff09;的出现与应用&#xff0c;彻底改变了我们与机器互动的方式。本文将探讨ChatGPT等大语言模型的定义、…

IPIDEA代理IP助力高效数据采集

IPIDEA代理IP助力高效数据采集 文章目录 IPIDEA代理IP助力高效数据采集&#x1f4d1;前言一、爬虫数据采集痛点二、代理IP解决爬虫痛点2.1 为什么可以2.2 选择代理IP的关键因素 三、IPIDEA海外IP代理的优势3.1 IPIDEA的显著优势3.2 IPIDEA的代理类型及应用 四、IPIDEA爬虫实战4…

复分析——第10章——Θ函数应用(E.M. Stein R. Shakarchi)

第10章 Θ函数的应用 (Applications of Theta Functions) The problem of the representation of an integer n as the sum of a given number k of integral squares is one of the most celebrated in the theory of numbers. Its history may be traced back to Diopha…

JS逆向技巧总结

总的来说&#xff0c;JavaScript 逆向可以分为三大部分&#xff1a;寻找入口、调试分析和模拟执行。下面分别进行介绍。 一&#xff0c;寻找入口 一个网站加载了很多 JavaScript 文件&#xff0c;那么怎么从这么多 JavaScript 里面找到关键的位置&#xff0c;那就是一个关键问…

Outlook发送大文件的问题是什么?怎么解决?

Outlook不仅是一款电子邮件客户端&#xff0c;还包括日历、任务、笔记、联系人等功能&#xff0c;同时与Microsoft Office套件中的其他应用程序&#xff08;如Word、Excel、PowerPoint等&#xff09;集成紧密&#xff0c;方便用户在不同应用程序之间切换&#xff0c;提高工作效…

计算机毕业设计Python+Spark股票基金推荐与预测系统 股票基金可视化 股票基金推荐系统 股票基金可视化系统 股票基金数据分析 股票基金爬虫大数据

目 录 摘 要 Abstract 第1章 前 言 1.1 项目的背景和意义 1.2 研究现状 1.3 项目的目标和范围 1.4 论文结构简介 第2章 技术与原理 2.1 开发原理 2.2 开发工具 2.3 关键技术 第3章 需求建模 3.1 系统可行性分析 3.2 功能需求分析 3.3 非功能性…

Kafka-服务端-副本同步-源码流程

杂 在0.9.0.0之前&#xff0c;Kafka提供了replica lag.max.messages 来控制follower副本最多落后leader副本的消息数量&#xff0c;follower 相对于leader 落后当超过这个数量的时候就判定该follower是失效的&#xff0c;就会踢出ISR&#xff0c;这里的指的是具体的LEO值。 对…

为Stable Diffusion换件新衣服

你是不是已经看腻Stable Diffusion默认的webui了&#xff0c;想要换件新衣服。Lobe Theme这个插件就可以帮助你。 首先&#xff0c;我们启动 SD&#xff0c;如果没有安装&#xff0c;可以参考https://mp.csdn.net/mp_blog/creation/editor/139196688。 然后找到扩展选项卡&…

网络安全--计算机网络安全概述

文章目录 网络信息系统安全的目标网络安全的分支举例P2DR模型信息安全模型访问控制的分类多级安全模型 网络信息系统安全的目标 保密性 保证用户信息的保密性&#xff0c;对于非公开的信息&#xff0c;用户无法访问并且无法进行非授权访问&#xff0c;举例子就是&#xff1a;防…

鸿蒙OS开发者高级学习第2课:自由流转(含习题答案)

自由流转两种形态&#xff1a;相继使用&#xff08;跨端迁移&#xff09;&#xff1b;同时使用&#xff08; 多端协同&#xff09; 习题&#xff1a;

linux 用户、用户组操作

一、用户组操作 用户组&#xff08;group&#xff09;就是具有相同特征的用户&#xff08;user&#xff09;的集合体&#xff1b;比如有时我们要让多个用户具有相同的权限&#xff0c;比如查看、修改某一文件或执行某个命令&#xff0c;这时我们需要用户组&#xff0c;我们把用…

8种数据迁移工具

前言 最近有些小伙伴问我&#xff0c;ETL数据迁移工具该用哪些。 ETL(是Extract-Transform-Load的缩写&#xff0c;即数据抽取、转换、装载的过程)&#xff0c;对于企业应用来说&#xff0c;我们经常会遇到各种数据的处理、转换、迁移的场景。 今天特地给大家汇总了一些目前…

Ubuntu 22.04 安装中文字体

笔者在用OpenCV4.9处理图片加水印时&#xff0c;中文乱码。原来是Ubuntu 22.04发行版缺少中文字体支持&#xff0c;因此&#xff0c;笔者就找资料安装了需要的中文字体&#xff0c;特此记录&#xff0c;以备后查。 1、打开终端&#xff1a; 2、更新软件包列表&#xff1a; su…

7基于SpringBoot的SSMP整合案例-表现层开发

目录 1.基于Restfu1进行表现层接口开发 1.1创建功能类 1.2基于Restful制作表现层接口 2.接收参数 2使用Apifox测试表现层接口功能 保存接口&#xff1a; 分页接口&#xff1a; 3.表现层一致性处理 3.1先创建一个工具类&#xff0c;用作后端返回格式统一类&#xff1a;…