MediaCode 的CreateByComponentName和CreateByType会调用mediacodec的构造方法
// static sp<MediaCodec> MediaCodec::CreateByType( const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid, uid_t uid) { sp<AMessage> format; return CreateByType(looper, mime, encoder, err, pid, uid, format); } sp<MediaCodec> MediaCodec::CreateByType( const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid, uid_t uid, sp<AMessage> format) { Vector<AString> matchingCodecs; MediaCodecList::findMatchingCodecs( mime.c_str(), encoder, 0, format, &matchingCodecs); if (err != NULL) { *err = NAME_NOT_FOUND; } for (size_t i = 0; i < matchingCodecs.size(); ++i) { sp<MediaCodec> 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; }
// static sp<MediaCodec> MediaCodec::CreateByComponentName( const sp<ALooper> &looper, const AString &name, status_t *err, pid_t pid, uid_t uid) { sp<MediaCodec> codec = new MediaCodec(looper, pid, uid); const status_t ret = codec->init(name); if (err != NULL) { *err = ret; } return ret == OK ? codec : NULL; // NULL deallocates codec. }
MediaCodec的构造方法调用了MediaCodecList的getInstance方法
Z:\rb-a3399pb1\frameworks\av\media\libstagefright\MediaCodec.cpp
MediaCodec::MediaCodec( const sp<ALooper> &looper, pid_t pid, uid_t uid, std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase, std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo) : mState(UNINITIALIZED), mReleasedByResourceManager(false), mLooper(looper), mCodec(NULL), mReplyID(0), mFlags(0), mStickyError(OK), mSoftRenderer(NULL), mIsVideo(false), mVideoWidth(0), mVideoHeight(0), mRotationDegrees(0), mDequeueInputTimeoutGeneration(0), mDequeueInputReplyID(0), mDequeueOutputTimeoutGeneration(0), mDequeueOutputReplyID(0), mTunneledInputWidth(0), mTunneledInputHeight(0), mTunneled(false), mTunnelPeekState(TunnelPeekState::kEnabledNoBuffer), mHaveInputSurface(false), mHavePendingInputBuffers(false), mCpuBoostRequested(false), mPlaybackDurationAccumulator(new PlaybackDurationAccumulator()), mIsSurfaceToScreen(false), mLatencyUnknown(0), mBytesEncoded(0), mEarliestEncodedPtsUs(INT64_MAX), mLatestEncodedPtsUs(INT64_MIN), mFramesEncoded(0), mNumLowLatencyEnables(0), mNumLowLatencyDisables(0), mIsLowLatencyModeOn(false), mIndexOfFirstFrameWhenLowLatencyOn(-1), mInputBufferCounter(0), mGetCodecBase(getCodecBase), mGetCodecInfo(getCodecInfo) { if (uid == kNoUid) { mUid = AIBinder_getCallingUid(); } else { mUid = uid; } mResourceManagerProxy = new ResourceManagerServiceProxy(pid, mUid, ::ndk::SharedRefBase::make<ResourceManagerClient>(this)); if (!mGetCodecBase) { mGetCodecBase = [](const AString &name, const char *owner) { return GetCodecBase(name, owner); }; } if (!mGetCodecInfo) { mGetCodecInfo = [](const AString &name, sp<MediaCodecInfo> *info) -> status_t { *info = nullptr; const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
1.MediaCodecList.cpp开始讲,前面的流程我也不太懂。
MediaCodecList位于 frameworks\av\media\libstagefright\MediaCodecList.cpp
// static sp<IMediaCodecList> MediaCodecList::getInstance() { Mutex::Autolock _l(sRemoteInitMutex); if (sRemoteList == nullptr) { sMediaPlayer = defaultServiceManager()->getService(String16("media.player"));获取mediaplayerservice sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(sMediaPlayer); if (service.get() != nullptr) { sRemoteList = service->getCodecList(); 获取codecList if (sRemoteList != nullptr) { sBinderDeathObserver = new BinderDeathObserver(); sMediaPlayer->linkToDeath(sBinderDeathObserver.get()); 保活 } } if (sRemoteList == nullptr) { // if failed to get remote list, create local list sRemoteList = getLocalInstance(); 获取codecList } } return sRemoteList; }
frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp 的 getCodecList方法实际上调用的还是MediaCodecList的getLocalInstance方法
sp<IMediaCodecList> MediaPlayerService::getCodecList() const {
return MediaCodecList::getLocalInstance();
}
// static sp<IMediaCodecList> 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; }
获取builders
std::unique_ptr<MediaCodecListBuilderBase> sCodec2InfoBuilder; MediaCodecListBuilderBase *GetCodec2InfoBuilder() { Mutex::Autolock _l(sCodec2InfoBuilderMutex); if (!sCodec2InfoBuilder) { sCodec2InfoBuilder.reset(new Codec2InfoBuilder); } 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 = CCodec::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; }
构造方法如下:
MediaCodecList::MediaCodecList(std::vector<MediaCodecListBuilderBase*> builders) { mGlobalSettings = new AMessage(); mCodecInfos.clear(); MediaCodecListWriter writer; for (MediaCodecListBuilderBase *builder : builders) { if (builder == nullptr) { ALOGD("ignored a null builder"); continue; } auto currentCheck = builder->buildMediaCodecList(&writer); 创建mediacodeclist if (currentCheck != OK) { ALOGD("ignored failed builder"); continue; } else { mInitCheck = currentCheck; } } writer.writeGlobalSettings(mGlobalSettings); writer.writeCodecInfos(&mCodecInfos); std::stable_sort( mCodecInfos.begin(), mCodecInfos.end(), [](const sp<MediaCodecInfo> &info1, const sp<MediaCodecInfo> &info2) { // null is lowest return info1 == nullptr || (info2 != nullptr && info1->getRank() < info2->getRank()); }); // remove duplicate entries bool dedupe = property_get_bool("debug.stagefright.dedupe-codecs", true); if (dedupe) { std::set<std::string> codecsSeen; for (auto it = mCodecInfos.begin(); it != mCodecInfos.end(); ) { std::string codecName = (*it)->getCodecName(); if (codecsSeen.count(codecName) == 0) { codecsSeen.emplace(codecName); it++; } else { it = mCodecInfos.erase(it); } } } }
std::unique_ptr<MediaCodecListBuilderBase> sCodec2InfoBuilder;
MediaCodecListBuilderBase 有两种 Codec2InfoBuilder 和 OmxInfoBuilder
Z:\rb-a3399pb1\frameworks\av\media\codec2\sfplugin\Codec2InfoBuilder.cpp 进行xml的解析
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. // Note: APEX XML names do not depend on ro.media.xml_variant.* properties. MediaCodecsXmlParser parser; parser.parseXmlFilesInSearchDirs( { "media_codecs.xml", "media_codecs_performance.xml" }, { "/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(); // The mainline modules for media may optionally include some codec shaping information. // Based on vendor partition SDK, and the brand/product/device information // (expect to be empty in almost always) // { // get build info so we know what file to search // ro.vendor.build.fingerprint std::string fingerprint = base::GetProperty("ro.vendor.build.fingerprint", "brand/product/device:"); ALOGV("property_get for ro.vendor.build.fingerprint == '%s'", fingerprint.c_str()); // ro.vendor.build.version.sdk std::string sdk = base::GetProperty("ro.vendor.build.version.sdk", "0"); ALOGV("property_get for ro.vendor.build.version.sdk == '%s'", sdk.c_str()); std::string brand; std::string product; std::string device; size_t pos1; pos1 = fingerprint.find('/'); if (pos1 != std::string::npos) { brand = fingerprint.substr(0, pos1); size_t pos2 = fingerprint.find('/', pos1+1); if (pos2 != std::string::npos) { product = fingerprint.substr(pos1+1, pos2 - pos1 - 1); size_t pos3 = fingerprint.find('/', pos2+1); if (pos3 != std::string::npos) { device = fingerprint.substr(pos2+1, pos3 - pos2 - 1); size_t pos4 = device.find(':'); if (pos4 != std::string::npos) { device.resize(pos4); } } } } ALOGV("parsed: sdk '%s' brand '%s' product '%s' device '%s'", sdk.c_str(), brand.c_str(), product.c_str(), device.c_str()); std::string base = "/apex/com.android.media/etc/formatshaper"; // looking in these directories within the apex const std::vector<std::string> modulePathnames = { base + "/" + sdk + "/" + brand + "/" + product + "/" + device, base + "/" + sdk + "/" + brand + "/" + product, base + "/" + sdk + "/" + brand, base + "/" + sdk, base }; parser.parseXmlFilesInSearchDirs( { "media_codecs_shaping.xml" }, modulePathnames); } 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()); } } if (!addSupportedProfileLevels(intf, caps.get(), trait, mediaType)) { // TODO(b/193279646) This will get fixed in C2InterfaceHelper // Some components may not advertise supported values if they use a const // param for profile/level (they support only one profile). For now cover // only VP8 here until it is fixed. if (mediaType == MIMETYPE_VIDEO_VP8) { caps->addProfileLevel(VP8ProfileMain, VP8Level_Version0); } } addSupportedColorFormats(intf, caps.get(), trait, mediaType); } } } return OK; }
MediaCodecsXmlParser 位于 frameworks\av\media\libstagefright\xmlparser\MediaCodecsXmlParser.cpp frameworks\av\media\libstagefright\xmlparser\include\media\stagefright\xmlparser\MediaCodecsXmlParser.h
用于解析xml
status_t parseXmlFilesInSearchDirs(
const std::vector<std::string> &xmlFiles = getDefaultXmlNames(),
const std::vector<std::string> &searchDirs = getDefaultSearchDirs());
static std::vector<std::string> getDefaultSearchDirs() { return { "/product/etc", "/odm/etc", "/vendor/etc", "/system/etc" }; }
std::vector<std::string> MediaCodecsXmlParser::getDefaultXmlNames() { static constexpr char const* prefixes[] = { "media_codecs", "media_codecs_performance" };
会优先读取/apex/com.android.media.swcodec/etc下的media_codecs.xml