AOSP视频解码流程 —— OMX加载goldfish插件流程
1. android媒体框架
本篇文章主要分析下图中libstagefrighthw.so如何加载到OMX Core中。
应用框架
应用代码位于应用框架层,利用 android.media API 与多媒体硬件进行交互。
Binder IPC
Binder IPC 代理用于促进跨越进程边界的通信。 这些代理位于 frameworks/av/media/libmedia
目录中,并以字母“I”开头。
原生多媒体框架
在原生层,Android 提供了一个利用 Stagefright 引擎进行音频和视频录制及播放的多媒体框架。Stagefright 随附支持的软件编解码器的默认列表,并且您可以使用 OpenMax 集成层标准实现自己的硬件编解码器。如需了解实现的更多详情,请参阅位于 frameworks/av/media
中的 MediaPlayer 和 Stagefright 组件。
OpenMAX 集成层 (IL)
OpenMAX IL 为 Stagefright 提供了一种标准化的方式识别和使用基于硬件的自定义多媒体编解码器(称为组件)。您必须以名为 libstagefrighthw.so
的共享库的形式提供 OpenMAX 插件。此插件将 Stagefright 与您的自定义编解码器组件相连接,并且该组件必须根据 OpenMAX IL 组件标准实现。
二. OMX加载goldfish视频编解码插件
frameworks/av/media/libstagefright/omx/OMXMaster.cpp
OMXMaster构造函数内调用addVendorPlugin方法,加载名为"libstagefrighthw.so"的插件,"libstagefrighthw.so"是厂商提供的,如果是goldfish层生效的话,此处的so应该是goldfish层编译生成。
附代码如下:
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 { // the name is newline terminated, so erase the newline mProcessName[len - 1] = 0; } close(fd); } addVendorPlugin(); addPlugin(new SoftOMXPlugin); } OMXMaster::~OMXMaster() { clearPlugins(); if (mVendorLibHandle != NULL) { dlclose(mVendorLibHandle); mVendorLibHandle = NULL; } } void OMXMaster::addVendorPlugin() { addPlugin("libstagefrighthw.so"); }
三.goldfish视频编解码提供上层封装接口
OMXMaster为编解码器提供了统计的插件话管理,对于goldfish层的视频解码器,同样对外封装了统一的接口,供外部调用。
device/generic/goldfish-opengl/system/codecs/omx/plugin/GoldfishOMXPlugin.cpp
对外提供接口如下:
OMXPluginBase *createOMXPlugin() { ALOGD("called createOMXPlugin for Goldfish"); return new GoldfishOMXPlugin; }
OMXMaster调动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)()); } }
至此,OMX与goldfish层解码模块绑定,具体需要使用哪一种解码器,可以修改GoldfishOMXPlugin.cpp文件中的编解码列表,并自行实现。代码如下:
static const GoldfishComponent kComponents[] = { {"OMX.google.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8"}, {"OMX.google.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9"}, {"OMX.google.goldfish.h264.decoder", "avcdec", "video_decoder.avc"}, {"OMX.android.goldfish.vp8.decoder", "vpxdec", "video_decoder.vp8"}, {"OMX.android.goldfish.vp9.decoder", "vpxdec", "video_decoder.vp9"}, {"OMX.android.goldfish.h264.decoder", "avcdec", "video_decoder.avc"}, };
四. goldfish视频编解码插件编译
goldfish层是如何通过编译文件生成libstagefrighthw.so的
device/generic/goldfish-opengl/system/codecs/omx/plugin/Android.mk
文件中有如下命令:
$(call emugl-begin-shared-library,libstagefrighthw$(GOLDFISH_OPENGL_LIB_SUFFIX))
该命令的含义为以libstagefrighthw为参数传入emugl-begin-shared-library函数内,并执行emugl-begin-shared-library调用函数。
继续转入mk文件:device/generic/goldfish-opengl/common.mk
emugl-begin-module = \ $(eval include $(CLEAR_VARS)) \ $(eval LOCAL_MODULE := $1) \ $(eval LOCAL_MODULE_CLASS := $(patsubst HOST_%,%,$(patsubst %EXECUTABLE,%EXECUTABLES,$(patsubst %LIBRARY,%LIBRARIES,$2)))) \ $(eval LOCAL_IS_HOST_MODULE := $(if $3,true,))\ $(eval LOCAL_C_INCLUDES := $(EMUGL_COMMON_INCLUDES)) \ $(eval LOCAL_CFLAGS := $(EMUGL_COMMON_CFLAGS)) \ $(eval _EMUGL_INCLUDE_TYPE := $(BUILD_$2)) \ $(call _emugl-init-module,$1,$2,$3)
这里$1则为libstagefrighthw
此为mk基础命令,用于生成libstagefrighthw.so。