(Android 11) MediaCodec 加载系统支持解码

  • 解析系统中所有支持的编码和解码器信息

/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;
}
  1. 在目录  "/apex/com.android.media.swcodec/etc" 中查找  "media_codecs_c2.xml" 和 "media_codecs_performance_c2.xml" 文件
  2. 解析相关文件设置编解码信息
  • 相关 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() 函数中有相关调用 

要在 Android 中使用 OpenGL ES 2.0 和 C/C++ 实现使用 MediaCodec 解码 MP4 视频格式并将其转换为 RGB 图像,需要完成以下步骤: 1. 创建 Android 应用程序并引入必要的库文件 在 Android Studio 中创建一个新的 Android 应用程序,并在 build.gradle 文件中添加以下库文件的引用: ``` // For decoding MP4 video format implementation 'com.google.android.exoplayer:exoplayer-core:2.X.X' implementation 'com.google.android.exoplayer:exoplayer-ui:2.X.X' // For using OpenGL ES in Android implementation 'com.android.support:support-v4:28.0.0' implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support:design:28.0.0' // For using C/C++ in Android implementation 'com.android.support:support-compat:28.0.0' implementation 'com.android.support:support-core-utils:28.0.0' implementation 'com.android.support:support-annotations:28.0.0' implementation 'com.android.support:support-core-ui:28.0.0' // For using MediaCodec in Android implementation 'com.android.support:support-media-compat:28.0.0' ``` 2. 创建 OpenGL 上下文并加载着色器程序 在 C/C++ 中使用 OpenGL ES 2.0,需要创建一个 OpenGL 上下文并加载着色器程序。可以使用 Android 提供的 NativeActivity 类来创建一个带有 OpenGL 上下文的活动,并使用 GLES20.glCreateProgram() 和 GLES20.glAttachShader() 等方法来加载着色器程序。 3. 使用 MediaCodec 解码 MP4 视频格式并将其转换为 RGB 图像 可以使用 Android 提供的 MediaCodec 类来解码 MP4 视频格式,并使用 GLES20.glTexImage2D() 和 GLES20.glTexSubImage2D() 等方法将解码后的视频帧转换为 RGB 图像。需要注意的是,由于 MediaCodec 解码后的视频帧是 YUV 格式的,需要进行 YUV 到 RGB 的转换。 4. 在 OpenGL 中渲染 RGB 图像 将转换后的 RGB 图像渲染到 OpenGL 中,可以使用 GLES20.glDrawArrays() 和 GLES20.glEnableVertexAttribArray() 等方法。需要注意的是,由于 RGB 图像的数据格式是 GL_UNSIGNED_BYTE,需要使用 GLES20.glPixelStorei() 方法设置像素存储模式。 以上是大致的代码实现步骤,实际上还有很多细节需要注意,比如使用 OpenGL ES 2.0 的版本号、将 YUV 转换为 RGB 的算法等。如果需要深入了解,可以查看 Android 官方文档和相关的开源库代码。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值