一、引言: OMX作为跨平台的多媒体解码框架,在Android上使用的尤其广泛,不论是Android移动平台还是Android TV,OMX已经成为了硬解通路的必然选择,在Android原生的媒体服务上,OMX是stagefright框架的底层重要支撑,随着Android版本的提升,媒体相关的服务被逐渐细化,Android P上,OMX被划到MediaCodec的服务中。
二、OMX服务启动及插件加载: Android的init.rc 脚本会去执行android.hardware.media.omx@1.0-service.rc 脚本(framework/av/services/mediacodec):
service vendor.media.omx /vendor/bin/hw/android.hardware.media.omx@1.0-service
class main
user mediacodec
group camera drmrpc mediadrm
capabilities SYS_NICE
ioprio rt 4
writepid /dev/cpuset/foreground/tasks
脚本会去启动android.hardware.media.omx@1.0-service服务,从对应路径下的mk可以看到,这个服务是由main_codecservice.cpp 编译出来的,下面看一下其main函数:
int main(int argc __unused, char** argv)
{
strcpy(argv[0], "media.codec");
LOG(INFO) << "mediacodecservice starting";
signal(SIGPIPE, SIG_IGN);
SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
android::ProcessState::initWithDriver("/dev/vndbinder");
android::ProcessState::self()->startThreadPool();
::android::hardware::configureRpcThreadpool(64, false);
void *registrantLib = dlopen(
"libmedia_codecserviceregistrant.so",
RTLD_NOW | RTLD_LOCAL);
if (registrantLib) {
RegisterCodecServicesFunc registerCodecServices =
reinterpret_cast<RegisterCodecServicesFunc>(
dlsym(registrantLib, "RegisterCodecServices"));
if (registerCodecServices) {
registerCodecServices();
} else {
LOG(WARNING) << "Cannot register additional services "
"-- corrupted library.";
}
} else {
using namespace ::android::hardware::media::omx::V1_0;
sp<IOmxStore> omxStore = new implementation::OmxStore();
if (omxStore == nullptr) {
LOG(ERROR) << "Cannot create IOmxStore HAL service.";
} else if (omxStore->registerAsService() != OK) {
LOG(ERROR) << "Cannot register IOmxStore HAL service.";
}
sp<IOmx> omx = new implementation::Omx();
if (omx == nullptr) {
LOG(ERROR) << "Cannot create IOmx HAL service.";
} else if (omx->registerAsService() != OK) {
LOG(ERROR) << "Cannot register IOmx HAL service.";
} else {
LOG(INFO) << "IOmx HAL service created.";
}
}
::android::hardware::joinRpcThreadpool();
}
main函数中会去实例化OMX,看一下OMX的构造函数:
Omx::Omx() :
mMaster(new OMXMaster()),
mParser() {
}
这里会去实例化OMXMaster :
OMXMaster::OMXMaster()
: mVendorLibHandle(NULL) {
pid_t pid = getpid();
char filename[20];
snprintf(filename, sizeof(filename), "/proc/%d/comm", pid);
int fd = open(filename, O_RDONLY);
if (fd < 0) {
ALOGW("couldn't determine process name");
strlcpy(mProcessName, "<unknown>", sizeof(mProcessName));
} else {
ssize_t len = read(fd, mProcessName, sizeof(mProcessName));
if (len < 2) {
ALOGW("couldn't determine process name");
strlcpy(mProcessName, "<unknown>", sizeof(mProcessName));
} else {
mProcessName[len - 1] = 0;
}
close(fd);
}
addVendorPlugin();
addPlugin(new SoftOMXPlugin);
}
我们重点关注addVendorPlugin() :
void OMXMaster::addVendorPlugin() {
addPlugin("libstagefrighthw.so");
}
看下addPlugin :
void OMXMaster::addPlugin(const char *libname) {
mVendorLibHandle = android_load_sphal_library(libname, RTLD_NOW);
if (mVendorLibHandle == NULL) {
return;
}
typedef OMXPluginBase *(*CreateOMXPluginFunc)();
CreateOMXPluginFunc createOMXPlugin =
(CreateOMXPluginFunc)dlsym(
mVendorLibHandle, "createOMXPlugin");
if (!createOMXPlugin)
createOMXPlugin = (CreateOMXPluginFunc)dlsym(
mVendorLibHandle, "_ZN7android15createOMXPluginEv");
if (createOMXPlugin) {
addPlugin((*createOMXPlugin)());
}
}
这里会去加载libstagefrighthw.so 并且重定向到函数createOMXPlugin 。到这里需要确认一个问题,芯片平台的libstagefrighthw.so 是从哪里来的,其对应的createOMXPlugin 函数是如何实现的。我目前使用的是MTK的芯片平台,库是由MTK自己命名的文件编译出来的,只要保证库名是libstagefrighthw.so 并且实现一些OMX标准组件的接口,就可以加载芯片平台的硬解库了,找到对应的源码及函数createOMXPlugin :
OMXPluginBase *createOMXPlugin() {
return new MSOMXPlugin;
}
这里会去构造芯片平台自己的MSOMXPlugin 类对象:
MSOMXPlugin::MSOMXPlugin()
: mLibHandle(dlopen("libOMX.MStar.so", RTLD_NOW)),
mInit(NULL),
mDeinit(NULL),
mComponentNameEnum(NULL),
mGetHandle(NULL),
mFreeHandle(NULL),
mGetRolesOfComponentHandle(NULL),
mSetupTunnel(NULL),
mTearDownTunnel(NULL) {
ALOGD("MSOMXPlugin::MSOMXPlugin");
if (mLibHandle != NULL) {
ALOGD("Get libOMX.MStar.so");
mInit = (InitFunc)dlsym(mLibHandle, "MS_OMX_Init");
mDeinit = (DeinitFunc)dlsym(mLibHandle, "MS_OMX_DeInit");
mComponentNameEnum =
(ComponentNameEnumFunc)dlsym(mLibHandle, "MS_OMX_ComponentNameEnum");
mGetHandle = (GetHandleFunc)dlsym(mLibHandle, "MS_OMX_GetHandle");
mFreeHandle = (FreeHandleFunc)dlsym(mLibHandle, "MS_OMX_FreeHandle");
mGetRolesOfComponentHandle =
(GetRolesOfComponentFunc)dlsym(
mLibHandle, "MS_OMX_GetRolesOfComponent");
#ifdef BUILD_GOOGLETV
mSetupTunnel = (SetupTunnelFunc)dlsym(mLibHandle, "MS_OMX_SetupTunnel");
mTearDownTunnel = (SetupTunnelFunc)dlsym(mLibHandle, "MS_OMX_TearDownTunnel");
#endif
CHECK(mInit != NULL);
(*mInit)();
...
}
函数包含的信息非常多,首先会去打开芯片平台的动态库,其次重定向各个OMX组件重要的函数指针,最后还会调用mInit 指向的函数做进一步的初始化。这里就把整个OMX服务的启动分析完了。
三、总结: 1.OMX服务是隶属于MediaCodec的binder服务下的子项,在系统服务启动的时候,会去加载MediaCodec的服务,OMX软解的库是一定会加载的,如果芯片平台支持硬解会去加载OMX的硬解库; 2.重启mediaserver 进程可以重新加载OMX的硬解库,后续有应用申请OMX组件将以OMX client的方式去访问;
|