媒体编解码API使用示例
//获取相关格式文件的内容信息,如轨道数量、获取MIME信息、视频的高度与宽度、语言格式、播放总时长等
MediaExtractor mediaExtractor = new MediaExtractor();
try {
mediaExtractor.setDataSource(path); // 设置数据源
} catch (IOException e1) {
e1.printStackTrace();
}
String mimeType = null; // "video/mp4v-es" - MPEG4 video, "audio/3gpp" - AMR narrowband audio
for (int i = 0; i < mediaExtractor.getTrackCount(); i++) { // 信道总数
MediaFormat format = mediaExtractor.getTrackFormat(i); // 音频文件信息
mimeType = format.getString(MediaFormat.KEY_MIME);
if (mimeType.startsWith("video/")) { // 视频信道
mediaExtractor.selectTrack(i); // 切换到视频信道
try {
mediaCodec = MediaCodec.createDecoderByType(mimeType); // 创建解码器,提供数据输出
} catch (IOException e) {
e.printStackTrace();
}
mediaCodec.configure(format, surface, null, 0);
break;
}
}
mediaCodec.start(); // 启动MediaCodec ,等待传入数据
public static MediaCodec createDecoderByType(@NonNull String type)
throws IOException {
return new MediaCodec(type, true /* nameIsType */, false /* encoder */);
}
private MediaCodec(
@NonNull String name, boolean nameIsType, boolean encoder) {
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
mCallbackHandler = mEventHandler;
mOnFrameRenderedHandler = mEventHandler;
mBufferLock = new Object();
native_setup(name, nameIsType, encoder);
}
通过JNI调用到MediaCodec.cpp
static void android_media_MediaCodec_native_setup(
sp codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
}
JMediaCodec::JMediaCodec(
JNIEnv *env, jobject thiz,
const char *name, bool nameIsType, bool encoder)
: mClass(NULL),
mObject(NULL) {
...
if (nameIsType) {
mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
} else {
mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
}
CHECK((mCodec != NULL) != (mInitStatus != OK));
}
// frameworks\av\media\libstagefright\MediaCodec.cpp
sp MediaCodec::CreateByType(
const sp &looper, const AString &mime, bool encoder, status_t *err, pid_t pid,
uid_t uid) {
Vector matchingCodecs;
// 1.根据mime获取对应的codec
MediaCodecList::findMatchingCodecs(
mime.c_str(),
encoder,
0,
&matchingCodecs);
if (err != NULL) {
*err = NAME_NOT_FOUND;
}
//2.创建对应的MediaCodec并初始化
for (size_t i = 0; i < matchingCodecs.size(); ++i) {
sp codec = new MediaCodec(looper, pid, uid);
AString componentName = matchingCodecs[i];
status_t ret = codec->init(componentName);
if (err != NULL) {
*err = ret;
}
if (ret == OK) {
return codec;
}
ALOGD("Allocating component '%s' failed (%d), try next one.",
componentName.c_str(), ret);
}
return NULL;
}
先获取支持的编解码器列表,再匹配最佳的编解码器
//frameworks\av\media\libstagefright\MediaCodecList.cpp
void MediaCodecList::findMatchingCodecs(
const char *mime, bool encoder, uint32_t flags,
Vector *matches) {
matches->clear();
// 获取系统支持的编解码器列表
const sp list = getInstance();
if (list == nullptr) {
return;
}
//匹配最佳的编解码器
size_t index = 0;
for (;;) {
ssize_t matchIndex =
list->findCodecByType(mime, encoder, index);
if (matchIndex < 0) {
break;
}
index = matchIndex + 1;
const sp info = list->getCodecInfo(matchIndex);
CHECK(info != nullptr);
AString componentName = info->getCodecName();
if ((flags & kHardwareCodecsOnly) && isSoftwareCodec(componentName)) {
ALOGV("skipping SW codec '%s'", componentName.c_str());
} else {
matches->push(componentName);
ALOGV("matching '%s'", componentName.c_str());
}
}
if (flags & kPreferSoftwareCodecs ||
property_get_bool("debug.stagefright.swcodec", false)) {
matches->sort(compareSoftwareCodecsFirst);
}
}
先通过binder调到MediaPlayerService的getCodecList函数
//frameworks\av\media\libstagefright\MediaCodecList.cpp
sp MediaCodecList::getInstance() {
Mutex::Autolock _l(sRemoteInitMutex);
if (sRemoteList == nullptr) {
sp binder =
defaultServiceManager()->getService(String16("media.player"));
sp service =
interface_cast(binder);
if (service.get() != nullptr) {
// 获取服务端的MediaCodecList
sRemoteList = service->getCodecList();
if (sRemoteList != nullptr) {
sBinderDeathObserver = new BinderDeathObserver();
binder->linkToDeath(sBinderDeathObserver.get());
}
}
if (sRemoteList == nullptr) {
// if failed to get remote list, create local list
sRemoteList = getLocalInstance();
}
}
return sRemoteList;
}
可以看到又回到了MediaCodecList,没错就是media/stagefright下的MediaCodecList
说明MediaCodecList的创建是在mediaplayerservice进程
//frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp
sp MediaPlayerService::getCodecList() const {
return MediaCodecList::getLocalInstance();
}
GetBuilders()作为参数创建MediaCodecList单例并返回,关键在于GetBuilders()函数
//frameworks\av\media\libstagefright\MediaCodecList.cpp
sp MediaCodecList::getLocalInstance() {
Mutex::Autolock autoLock(sInitMutex);
if (sCodecList == nullptr) {
MediaCodecList *codecList = new MediaCodecList(GetBuilders());
if (codecList->initCheck() == OK) {
sCodecList = codecList;
if (isProfilingNeeded()) {
ALOGV("Codec profiling needed, will be run in separated thread.");
pthread_t profiler;
if (pthread_create(&profiler, nullptr, profilerThreadWrapper, nullptr) != 0) {
ALOGW("Failed to create thread for codec profiling.");
}
}
} else {
// failure to initialize may be temporary. retry on next call.
delete codecList;
}
}
return sCodecList;
}
GetBuilders
std::vector GetBuilders() {
std::vector builders;
// if plugin provides the input surface, we cannot use OMX video encoders.
// In this case, rely on plugin to provide list of OMX codecs that are usable.
sp surfaceTest =
StagefrightPluginLoader::GetCCodecInstance()->createInputSurface();
if (surfaceTest == nullptr) {
builders.push_back(&sOmxInfoBuilder);
}
builders.push_back(GetCodec2InfoBuilder());
return builders;
}
frameworks\av\media\libstagefright\MediaCodecList.cpp
MediaCodecList::MediaCodecList(std::vector builders) {
mGlobalSettings = new AMessage();
mCodecInfos.clear();
MediaCodecListWriter writer;
for (MediaCodecListBuilderBase *builder : builders) {
if (builder == nullptr) {
ALOGD("ignored a null builder");
continue;
}
// 进入build的buildMediaCodecList函数
mInitCheck = builder->buildMediaCodecList(&writer);
if (mInitCheck != OK) {
break;
}
}
writer.writeGlobalSettings(mGlobalSettings);
writer.writeCodecInfos(&mCodecInfos);
std::stable_sort(
mCodecInfos.begin(),
mCodecInfos.end(),
[](const sp &info1, const sp &info2) {
if (info2 == nullptr) {
return false;
} else if (info1 == nullptr) {
return true;
} else {
return info1->rank() < info2->rank();
}
});
}
通过OmxInfoBuilder创建MediaCodec列表(途径一)
1、通过HIDL调用到OmxStore.cpp, 通过OmxStore从xml解析支持的CodecList及Attributes
2、将支持的codec存储进swCodecName2Info, hwCodecName2Info
//frameworks\av\media\libstagefright\OmxInfoBuilder.cpp
status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
// Obtain IOmxStore
sp omxStore = IOmxStore::getService();
if (omxStore == nullptr) {
ALOGE("Cannot find an IOmxStore service.");
return NO_INIT;
}
// List service attributes (global settings)
Status status;
hidl_vec roles;
// 通过HIDL,获取inRoleList
auto transStatus = omxStore->listRoles(
[&roles] (
const hidl_vec& inRoleList) {
roles = inRoleList;
});
if (!transStatus.isOk()) {
ALOGE("Fail to obtain codec roles from IOmxStore.");
return NO_INIT;
}
hidl_vec serviceAttributes;
transStatus = omxStore->listServiceAttributes(
[&status, &serviceAttributes] (
Status inStatus,
const hidl_vec& inAttributes) {
status = inStatus;
serviceAttributes = inAttributes;
});
if (!transStatus.isOk()) {
ALOGE("Fail to obtain global settings from IOmxStore.");
return NO_INIT;
}
if (status != Status::OK) {
ALOGE("IOmxStore reports parsing error.");
return NO_INIT;
}
for (const auto& p : serviceAttributes) {
writer->addGlobalSetting(
p.key.c_str(), p.value.c_str());
}
// Convert roles to lists of codecs
// codec name -> index into swCodecs/hwCodecs
std::map>
swCodecName2Info, hwCodecName2Info;
char rank[PROPERTY_VALUE_MAX];
uint32_t defaultRank = 0x100;
if (property_get("debug.stagefright.omx_default_rank", rank, nullptr)) {
defaultRank = std::strtoul(rank, nullptr, 10);
}
//将支持的codec存储进swCodecName2Info, hwCodecName2Info
for (const IOmxStore::RoleInfo& role : roles) {
const hidl_string& typeName = role.type;
bool isEncoder = role.isEncoder;
bool preferPlatformNodes = role.preferPlatformNodes;
// If preferPlatformNodes is true, hardware nodes must be added after
// platform (software) nodes. hwCodecs is used to hold hardware nodes
// that need to be added after software nodes for the same role.
std::vector hwCodecs;
for (const IOmxStore::NodeInfo& node : role.nodes) {
const hidl_string& nodeName = node.name;
// OMX.google开头的都是软解码
bool isSoftware = hasPrefix(nodeName, "OMX.google");
MediaCodecInfoWriter* info;
if (isSoftware) {
auto c2i = swCodecName2Info.find(nodeName);
if (c2i == swCodecName2Info.end()) {
// Create a new MediaCodecInfo for a new node.
c2i = swCodecName2Info.insert(std::make_pair(
nodeName, writer->addMediaCodecInfo())).first;
info = c2i->second.get();
info->setName(nodeName.c_str());
info->setOwner(node.owner.c_str());
info->setEncoder(isEncoder);
info->setRank(defaultRank);
} else {
// The node has been seen before. Simply retrieve the
// existing MediaCodecInfoWriter.
info = c2i->second.get();
}
} else {
auto c2i = hwCodecName2Info.find(nodeName);
if (c2i == hwCodecName2Info.end()) {
// Create a new MediaCodecInfo for a new node.
if (!preferPlatformNodes) {
c2i = hwCodecName2Info.insert(std::make_pair(
nodeName, writer->addMediaCodecInfo())).first;
info = c2i->second.get();
info->setName(nodeName.c_str());
info->setOwner(node.owner.c_str());
info->setEncoder(isEncoder);
info->setRank(defaultRank);
} else {
// If preferPlatformNodes is true, this node must be
// added after all software nodes.
hwCodecs.push_back(&node);
continue;
}
} else {
// The node has been seen before. Simply retrieve the
// existing MediaCodecInfoWriter.
info = c2i->second.get();
}
}
std::unique_ptr caps =
info->addMime(typeName.c_str());
if (queryCapabilities(
node, typeName.c_str(), isEncoder, caps.get()) != OK) {
ALOGW("Fail to add mime %s to codec %s",
typeName.c_str(), nodeName.c_str());
info->removeMime(typeName.c_str());
}
}
。。。
}
return OK;
}
通过OmxStore.cpp解析xml中的编解码器及属性
OmxStore.cpp读取的配置文件有:
实际项目,在 /vendor/etc 中
//frameworks\av\media\libstagefright\xmlparser\include\media\stagefright\xmlparser\MediaCodecsXmlParser.h
static constexpr char const* defaultSearchDirs[] =
{"/odm/etc", "/vendor/etc", "/etc", nullptr};
static constexpr char const* defaultMainXmlName =
"media_codecs.xml";
static constexpr char const* defaultPerformanceXmlName =
"media_codecs_performance.xml";
static constexpr char const* defaultProfilingResultsXmlPath =
"/data/misc/media/media_codecs_profiling_results.xml";
获取对应解码器的查询能力,实际为创建对应得解码器
//frameworks\av\media\libstagefright\OmxInfoBuilder.cpp
status_t queryCapabilities(
const IOmxStore::NodeInfo& node, const char* mime, bool isEncoder,
MediaCodecInfo::CapabilitiesWriter* caps) {
sp codec = new ACodec();
status_t err = codec->queryCapabilities(
node.owner.c_str(), node.name.c_str(), mime, isEncoder, caps);
// ...
}
依靠binder机制调用OMX服务中的allocateNode()
//frameworks\av\media\libstagefright\ACodec.cpp
status_t ACodec::queryCapabilities(
const char* owner, const char* name, const char* mime, bool isEncoder,
MediaCodecInfo::CapabilitiesWriter* caps) {
const char *role = AVUtils::get()->getComponentRole(isEncoder, mime);
if (role == NULL) {
return BAD_VALUE;
}
OMXClient client;
// 获取名为“” Omx实现
status_t err = client.connect(owner);
if (err != OK) {
return err;
}
// 获取omx bp代理对象
sp omx = client.interface();
sp observer = new CodecObserver;
sp omxNode;
// hidl远程调用allocateNode
err = omx->allocateNode(name, observer, &omxNoe);
// ...
}
获取服务名为XXXX的OMX,并以LWOmx封装返回
frameworks\av\media\libstagefright\OMXClient.cpp
status_t OMXClient::connect(const char* name) {
using namespace ::android::hardware::media::omx::V1_0;
if (name == nullptr) {
name = "default";
}
sp tOmx = IOmx::getService(name);
if (tOmx.get() == nullptr) {
ALOGE("Cannot obtain IOmx service.");
return NO_INIT;
}
if (!tOmx->isRemote()) {
ALOGE("IOmx service running in passthrough mode.");
return NO_INIT;
}
mOMX = new utils::LWOmx(tOmx);
ALOGI("IOmx service obtained");
return OK;
}
LWOmx是代理,具体的实现在libstagefright_omx.so
//frameworks\av\media\libmedia\omx\1.0\WOmx.cpp
status_t LWOmx::allocateNode(
char const* name,
sp const& observer,
sp* omxNode) {
status_t fnStatus;
// allocateNode
status_t transStatus = toStatusT(mBase->allocateNode(
name, new TWOmxObserver(observer),
[&fnStatus, omxNode](Status status, sp const& node) {
fnStatus = toStatusT(status);
*omxNode = new LWOmxNode(node);
}));
return transStatus == NO_ERROR ? fnStatus : transStatus;
}
OMXNodeInstance对象持有一些关键信息,比如生成的节点id(mNodeID)、ACodec传递下来的observer、plugin里创建的解码组件handle和构造OMXNodeInstance时传入的omx对象等。还有关键的解码事件返回的kCallbacks。
//frameworks\av\media\libstagefright\omx\1.0\Omx.cpp
//libstagefright_omx.so
Return Omx::allocateNode(
const hidl_string& name,
const sp& observer,
allocateNode_cb _hidl_cb) {
using ::android::IOMXNode;
using ::android::IOMXObserver;
sp instance;
{
Mutex::Autolock autoLock(mLock);
if (mLiveNodes.size() == kMaxNodeInstances) {
_hidl_cb(toStatus(NO_MEMORY), nullptr);
return Void();
}
// 1. 实例化OMXNodeInstance对象,存放node id、解码组件handle、ACodec传递下来的observer等
instance = new OMXNodeInstance(
this, new LWOmxObserver(observer), name.c_str());
OMX_COMPONENTTYPE *handle;
// 2. master通知plugin创建对应的解码组件、并返回其操作句柄
OMX_ERRORTYPE err = mMaster->makeComponentInstance(
name.c_str(), &OMXNodeInstance::kCallbacks,
instance.get(), &handle);
if (err != OMX_ErrorNone) {
LOG(ERROR) << "Failed to allocate omx component "
"'" << name.c_str() << "' "
" err=" << asString(err) <<
"(0x" << std::hex << unsigned(err) << ")";
_hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);
return Void();
}
instance->setHandle(handle);
// Find quirks from mParser
const auto& codec = mParser.getCodecMap().find(name.c_str());
if (codec == mParser.getCodecMap().cend()) {
LOG(WARNING) << "Failed to obtain quirks for omx component "
"'" << name.c_str() << "' "
"from XML files";
} else {
uint32_t quirks = 0;
for (const auto& quirk : codec->second.quirkSet) {
if (quirk == "requires-allocate-on-input-ports") {
quirks |= OMXNodeInstance::
kRequiresAllocateBufferOnInputPorts;
}
if (quirk == "requires-allocate-on-output-ports") {
quirks |= OMXNodeInstance::
kRequiresAllocateBufferOnOutputPorts;
}
}
instance->setQuirks(quirks);
}
mLiveNodes.add(observer.get(), instance);
mNode2Observer.add(instance.get(), observer.get());
}
observer->linkToDeath(this, 0);
_hidl_cb(toStatus(OK), new TWOmxNode(instance));
return Void();
}
// frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp
// static
OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
&OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
};
OMXMaster是解码库加载的核心
先找到指定的plugin(解码器组件,有厂商定制的及AOSP的)、再通知plugin去创建对应的解码组件。
frameworks\av\media\libstagefright\omx\OMXMaster.cpp
OMX_ERRORTYPE OMXMaster::makeComponentInstance(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component) {
ALOGI("makeComponentInstance(%s) in %s process", name, mProcessName);
Mutex::Autolock autoLock(mLock);
*component = NULL;
// 找到对应的Plugin
ssize_t index = mPluginByComponentName.indexOfKey(String8(name));
if (index < 0) {
return OMX_ErrorInvalidComponentName;
}
OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);
// 创建对应的解码组件
OMX_ERRORTYPE err =
plugin->makeComponentInstance(name, callbacks, appData, component);
if (err != OMX_ErrorNone) {
return err;
}
mPluginByInstance.add(*component, plugin);
return err;
}
这些解码器是在哪加载的呢,回到OMXMaster构造函数
加载软硬编解码管理器中的所有解码器,并存在mPluginByComponentName。
1.加载厂商编解码管理器,libstagefrighthw.so
2.加载软编解码管理器,SoftOMXPlugin
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, "", sizeof(mProcessName));
} else {
ssize_t len = read(fd, mProcessName, sizeof(mProcessName));
if (len < 2) {
ALOGW("couldn't determine process name");
strlcpy(mProcessName, "", sizeof(mProcessName));
} else {
// the name is newline terminated, so erase the newline
mProcessName[len - 1] = 0;
}
close(fd);
}
//加载厂商解码器SO
addVendorPlugin();
//加载软解码器SO
addPlugin(new SoftOMXPlugin);
}
void OMXMaster::addVendorPlugin() {
addPlugin("libstagefrighthw.so");
}
如果是软件编解码器,调用SoftOMXPlugin的makeComponentInstance
如果是硬件就调用QComOMXPlugin的makeComponentInstance
Component可以理解为一个解码器实例。
1.根据mime name匹配kComponents数据,如: { "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" },
2. 拿到的mLibNameSuffix值为aacdec,最后拼接的libName是libstagefright_soft_aacdec.so
3. 从system/lib目录下加载libstagefright_soft_aacdec.so库
4. 调用其对应的createSoftOMXComponent函数创建SoftOMXComponent
// frameworks\av\media\libstagefright\omx\SoftOMXComponent.cpp
OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component) {
ALOGV("makeComponentInstance '%s'", name);
for (size_t i = 0; i < kNumComponents; ++i) {
// 1.根据name匹配kComponents数据,
// 如: { "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" },
if (strcmp(name, kComponents[i].mName)) {
continue;
}
// 2. 拿到的mLibNameSuffix值为aacdec,最后拼接的libName是libstagefright_soft_aacdec.so
AString libName = "libstagefright_soft_";
libName.append(kComponents[i].mLibNameSuffix);
libName.append(".so");
// RTLD_NODELETE means we keep the shared library around forever.
// this eliminates thrashing during sequences like loading soundpools.
// It also leaves the rest of the logic around the dlopen()/dlclose()
// calls in this file unchanged.
//
// Implications of the change:
// -- the codec process (where this happens) will have a slightly larger
// long-term memory footprint as it accumulates the loaded shared libraries.
// This is expected to be a small amount of memory.
// -- plugin codecs can no longer (and never should have) depend on a
// free reset of any static data as the library would have crossed
// a dlclose/dlopen cycle.
//
// 3. 从system/lib目录下加载libstagefright_soft_aacdec.so库
void *libHandle = dlopen(libName.c_str(), RTLD_NOW|RTLD_NODELETE);
if (libHandle == NULL) {
ALOGE("unable to dlopen %s: %s", libName.c_str(), dlerror());
return OMX_ErrorComponentNotFound;
}
typedef SoftOMXComponent *(*CreateSoftOMXComponentFunc)(
const char *, const OMX_CALLBACKTYPE *,
OMX_PTR, OMX_COMPONENTTYPE **);
CreateSoftOMXComponentFunc createSoftOMXComponent =
(CreateSoftOMXComponentFunc)dlsym(
libHandle,
"_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPE"
"PvPP17OMX_COMPONENTTYPE");
if (createSoftOMXComponent == NULL) {
dlclose(libHandle);
libHandle = NULL;
return OMX_ErrorComponentNotFound;
}
// 4. 创建对应的SoftOMXComponent
sp codec =
(*createSoftOMXComponent)(name, callbacks, appData, component);
if (codec == NULL) {
dlclose(libHandle);
libHandle = NULL;
return OMX_ErrorInsufficientResources;
}
OMX_ERRORTYPE err = codec->initCheck();
if (err != OMX_ErrorNone) {
dlclose(libHandle);
libHandle = NULL;
return err;
}
codec->incStrong(this);
codec->setLibHandle(libHandle);
return OMX_ErrorNone;
}
return OMX_ErrorInvalidComponentName;
}
SoftOmxPlugin是google提供的原生的一套编解码器插件
即通常说的软解硬解中的软解。它支持市面上常用的音视频格式,软解码支持的格式:
// frameworks\av\media\libstagefright\omx\SoftOMXPlugin.cpp
static const struct {
const char *mName;
const char *mLibNameSuffix;
const char *mRole;
} kComponents[] = {
// two choices for aac decoding.
// configurable in media/libstagefright/data/media_codecs_google_audio.xml
// default implementation
{ "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" },
// alternate implementation
{ "OMX.google.xaac.decoder", "xaacdec", "audio_decoder.aac" },
{ "OMX.google.aac.encoder", "aacenc", "audio_encoder.aac" },
{ "OMX.google.amrnb.decoder", "amrdec", "audio_decoder.amrnb" },
{ "OMX.google.amrnb.encoder", "amrnbenc", "audio_encoder.amrnb" },
{ "OMX.google.amrwb.decoder", "amrdec", "audio_decoder.amrwb" },
{ "OMX.google.amrwb.encoder", "amrwbenc", "audio_encoder.amrwb" },
{ "OMX.google.h264.decoder", "avcdec", "video_decoder.avc" },
{ "OMX.google.h264.encoder", "avcenc", "video_encoder.avc" },
{ "OMX.google.hevc.decoder", "hevcdec", "video_decoder.hevc" },
{ "OMX.google.g711.alaw.decoder", "g711dec", "audio_decoder.g711alaw" },
{ "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" },
{ "OMX.google.mpeg2.decoder", "mpeg2dec", "video_decoder.mpeg2" },
{ "OMX.google.h263.decoder", "mpeg4dec", "video_decoder.h263" },
{ "OMX.google.h263.encoder", "mpeg4enc", "video_encoder.h263" },
{ "OMX.google.mpeg4.decoder", "mpeg4dec", "video_decoder.mpeg4" },
{ "OMX.google.mpeg4.encoder", "mpeg4enc", "video_encoder.mpeg4" },
{ "OMX.google.mp3.decoder", "mp3dec", "audio_decoder.mp3" },
{ "OMX.google.vorbis.decoder", "vorbisdec", "audio_decoder.vorbis" },
{ "OMX.google.opus.decoder", "opusdec", "audio_decoder.opus" },
{ "OMX.google.vp8.decoder", "vpxdec", "video_decoder.vp8" },
{ "OMX.google.vp9.decoder", "vpxdec", "video_decoder.vp9" },
{ "OMX.google.vp8.encoder", "vpxenc", "video_encoder.vp8" },
{ "OMX.google.vp9.encoder", "vpxenc", "video_encoder.vp9" },
{ "OMX.google.raw.decoder", "rawdec", "audio_decoder.raw" },
{ "OMX.google.flac.decoder", "flacdec", "audio_decoder.flac" },
{ "OMX.google.flac.encoder", "flacenc", "audio_encoder.flac" },
{ "OMX.google.gsm.decoder", "gsmdec", "audio_decoder.gsm" },
#ifdef QTI_FLAC_DECODER
{ "OMX.qti.audio.decoder.flac", "qtiflacdec", "audio_decoder.flac" },
#endif
};
软解码器代码目录
frameworks\av\media\libstagefright\codecs,编译会生成对应的so库
车机内软解码so所在的目录
软解码器的实现
是基于“OpenMax IL的标准接口”进行,实际硬解码器也是如此。
以libstagefright_soft_aacdec为例子
libstagefright_soft_aacdec.so主体是SoftAAC2.cpp和SoftAAC2.h,所以dlsym返回的createSoftOMXComponent值如下:
//frameworks\av\media\libstagefright\codecs\aacdec\SoftAAC2.cpp
android::SoftOMXComponent *createSoftOMXComponent(
const char *name, const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData, OMX_COMPONENTTYPE **component) {
return new android::SoftAAC2(name, callbacks, appData, component);
}
SoftAAC2继承自SimpleSoftOMXComponent
//frameworks\av\media\libstagefright\codecs\aacdec\SoftAAC2.cpp
SoftAAC2::SoftAAC2(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component)
: SimpleSoftOMXComponent(name, callbacks, appData, component),
mAACDecoder(NULL),
mStreamInfo(NULL),
mIsADTS(false),
mInputBufferCount(0),
mOutputBufferCount(0),
mSignalledError(false),
mLastInHeader(NULL),
mLastHeaderTimeUs(-1),
mNextOutBufferTimeUs(0),
mOutputPortSettingsChange(NONE) {
initPorts();
CHECK_EQ(initDecoder(), (status_t)OK);
}
SimpleSoftOMXComponent实现OpenMax IL的标准接口,例如sendCommand、setParameter
//frameworks\av\media\stagefright\omx\SimpleSoftOMXComponent.cpp
SimpleSoftOMXComponent::SimpleSoftOMXComponent(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component)
: SoftOMXComponent(name, callbacks, appData, component),
mLooper(new ALooper),
mHandler(new AHandlerReflector(this)),
mState(OMX_StateLoaded),
mTargetState(OMX_StateLoaded) {
mLooper->setName(name);
mLooper->registerHandler(mHandler);
mLooper->start(
false, // runOnCallingThread
false, // canCallJava
ANDROID_PRIORITY_VIDEO);
}
SoftOMXComponent里有对OpenMax接口的
// frameworks\av\media\stagefright\omx\SoftOMXComponent.cpp
// OMX_Component.h为 OpenMax IL version 1.1.2的接口头文件
#include
SoftOMXComponent::SoftOMXComponent(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component)
: mName(name),
mCallbacks(callbacks),
mComponent(new OMX_COMPONENTTYPE),
mLibHandle(NULL) {
mComponent->nSize = sizeof(*mComponent);
mComponent->nVersion.s.nVersionMajor = 1;
mComponent->nVersion.s.nVersionMinor = 0;
mComponent->nVersion.s.nRevision = 0;
mComponent->nVersion.s.nStep = 0;
mComponent->pComponentPrivate = this;
mComponent->pApplicationPrivate = appData; 。。。
*component = mComponent;
}
调用mGetHandle函数指针,而该函数指针是在该类构造时初始化。
//hardware\qcom\media\libstagefrighthw\QComOMXPlugin.cpp
OMX_ERRORTYPE QComOMXPlugin::makeComponentInstance(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component) {
if (mLibHandle == NULL) {
return OMX_ErrorUndefined;
}
return (*mGetHandle)(
reinterpret_cast(component),
const_cast(name),
appData, const_cast(callbacks));
}
可以看到原来mGetHandle就是libOmxCore.so库中的OMX_GetHandle函数
//hardware\qcom\media\libstagefrighthw\QComOMXPlugin.cpp
QComOMXPlugin::QComOMXPlugin()
: mLibHandle(dlopen("libOmxCore.so", RTLD_NOW)),
mInit(NULL),
mDeinit(NULL),
mComponentNameEnum(NULL),
mGetHandle(NULL),
mFreeHandle(NULL),
mGetRolesOfComponentHandle(NULL) {
if (mLibHandle != NULL) {
mInit = (InitFunc)dlsym(mLibHandle, "OMX_Init");
mDeinit = (DeinitFunc)dlsym(mLibHandle, "OMX_Deinit");
mComponentNameEnum =
(ComponentNameEnumFunc)dlsym(mLibHandle, "OMX_ComponentNameEnum");
mGetHandle = (GetHandleFunc)dlsym(mLibHandle, "OMX_GetHandle");
mFreeHandle = (FreeHandleFunc)dlsym(mLibHandle, "OMX_FreeHandle");
mGetRolesOfComponentHandle =
(GetRolesOfComponentFunc)dlsym(
mLibHandle, "OMX_GetRolesOfComponent");
if (!mInit || !mDeinit || !mComponentNameEnum || !mGetHandle ||
!mFreeHandle || !mGetRolesOfComponentHandle) {
dlclose(mLibHandle);
mLibHandle = NULL;
} else
(*mInit)();
}
}
OMX_GetHandle函数
1、如果是avc解码器,加载libOmxVideoDSMode.so库,判断是否有dsmode
2、视频预处理开启情况需要加载vpp库
3、动态加载对应的编解码so
//hardware\qcom\media\mm-core\src\common\qc_omx_core.c
// libOmxCore.so
OMX_API OMX_ERRORTYPE OMX_APIENTRY
OMX_GetHandle(OMX_OUT OMX_HANDLETYPE* handle,
OMX_IN OMX_STRING componentName,
OMX_IN OMX_PTR appData,
OMX_IN OMX_CALLBACKTYPE* callBacks)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
int cmp_index = -1;
int hnd_index = -1;
int vpp_cmp_index = -1;
DEBUG_PRINT("OMXCORE API : GetHandle %p %s %p\n", handle,
componentName,
appData);
pthread_mutex_lock(&lock_core);
if(handle)
{
*handle = NULL;
char optComponentName[OMX_MAX_STRINGNAME_SIZE];
strlcpy(optComponentName, componentName, OMX_MAX_STRINGNAME_SIZE);
// 如果是avc解码器,加载libOmxVideoDSMode.so库,判断是否有dsmode
if(strstr(componentName, "avc") && strstr(componentName, "decoder"))
{
void *libhandle = dlopen("libOmxVideoDSMode.so", RTLD_NOW);
if(libhandle)
{
int (*fn_ptr)() = dlsym(libhandle, "isDSModeActive");
dlclose(libhandle);
}
else
{
DEBUG_PRINT_ERROR("Failed to load dsmode library");
}
}
if(cmp_index < 0)
{
cmp_index = get_cmp_index(componentName);
strlcpy(optComponentName, componentName, OMX_MAX_STRINGNAME_SIZE);
}
if(cmp_index >= 0)
{
char value[PROPERTY_VALUE_MAX];
DEBUG_PRINT("getting fn pointer\n");
// Load VPP omx component for decoder if vpp
// property is enabled
// 视频预处理开启情况需要加载vpp
if ((property_get("vendor.media.vpp.enable", value, NULL))
&& (!strcmp("1", value) || !strcmp("true", value))) {
DEBUG_PRINT("VPP property is enabled");
if (!strcmp(core[cmp_index].so_lib_name, "libOmxVdec.so")
|| !strcmp(core[cmp_index].so_lib_name, "libOmxSwVdec.so")) {
vpp_cmp_index = get_cmp_index("OMX.qti.vdec.vpp");
if (vpp_cmp_index < 0) {
DEBUG_PRINT_ERROR("Unable to find VPP OMX lib in registry ");
} else {
DEBUG_PRINT("Loading vpp for vdec");
cmp_index = vpp_cmp_index;
}
}
}
// dynamically load the so
core[cmp_index].fn_ptr =
omx_core_load_cmp_library(core[cmp_index].so_lib_name,
&core[cmp_index].so_lib_handle);
。。。。
}
加载对应的SO库
// /hardware\qcom\media\mm-core\src\common\qc_omx_core.c
static create_qc_omx_component
omx_core_load_cmp_library(char *libname, void **handle_ptr)
{
create_qc_omx_component fn_ptr = NULL;
if(handle_ptr)
{
DEBUG_PRINT("Dynamically Loading the library : %s\n",libname);
if (!strcmp(libname, "libOmxVpp.so"))
*handle_ptr = dlopen(libname, RTLD_NOW|RTLD_GLOBAL);
else
*handle_ptr = dlopen(libname, RTLD_NOW);
if(*handle_ptr)
{
fn_ptr = dlsym(*handle_ptr, "get_omx_component_factory_fn");
if(fn_ptr == NULL)
{
DEBUG_PRINT("Error: Library %s incompatible as QCOM OMX component loader - %s\n",
libname, dlerror());
*handle_ptr = NULL;
}
}
else
{
DEBUG_PRINT("Error: Couldn't load %s: %s\n",libname,dlerror());
}
}
return fn_ptr;
}
高通平台支持的硬解码器
注意里边有一些是软解码(包含Sw字符的)
omx_core_cb_type core[] =
{
//Common entries
OMX_REGISTRY_ENTRY("OMX.qcom.video.decoder.avc", "libOmxVdec.so", "video_decoder.avc"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.decoder.avc.secure", "libOmxVdec.so", "video_decoder.avc"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.decoder.mpeg2", "libOmxVdec.so", "video_decoder.mpeg2"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.decoder.mpeg2.secure", "libOmxVdec.so", "video_decoder.mpeg2"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.decoder.hevc", "libOmxVdec.so", "video_decoder.hevc"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.decoder.hevc.secure", "libOmxVdec.so", "video_decoder.hevc"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.decoder.vp8", "libOmxVdec.so", "video_decoder.vp8"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.decoder.vp9", "libOmxVdec.so", "video_decoder.vp9"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.decoder.vp9.secure", "libOmxVdec.so", "video_decoder.vp9"),
OMX_REGISTRY_ENTRY("OMX.qti.video.decoder.mpeg4sw", "libOmxSwVdec.so", "video_decoder.mpeg4"),
OMX_REGISTRY_ENTRY("OMX.qti.video.decoder.divxsw", "libOmxSwVdec.so", "video_decoder.divx"),
OMX_REGISTRY_ENTRY("OMX.qti.video.decoder.divx4sw", "libOmxSwVdec.so", DIVX4_MIME),
OMX_REGISTRY_ENTRY("OMX.qti.video.decoder.h263sw", "libOmxSwVdec.so", "video_decoder.h263"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.encoder.mpeg4sw", "libOmxSwVencMpeg4.so", "video_encoder.mpeg4"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.encoder.h263sw", "libOmxSwVencMpeg4.so", "video_encoder.h263"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.encoder.avc", "libOmxVenc.so", "video_encoder.avc"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.encoder.avc.secure", "libOmxVenc.so", "video_encoder.avc"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.encoder.vp8", "libOmxVenc.so", "video_encoder.vp8"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.encoder.hevc", "libOmxVenc.so", "video_encoder.hevc"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.encoder.hevc.secure", "libOmxVenc.so", "video_encoder.hevc"),
OMX_REGISTRY_ENTRY("OMX.qcom.video.encoder.heic", "libOmxVenc.so", "image_encoder.heic"),
OMX_REGISTRY_ENTRY("OMX.qcom.audio.decoder.Qcelp13", "libOmxQcelp13Dec.so", "audio_decoder.Qcelp13"),
OMX_REGISTRY_ENTRY("OMX.qcom.audio.decoder.evrc", "libOmxEvrcDec.so", "audio_decoder.evrc"),
OMX_REGISTRY_ENTRY("OMX.qcom.audio.decoder.wma", "libOmxWmaDec.so", "audio_decoder.wma"),
OMX_REGISTRY_ENTRY("OMX.qcom.audio.decoder.wma10Pro", "libOmxWmaDec.so", "audio_decoder.wma"),
OMX_REGISTRY_ENTRY("OMX.qcom.audio.decoder.wmaLossLess", "libOmxWmaDec.so", "audio_decoder.wma"),
OMX_REGISTRY_ENTRY("OMX.qcom.audio.decoder.amrwbplus", "libOmxAmrwbplusDec.so", "audio_decoder.awbplus"),
OMX_REGISTRY_ENTRY("OMX.qcom.audio.decoder.alac", "libOmxAlacDec.so", "audio_decoder.alac"),
OMX_REGISTRY_ENTRY("OMX.qti.audio.decoder.alac.sw", "libOmxAlacDecSw.so", "audio_decoder.alac"),
。。。。。
};
硬解码器的实现位置
Audio encode:hardware\qcom\audio\mm-audio
Audio decode:\vendor\qcom\proprietary\mm-audio\omx
Video encode/decode: hardware\qcom\media\mm-video-v4l2
对比Audio每个解码器均有一个so,Video采用v4l2框架实现,只有libOmxVenc.so,libOmxSwVencMpeg4
libOmxSwVdec,libOmxVdec.so 这4个库。
1.VPP 视频预处理
2.avc 就是H264
3.v4l2 是:video for linux version2,是Linux内核中关于视频设备的内核驱动框架,为上层的访问底层的视频设备提供了统一的接口.凡是内核中的子系统都有抽象底层硬件的差异,为上层提供统一的接口和提取出公共代码避免代码冗余等好处.