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.pswp.cn/web/41136.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/41136.shtml
英文地址,請注明出處:http://en.pswp.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對泰勒陣列方向圖的影響 六、泰勒陣列和切比雪夫陣…

量化交易在不同經濟周期中的表現

量化交易&#xff0c;作為一種基于算法和數學模型的交易方法&#xff0c;其在不同經濟周期中的表現受到了市場參與者的廣泛關注。量化交易策略的設計使其能夠在多種市場環境中尋找投資機會&#xff0c;無論是經濟擴張期還是衰退期&#xff0c;都能夠展現出其獨特的適應性和效率…

7.6數據結構作業

// 練習一 struct K { double a; //8 char b; //1 char c; //1 double d; //8 };//24 // 練習二 struct L { int a; //4 double b; //8 char c; //1 };//24 // 練習三 struct M { char a;//1 int b; //4 char c; //1 double d; //8 };//24 /…

(5) 深入探索Python-Pandas庫的核心數據結構:Series詳解

目錄 前言1. Series 簡介2. Series的特點3. Series的創建3.1 使用列表創建Series3.2 使用字典創建Series3.3 使用列表和自定義索引創建Series3.4 指定數據類型和名稱 4. Series的索引/切片4.1 下標索引&#xff1a;基于整數位置的索引4.2 基于標簽的索引4.3 切片4.4 使用.loc[]…

觸感網絡:WebKit 振動(Vibration API)的交互新維度

觸感網絡&#xff1a;WebKit 振動&#xff08;Vibration API&#xff09;的交互新維度 在數字化時代&#xff0c;用戶體驗的追求已經不僅限于視覺和聽覺&#xff0c;觸覺反饋也逐漸成為網頁交互設計的重要組成部分。WebKit 作為眾多現代瀏覽器的核心技術引擎&#xff0c;對振動…

Linux 文件描述符 fd

當然&#xff0c;以下是一些關于 Linux 文件描述符&#xff08;fd&#xff09;的示例&#xff0c;以清晰、分點表示和歸納的形式給出&#xff1a; 1. 文件描述符的基本概念和用途 定義&#xff1a;文件描述符是一個非負整數&#xff0c;用于指代被進程所打開或使用的文件、套…

Leetcode 59. 螺旋打印矩陣

題目描述 給你一個正整數 n &#xff0c;生成一個包含 1 到 n2 所有元素&#xff0c;且元素按順時針順序螺旋排列的 n x n 正方形矩陣 matrix 。 示例 1&#xff1a; 輸入&#xff1a;n 3 輸出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]] 示例 2&#xff1a; 輸入&#xff1a;n…

c++中new和delete重載的一點介紹

通義千問中作答的&#xff0c;感覺回答的比自己總結的好&#xff1a; 實際上&#xff0c;你可以在C中重載new和delete運算符。重載new和delete允許你自定義內存分配和釋放的行為&#xff0c;這對于實現特殊的內存管理策略非常有用&#xff0c;例如&#xff1a; 內存池&#xf…

系統遷移從CentOS7.9到Rocky8.9

我有兩臺阿里云上的服務器是CentOS7.9&#xff0c;由于CentOS7已經停止支持&#xff0c;后續使用的話會有安全漏洞&#xff0c;所以需要盡快遷移&#xff0c;個人使用的話目前兼容性好的還是RockyLinux8&#xff0c;很多腳本改改就能用了。 一、盤點系統和遷移應用 查看當前系…

AI在軟件開發中的革新與未來挑戰

目錄 前言 AI工具的廣泛應用與優勢 AI與開發者技能需求的互動關系 AI的未來展望與面臨的挑戰 結語 前言 在當今快速發展的技術領域中&#xff0c;生成式人工智能&#xff08;AIGC&#xff09;正以前所未有的方式改變著軟件開發的面貌。從代碼生成到錯誤檢測&#xff0c;再…

linux內核源碼學習所需基礎

1.面向對象的思想&#xff0c;尤其是oopc的實現方式。 2.設計模式。 這兩點需要內核源碼學習者不僅要會c和匯編&#xff0c;還要接觸一門面向對象的語言&#xff0c;比如c&#xff0b;&#xff0b;/java/python等等任意一門都行&#xff0c;起碼要了解面向對象的思想。 另外li…

MyBatis 框架核心及面試知識要點

1、什么是 MyBatis? MyBatis 是一款優秀的支持自定義 SQL 查詢、存儲過程和高級映射的持久層框架&#xff0c;消除了 幾乎所有的 JDBC 代碼和參數的手動設置以及結果集的檢索 。 MyBatis 可以使用 XML,或注解進 行配置和映射&#xff0c;MyBatis 通過將參數映射到配置的 SOL,形…

FastSpeech2中文語音合成就步解析:TTS數據訓練實戰篇

參考github網址&#xff1a; GitHub - roedoejet/FastSpeech2: An implementation of Microsoft’s “FastSpeech 2: Fast and High-Quality End-to-End Text to Speech” 數據訓練所用python 命令&#xff1a; python3 train.py -p config/AISHELL3/preprocess.yaml -m confi…

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; …

java面試-java基礎(下)

文章目錄 一、和equals區別&#xff1f;二、hashcode方法作用&#xff1f;兩個對象的hashCode方法相同&#xff0c;則equals方法也一定為true嗎&#xff1f;三、為什么重寫equals方法就一定要重寫hashCode方法&#xff1f;四、Java中的參數傳遞時傳值呢還是傳引用&#xff1f;五…

期末上分站——計組(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、問…

【深度學習】vscode 命令行下的debug

其實我一直知道vscode可以再命令行下進行debug。 比如 python aaa.py --bb1 --cc2 以前的做法是 去aaa.py 寫死bb和cc 然后直接debug。 直到今天我遇到這個&#xff1a; hydra hydra.main(version_baseNone, config_name/home/justin/Desktop/code/python_project/WASB-SBDT-m…

Truffle學習筆記

Truffle學習筆記 安裝truffle, 注意: 雖然目前truffle最新版是 5.0.0, 但是經過我實踐之后, 返現和v4有很多不同(比如: web3.eth.accounts; 都獲取不到賬戶), 還是那句話: “nodejs模塊的版本問題會搞死人的 !” 目前4.1.15之前的版本都不能用了, 只能安裝v4.1.15 npm instal…