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