-
解析系统中所有支持的编码和解码器信息
/frameworks/av/media/libstagefright/MediaCodecList.cpp
MediaCodecList::MediaCodecList(std::vector<MediaCodecListBuilderBase*> builders) {
..........................................................
for (MediaCodecListBuilderBase *builder : builders) {
if (builder == nullptr) {
ALOGD("ignored a null builder");
continue;
}
mInitCheck = builder->buildMediaCodecList(&writer);
if (mInitCheck != OK) {
break;
}
}
..........................................................
}
此函数加载相关的 xml 文件,并解析其内容,先来看看 builder 都有那些
/frameworks/av/media/libstagefright/MediaCodecList.cpp
OmxInfoBuilder sOmxInfoBuilder{true /* allowSurfaceEncoders */};
OmxInfoBuilder sOmxNoSurfaceEncoderInfoBuilder{false /* allowSurfaceEncoders */};
MediaCodecListBuilderBase *GetCodec2InfoBuilder() {
Mutex::Autolock _l(sCodec2InfoBuilderMutex);
if (!sCodec2InfoBuilder) {
sCodec2InfoBuilder.reset(
StagefrightPluginLoader::GetCCodecInstance()->createBuilder());
}
return sCodec2InfoBuilder.get();
}
std::vector<MediaCodecListBuilderBase *> GetBuilders() {
std::vector<MediaCodecListBuilderBase *> 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<PersistentSurface> surfaceTest =
StagefrightPluginLoader::GetCCodecInstance()->createInputSurface();
if (surfaceTest == nullptr) {
ALOGD("Allowing all OMX codecs");
builders.push_back(&sOmxInfoBuilder);
} else {
ALOGD("Allowing only non-surface-encoder OMX codecs");
builders.push_back(&sOmxNoSurfaceEncoderInfoBuilder);
}
builders.push_back(GetCodec2InfoBuilder());
return builders;
}
/frameworks/av/media/libstagefright/StagefrightPluginLoader.cpp
StagefrightPluginLoader::StagefrightPluginLoader(const char *libPath) {
.......................................................
mLibHandle = dlopen(libPath, RTLD_NOW | RTLD_NODELETE);
if (mLibHandle == nullptr) {
ALOGD("Failed to load library: %s (%s)", libPath, dlerror());
return;
}
.......................................................
mCreateBuilder = (MediaCodecListBuilderBase::CreateBuilderFunc)dlsym(
mLibHandle, "CreateBuilder");
if (mCreateBuilder == nullptr) {
ALOGD("Failed to find symbol: CreateBuilder (%s)", dlerror());
}
.......................................................
}
MediaCodecListBuilderBase *StagefrightPluginLoader::createBuilder() {
if (mLibHandle == nullptr || mCreateBuilder == nullptr) {
ALOGD("Handle or CreateBuilder symbol is null");
return nullptr;
}
return mCreateBuilder();
}
可以看到 Codec2InfoBuilder 是从动态库中获取的
/frameworks/av/media/codec2/sfplugin/Codec2InfoBuilder.cpp
extern "C" android::MediaCodecListBuilderBase *CreateBuilder() {
return new android::Codec2InfoBuilder;
}
可以发现其中一个 builder 是 Codec2InfoBuilder,还有一个为 OmxInfoBuilder
-
先来看一下 OmxInfoBuilder
/frameworks/av/media/libstagefright/OmxInfoBuilder.cpp
status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
// Obtain IOmxStore
sp<IOmxStore> omxStore = IOmxStore::getService();
if (omxStore == nullptr) {
ALOGE("Cannot find an IOmxStore service.");
return NO_INIT;
}
// List service attributes (global settings)
Status status;
hidl_vec<IOmxStore::RoleInfo> roles;
auto transStatus = omxStore->listRoles(
[&roles] (
const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
roles = inRoleList;
});
if (!transStatus.isOk()) {
ALOGE("Fail to obtain codec roles from IOmxStore.");
return NO_INIT;
}
hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
transStatus = omxStore->listServiceAttributes(
[&status, &serviceAttributes] (
Status inStatus,
const hidl_vec<IOmxStore::ServiceAttribute>& 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<hidl_string, std::unique_ptr<MediaCodecInfoWriter>> codecName2Info;
uint32_t defaultRank =
::android::base::GetUintProperty("debug.stagefright.omx_default_rank", 0x100u);
uint32_t defaultSwAudioRank =
::android::base::GetUintProperty("debug.stagefright.omx_default_rank.sw-audio", 0x10u);
uint32_t defaultSwOtherRank =
::android::base::GetUintProperty("debug.stagefright.omx_default_rank.sw-other", 0x210u);
for (const IOmxStore::RoleInfo& role : roles) {
const hidl_string& typeName = role.type;
bool isEncoder = role.isEncoder;
bool isAudio = hasPrefix(role.type, "audio/");
bool isVideoOrImage = hasPrefix(role.type, "video/") || hasPrefix(role.type, "image/");
for (const IOmxStore::NodeInfo &node : role.nodes) {
const hidl_string& nodeName = node.name;
// currently image and video encoders use surface input
if (!mAllowSurfaceEncoders && isVideoOrImage && isEncoder) {
ALOGD("disabling %s for media type %s because we are not using OMX input surface",
nodeName.c_str(), role.type.c_str());
continue;
}
bool isSoftware = hasPrefix(nodeName, "OMX.google");
uint32_t rank = isSoftware
? (isAudio ? defaultSwAudioRank : defaultSwOtherRank)
: defaultRank;
// get rank from IOmxStore via attribute
for (const IOmxStore::Attribute& attribute : node.attributes) {
if (attribute.key == "rank") {
uint32_t oldRank = rank;
char dummy;
if (sscanf(attribute.value.c_str(), "%u%c", &rank, &dummy) != 1) {
rank = oldRank;
}
break;
}
}
MediaCodecInfoWriter* info;
auto c2i = codecName2Info.find(nodeName);
if (c2i == codecName2Info.end()) {
// Create a new MediaCodecInfo for a new node.
c2i = codecName2Info.insert(std::make_pair(
nodeName, writer->addMediaCodecInfo())).first;
info = c2i->second.get();
info->setName(nodeName.c_str());
info->setOwner(node.owner.c_str());
info->setRank(rank);
typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
// all OMX codecs are vendor codecs (in the vendor partition), but
// treat OMX.google codecs as non-hardware-accelerated and non-vendor
if (!isSoftware) {
attrs |= MediaCodecInfo::kFlagIsVendor;
if (!std::count_if(
node.attributes.begin(), node.attributes.end(),
[](const IOmxStore::Attribute &i) -> bool {
return i.key == "attribute::software-codec";
})) {
attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
}
}
if (isEncoder) {
attrs |= MediaCodecInfo::kFlagIsEncoder;
}
info->setAttributes(attrs);
} else {
// The node has been seen before. Simply retrieve the
// existing MediaCodecInfoWriter.
info = c2i->second.get();
}
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
info->addMediaType(typeName.c_str());
if (queryCapabilities(
node, typeName.c_str(), isEncoder, caps.get()) != OK) {
ALOGW("Fail to add media type %s to codec %s",
typeName.c_str(), nodeName.c_str());
info->removeMediaType(typeName.c_str());
}
}
}
return OK;
}
1. 从 OMX Service 中获取编解码信息,查找目录为 "/odm/etc", "/vendor/etc", "/etc"
2. 遍历所有的编解码,按照相关属性配置编解码信息
3. 调用 queryCapabilities() 函数,此处会调用到对应 plugin 的 makeComponentInstance 函数来创建解码器
-
再来看一下 Codec2InfoBuilder
status_t Codec2InfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
// TODO: Remove run-time configurations once all codecs are working
// properly. (Assume "full" behavior eventually.)
//
// debug.stagefright.ccodec supports 5 values.
// 0 - No Codec 2.0 components are available.
// 1 - Audio decoders and encoders with prefix "c2.android." are available
// and ranked first.
// All other components with prefix "c2.android." are available with
// their normal ranks.
// Components with prefix "c2.vda." are available with their normal
// ranks.
// All other components with suffix ".avc.decoder" or ".avc.encoder"
// are available but ranked last.
// 2 - Components with prefix "c2.android." are available and ranked
// first.
// Components with prefix "c2.vda." are available with their normal
// ranks.
// All other components with suffix ".avc.decoder" or ".avc.encoder"
// are available but ranked last.
// 3 - Components with prefix "c2.android." are available and ranked
// first.
// All other components are available with their normal ranks.
// 4 - All components are available with their normal ranks.
//
// The default value (boot time) is 1.
//
// Note: Currently, OMX components have default rank 0x100, while all
// Codec2.0 software components have default rank 0x200.
int option = ::android::base::GetIntProperty("debug.stagefright.ccodec", 4);
// Obtain Codec2Client
std::vector<Traits> traits = Codec2Client::ListComponents();
// parse APEX XML first, followed by vendor XML
MediaCodecsXmlParser parser;
parser.parseXmlFilesInSearchDirs(
parser.getDefaultXmlNames(),
{ "/apex/com.android.media.swcodec/etc" });
// TODO: remove these c2-specific files once product moved to default file names
parser.parseXmlFilesInSearchDirs(
{ "media_codecs_c2.xml", "media_codecs_performance_c2.xml" });
// parse default XML files
parser.parseXmlFilesInSearchDirs();
if (parser.getParsingStatus() != OK) {
ALOGD("XML parser no good");
return OK;
}
MediaCodecsXmlParser::AttributeMap settings = parser.getServiceAttributeMap();
for (const auto &v : settings) {
if (!hasPrefix(v.first, "media-type-")
&& !hasPrefix(v.first, "domain-")
&& !hasPrefix(v.first, "variant-")) {
writer->addGlobalSetting(v.first.c_str(), v.second.c_str());
}
}
for (const Traits& trait : traits) {
C2Component::rank_t rank = trait.rank;
// Interface must be accessible for us to list the component, and there also
// must be an XML entry for the codec. Codec aliases listed in the traits
// allow additional XML entries to be specified for each alias. These will
// be listed as separate codecs. If no XML entry is specified for an alias,
// those will be treated as an additional alias specified in the XML entry
// for the interface name.
std::vector<std::string> nameAndAliases = trait.aliases;
nameAndAliases.insert(nameAndAliases.begin(), trait.name);
for (const std::string &nameOrAlias : nameAndAliases) {
bool isAlias = trait.name != nameOrAlias;
std::shared_ptr<Codec2Client::Interface> intf =
Codec2Client::CreateInterfaceByName(nameOrAlias.c_str());
if (!intf) {
ALOGD("could not create interface for %s'%s'",
isAlias ? "alias " : "",
nameOrAlias.c_str());
continue;
}
if (parser.getCodecMap().count(nameOrAlias) == 0) {
if (isAlias) {
std::unique_ptr<MediaCodecInfoWriter> baseCodecInfo =
writer->findMediaCodecInfo(trait.name.c_str());
if (!baseCodecInfo) {
ALOGD("alias '%s' not found in xml but canonical codec info '%s' missing",
nameOrAlias.c_str(),
trait.name.c_str());
} else {
ALOGD("alias '%s' not found in xml; use an XML <Alias> tag for this",
nameOrAlias.c_str());
// merge alias into existing codec
baseCodecInfo->addAlias(nameOrAlias.c_str());
}
} else {
ALOGD("component '%s' not found in xml", trait.name.c_str());
}
continue;
}
std::string canonName = trait.name;
// TODO: Remove this block once all codecs are enabled by default.
switch (option) {
case 0:
continue;
case 1:
if (hasPrefix(canonName, "c2.vda.")) {
break;
}
if (hasPrefix(canonName, "c2.android.")) {
if (trait.domain == C2Component::DOMAIN_AUDIO) {
rank = 1;
break;
}
break;
}
if (hasSuffix(canonName, ".avc.decoder") ||
hasSuffix(canonName, ".avc.encoder")) {
rank = std::numeric_limits<decltype(rank)>::max();
break;
}
continue;
case 2:
if (hasPrefix(canonName, "c2.vda.")) {
break;
}
if (hasPrefix(canonName, "c2.android.")) {
rank = 1;
break;
}
if (hasSuffix(canonName, ".avc.decoder") ||
hasSuffix(canonName, ".avc.encoder")) {
rank = std::numeric_limits<decltype(rank)>::max();
break;
}
continue;
case 3:
if (hasPrefix(canonName, "c2.android.")) {
rank = 1;
}
break;
}
const MediaCodecsXmlParser::CodecProperties &codec =
parser.getCodecMap().at(nameOrAlias);
// verify that either the codec is explicitly enabled, or one of its domains is
bool codecEnabled = codec.quirkSet.find("attribute::disabled") == codec.quirkSet.end();
if (!codecEnabled) {
for (const std::string &domain : codec.domainSet) {
const Switch enabled = isDomainEnabled(domain, settings);
ALOGV("codec entry '%s' is in domain '%s' that is '%s'",
nameOrAlias.c_str(), domain.c_str(), asString(enabled));
if (enabled) {
codecEnabled = true;
break;
}
}
}
// if codec has variants, also check that at least one of them is enabled
bool variantEnabled = codec.variantSet.empty();
for (const std::string &variant : codec.variantSet) {
const Switch enabled = isVariantExpressionEnabled(variant, settings);
ALOGV("codec entry '%s' has a variant '%s' that is '%s'",
nameOrAlias.c_str(), variant.c_str(), asString(enabled));
if (enabled) {
variantEnabled = true;
break;
}
}
if (!codecEnabled || !variantEnabled) {
ALOGD("codec entry for '%s' is disabled", nameOrAlias.c_str());
continue;
}
ALOGV("adding codec entry for '%s'", nameOrAlias.c_str());
std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
codecInfo->setName(nameOrAlias.c_str());
codecInfo->setOwner(("codec2::" + trait.owner).c_str());
bool encoder = trait.kind == C2Component::KIND_ENCODER;
typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
if (encoder) {
attrs |= MediaCodecInfo::kFlagIsEncoder;
}
if (trait.owner == "software") {
attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
} else {
attrs |= MediaCodecInfo::kFlagIsVendor;
if (trait.owner == "vendor-software") {
attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
} else if (codec.quirkSet.find("attribute::software-codec")
== codec.quirkSet.end()) {
attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
}
}
codecInfo->setAttributes(attrs);
if (!codec.rank.empty()) {
uint32_t xmlRank;
char dummy;
if (sscanf(codec.rank.c_str(), "%u%c", &xmlRank, &dummy) == 1) {
rank = xmlRank;
}
}
ALOGV("rank: %u", (unsigned)rank);
codecInfo->setRank(rank);
for (const std::string &alias : codec.aliases) {
ALOGV("adding alias '%s'", alias.c_str());
codecInfo->addAlias(alias.c_str());
}
for (auto typeIt = codec.typeMap.begin(); typeIt != codec.typeMap.end(); ++typeIt) {
const std::string &mediaType = typeIt->first;
const Switch typeEnabled = isSettingEnabled(
"media-type-" + mediaType, settings, Switch::ENABLED_BY_DEFAULT());
const Switch domainTypeEnabled = isSettingEnabled(
"media-type-" + mediaType + (encoder ? "-encoder" : "-decoder"),
settings, Switch::ENABLED_BY_DEFAULT());
ALOGV("type '%s-%s' is '%s/%s'",
mediaType.c_str(), (encoder ? "encoder" : "decoder"),
asString(typeEnabled), asString(domainTypeEnabled));
if (!typeEnabled || !domainTypeEnabled) {
ALOGD("media type '%s' for codec entry '%s' is disabled", mediaType.c_str(),
nameOrAlias.c_str());
continue;
}
ALOGI("adding type '%s'", typeIt->first.c_str());
const MediaCodecsXmlParser::AttributeMap &attrMap = typeIt->second;
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
codecInfo->addMediaType(mediaType.c_str());
for (const auto &v : attrMap) {
std::string key = v.first;
std::string value = v.second;
size_t variantSep = key.find(":::");
if (variantSep != std::string::npos) {
std::string variant = key.substr(0, variantSep);
const Switch enabled = isVariantExpressionEnabled(variant, settings);
ALOGV("variant '%s' is '%s'", variant.c_str(), asString(enabled));
if (!enabled) {
continue;
}
key = key.substr(variantSep + 3);
}
if (key.find("feature-") == 0 && key.find("feature-bitrate-modes") != 0) {
int32_t intValue = 0;
// Ignore trailing bad characters and default to 0.
(void)sscanf(value.c_str(), "%d", &intValue);
caps->addDetail(key.c_str(), intValue);
} else {
caps->addDetail(key.c_str(), value.c_str());
}
}
addSupportedProfileLevels(intf, caps.get(), trait, mediaType);
addSupportedColorFormats(intf, caps.get(), trait, mediaType);
}
}
}
return OK;
}
- 在目录 "/apex/com.android.media.swcodec/etc" 中查找 "media_codecs_c2.xml" 和 "media_codecs_performance_c2.xml" 文件
- 解析相关文件设置编解码信息
-
相关 OMX Service 的启动
/frameworks/av/services/mediacodec/main_codecservice.cpp
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);
// Default codec services
using namespace ::android::hardware::media::omx::V1_0;
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.";
}
sp<IOmxStore> omxStore = new implementation::OmxStore(omx);
if (omxStore == nullptr) {
LOG(ERROR) << "Cannot create IOmxStore HAL service.";
} else if (omxStore->registerAsService() != OK) {
LOG(ERROR) << "Cannot register IOmxStore HAL service.";
}
::android::hardware::joinRpcThreadpool();
}
此函数分辨启动了 Omx 和 OmxStore 服务
-
首先是 Omx
/frameworks/av/media/libstagefright/omx/1.0/Omx.cpp
Omx::Omx() :
mMaster(new OMXMaster()),
mParser() {
(void)mParser.parseXmlFilesInSearchDirs();
(void)mParser.parseXmlPath(mParser.defaultProfilingResultsXmlPath);
}
/frameworks/av/media/libstagefright/omx/OMXMaster.cpp
void OMXMaster::addPlugin(const char *libname) {
if (::android::base::GetIntProperty("vendor.media.omx", int64_t(1)) == 0) {
return;
}
void *libHandle = android_load_sphal_library(libname, RTLD_NOW);
if (libHandle == NULL) {
return;
}
typedef OMXPluginBase *(*CreateOMXPluginFunc)();
CreateOMXPluginFunc createOMXPlugin =
(CreateOMXPluginFunc)dlsym(
libHandle, "createOMXPlugin");
if (!createOMXPlugin)
createOMXPlugin = (CreateOMXPluginFunc)dlsym(
libHandle, "_ZN7android15createOMXPluginEv");
OMXPluginBase *plugin = nullptr;
if (createOMXPlugin) {
plugin = (*createOMXPlugin)();
}
if (plugin) {
mPlugins.push_back({ plugin, libHandle });
addPlugin(plugin);
} else {
android_unload_sphal_library(libHandle);
}
}
OMXMaster 负责加载 "libstagefrighthw.so" 和 "libstagefright_softomx_plugin.so" 库文件,调用其中的 createOMXPlugin 函数来获取对应的解码器的库文件
-
重点看一下 SoftOMXPlugin
/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" },
};
可以看到所有关于 google 解码器的信息
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) {
if (strcmp(name, kComponents[i].mName)) {
continue;
}
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.
//
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;
}
sp<SoftOMXComponent> 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;
}
此函数加载指定的解码器
1. 通过查表合成字符串,生成对应 codec 的库文件
2. 调用对应库的 createSoftOMXComponent() 函数生成解码器
-
关于 OmxStore
/frameworks/av/media/libstagefright/omx/1.0/OmxStore.cpp
OmxStore::OmxStore(
const sp<IOmx> &omx,
const char* owner,
const std::vector<std::string> &searchDirs,
const std::vector<std::string> &xmlNames,
const char* profilingResultsXmlPath) {
// retrieve list of omx nodes
std::set<std::string> nodes;
if (omx != nullptr) {
omx->listNodes([&nodes](const Status &status,
const hidl_vec<IOmx::ComponentInfo> &nodeList) {
if (status == Status::OK) {
for (const IOmx::ComponentInfo& info : nodeList) {
nodes.emplace(info.mName.c_str());
}
}
});
}
MediaCodecsXmlParser parser;
parser.parseXmlFilesInSearchDirs(xmlNames, searchDirs);
if (profilingResultsXmlPath != nullptr) {
parser.parseXmlPath(profilingResultsXmlPath);
}
mParsingStatus = toStatus(parser.getParsingStatus());
const auto& serviceAttributeMap = parser.getServiceAttributeMap();
mServiceAttributeList.resize(serviceAttributeMap.size());
size_t i = 0;
for (const auto& attributePair : serviceAttributeMap) {
ServiceAttribute attribute;
attribute.key = attributePair.first;
attribute.value = attributePair.second;
mServiceAttributeList[i] = std::move(attribute);
++i;
}
const auto& roleMap = parser.getRoleMap();
mRoleList.resize(roleMap.size());
i = 0;
for (const auto& rolePair : roleMap) {
RoleInfo role;
role.role = rolePair.first;
role.type = rolePair.second.type;
role.isEncoder = rolePair.second.isEncoder;
role.preferPlatformNodes = false; // deprecated and ignored, using rank instead
hidl_vec<NodeInfo>& nodeList = role.nodes;
nodeList.resize(rolePair.second.nodeList.size());
size_t j = 0;
for (const auto& nodePair : rolePair.second.nodeList) {
if (!nodes.count(nodePair.second.name)) {
// not supported by this OMX instance
if (!strncasecmp(nodePair.second.name.c_str(), "omx.", 4)) {
LOG(INFO) << "node [" << nodePair.second.name.c_str() << "] not found in IOmx";
}
continue;
}
NodeInfo node;
node.name = nodePair.second.name;
node.owner = owner;
hidl_vec<NodeAttribute>& attributeList = node.attributes;
attributeList.resize(nodePair.second.attributeList.size());
size_t k = 0;
for (const auto& attributePair : nodePair.second.attributeList) {
NodeAttribute attribute;
attribute.key = attributePair.first;
attribute.value = attributePair.second;
attributeList[k] = std::move(attribute);
++k;
}
nodeList[j] = std::move(node);
++j;
}
nodeList.resize(j);
mRoleList[i] = std::move(role);
++i;
}
mPrefix = parser.getCommonPrefix();
}
函数解析 "/odm/etc", "/vendor/etc", "/etc" 目录中的 "media_codecs.xml" 和 "media_codecs_performance.xml" 文件,将相关的编解码信息保存到 mRoleList 中,其中 OmxInfoBuilder::buildMediaCodecList() 函数中有相关调用