From 60b1c0e79d12a1c70758bc8d060156924635f8ba Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 6 Aug 2014 16:55:46 -0700 Subject: stagefright: rework media codec list and infos This is in preparation of serving the codec list and codec infos from the mediaserver Bug: 11990470 Change-Id: Ib8e2708679c9ce461a4ba179974a740cdcdf2731 --- media/libmedia/Android.mk | 3 + media/libmedia/IMediaCodecList.cpp | 163 ++++++++++++++ media/libmedia/MediaCodecInfo.cpp | 252 +++++++++++++++++++++ media/libstagefright/MediaCodec.cpp | 16 +- media/libstagefright/MediaCodecList.cpp | 374 ++++++++++++-------------------- media/libstagefright/OMXCodec.cpp | 26 +-- 6 files changed, 574 insertions(+), 260 deletions(-) create mode 100644 media/libmedia/IMediaCodecList.cpp create mode 100644 media/libmedia/MediaCodecInfo.cpp (limited to 'media') diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index cee26d9..3be0651 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -25,6 +25,7 @@ LOCAL_SRC_FILES:= \ AudioRecord.cpp \ AudioSystem.cpp \ mediaplayer.cpp \ + IMediaCodecList.cpp \ IMediaHTTPConnection.cpp \ IMediaHTTPService.cpp \ IMediaLogService.cpp \ @@ -36,6 +37,7 @@ LOCAL_SRC_FILES:= \ IRemoteDisplay.cpp \ IRemoteDisplayClient.cpp \ IStreamSource.cpp \ + MediaCodecInfo.cpp \ Metadata.cpp \ mediarecorder.cpp \ IMediaMetadataRetriever.cpp \ @@ -74,6 +76,7 @@ LOCAL_MODULE:= libmedia LOCAL_C_INCLUDES := \ $(TOP)/frameworks/native/include/media/openmax \ + $(TOP)/frameworks/av/media/libstagefright \ external/icu/icu4c/source/common \ external/icu/icu4c/source/i18n \ $(call include-path-for, audio-effects) \ diff --git a/media/libmedia/IMediaCodecList.cpp b/media/libmedia/IMediaCodecList.cpp new file mode 100644 index 0000000..bf7c5ca --- /dev/null +++ b/media/libmedia/IMediaCodecList.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include + +#include // for status_t + +namespace android { + +enum { + CREATE = IBinder::FIRST_CALL_TRANSACTION, + COUNT_CODECS, + GET_CODEC_INFO, + FIND_CODEC_BY_TYPE, + FIND_CODEC_BY_NAME, +}; + +class BpMediaCodecList: public BpInterface +{ +public: + BpMediaCodecList(const sp& impl) + : BpInterface(impl) + { + } + + virtual size_t countCodecs() const + { + Parcel data, reply; + data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor()); + remote()->transact(COUNT_CODECS, data, &reply); + return static_cast(reply.readInt32()); + } + + virtual sp getCodecInfo(size_t index) const + { + Parcel data, reply; + data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor()); + data.writeInt32(index); + remote()->transact(GET_CODEC_INFO, data, &reply); + status_t err = reply.readInt32(); + if (err == OK) { + return MediaCodecInfo::FromParcel(reply); + } else { + return NULL; + } + } + + virtual ssize_t findCodecByType( + const char *type, bool encoder, size_t startIndex = 0) const + { + if (startIndex > INT32_MAX) { + return NAME_NOT_FOUND; + } + + Parcel data, reply; + data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor()); + data.writeCString(type); + data.writeInt32(encoder); + data.writeInt32(startIndex); + remote()->transact(FIND_CODEC_BY_TYPE, data, &reply); + return static_cast(reply.readInt32()); + } + + virtual ssize_t findCodecByName(const char *name) const + { + Parcel data, reply; + data.writeInterfaceToken(IMediaCodecList::getInterfaceDescriptor()); + data.writeCString(name); + remote()->transact(FIND_CODEC_BY_NAME, data, &reply); + return static_cast(reply.readInt32()); + } +}; + +IMPLEMENT_META_INTERFACE(MediaCodecList, "android.media.IMediaCodecList"); + +// ---------------------------------------------------------------------- + +status_t BnMediaCodecList::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch (code) { + case COUNT_CODECS: + { + CHECK_INTERFACE(IMediaCodecList, data, reply); + size_t count = countCodecs(); + if (count > INT32_MAX) { + count = INT32_MAX; + } + reply->writeInt32(count); + return NO_ERROR; + } + break; + + case GET_CODEC_INFO: + { + CHECK_INTERFACE(IMediaCodecList, data, reply); + size_t index = static_cast(data.readInt32()); + const sp info = getCodecInfo(index); + if (info != NULL) { + reply->writeInt32(OK); + info->writeToParcel(reply); + } else { + reply->writeInt32(-ERANGE); + } + return NO_ERROR; + } + break; + + case FIND_CODEC_BY_TYPE: + { + CHECK_INTERFACE(IMediaCodecList, data, reply); + const char *type = data.readCString(); + bool isEncoder = static_cast(data.readInt32()); + size_t startIndex = static_cast(data.readInt32()); + ssize_t index = findCodecByType(type, isEncoder, startIndex); + if (index > INT32_MAX || index < 0) { + index = NAME_NOT_FOUND; + } + reply->writeInt32(index); + return NO_ERROR; + } + break; + + case FIND_CODEC_BY_NAME: + { + CHECK_INTERFACE(IMediaCodecList, data, reply); + const char *name = data.readCString(); + ssize_t index = findCodecByName(name); + if (index > INT32_MAX || index < 0) { + index = NAME_NOT_FOUND; + } + reply->writeInt32(index); + return NO_ERROR; + } + break; + + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp new file mode 100644 index 0000000..7900eae --- /dev/null +++ b/media/libmedia/MediaCodecInfo.cpp @@ -0,0 +1,252 @@ +/* + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaCodecInfo" +#include + +#include + +#include + +#include +#include +#include + +#include + +namespace android { + +void MediaCodecInfo::Capabilities::getSupportedProfileLevels( + Vector *profileLevels) const { + profileLevels->clear(); + profileLevels->appendVector(mProfileLevels); +} + +void MediaCodecInfo::Capabilities::getSupportedColorFormats( + Vector *colorFormats) const { + colorFormats->clear(); + colorFormats->appendVector(mColorFormats); +} + +uint32_t MediaCodecInfo::Capabilities::getFlags() const { + return mFlags; +} + +const sp &MediaCodecInfo::Capabilities::getDetails() const { + return mDetails; +} + +MediaCodecInfo::Capabilities::Capabilities() + : mFlags(0) { + mDetails = new AMessage; +} + +// static +sp MediaCodecInfo::Capabilities::FromParcel( + const Parcel &parcel) { + sp caps = new Capabilities(); + size_t size = static_cast(parcel.readInt32()); + for (size_t i = 0; i < size; i++) { + ProfileLevel profileLevel; + profileLevel.mProfile = static_cast(parcel.readInt32()); + profileLevel.mLevel = static_cast(parcel.readInt32()); + if (caps != NULL) { + caps->mProfileLevels.push_back(profileLevel); + } + } + size = static_cast(parcel.readInt32()); + for (size_t i = 0; i < size; i++) { + uint32_t color = static_cast(parcel.readInt32()); + if (caps != NULL) { + caps->mColorFormats.push_back(color); + } + } + uint32_t flags = static_cast(parcel.readInt32()); + sp details = AMessage::FromParcel(parcel); + if (caps != NULL) { + caps->mFlags = flags; + caps->mDetails = details; + } + return caps; +} + +status_t MediaCodecInfo::Capabilities::writeToParcel(Parcel *parcel) const { + CHECK_LE(mProfileLevels.size(), INT32_MAX); + parcel->writeInt32(mProfileLevels.size()); + for (size_t i = 0; i < mProfileLevels.size(); i++) { + parcel->writeInt32(mProfileLevels.itemAt(i).mProfile); + parcel->writeInt32(mProfileLevels.itemAt(i).mLevel); + } + CHECK_LE(mColorFormats.size(), INT32_MAX); + parcel->writeInt32(mColorFormats.size()); + for (size_t i = 0; i < mColorFormats.size(); i++) { + parcel->writeInt32(mColorFormats.itemAt(i)); + } + parcel->writeInt32(mFlags); + mDetails->writeToParcel(parcel); + return OK; +} + +bool MediaCodecInfo::isEncoder() const { + return mIsEncoder; +} + +bool MediaCodecInfo::hasQuirk(const char *name) const { + for (size_t ix = 0; ix < mQuirks.size(); ix++) { + if (mQuirks.itemAt(ix).equalsIgnoreCase(name)) { + return true; + } + } + return false; +} + +void MediaCodecInfo::getSupportedMimes(Vector *mimes) const { + mimes->clear(); + for (size_t ix = 0; ix < mCaps.size(); ix++) { + mimes->push_back(mCaps.keyAt(ix)); + } +} + +const sp & +MediaCodecInfo::getCapabilitiesFor(const char *mime) const { + ssize_t ix = getCapabilityIndex(mime); + if (ix >= 0) { + return mCaps.valueAt(ix); + } + return NULL; +} + +const char *MediaCodecInfo::getCodecName() const { + return mName.c_str(); +} + +// static +sp MediaCodecInfo::FromParcel(const Parcel &parcel) { + AString name = AString::FromParcel(parcel); + bool isEncoder = static_cast(parcel.readInt32()); + sp info = new MediaCodecInfo(name, isEncoder, NULL); + size_t size = static_cast(parcel.readInt32()); + for (size_t i = 0; i < size; i++) { + AString quirk = AString::FromParcel(parcel); + if (info != NULL) { + info->mQuirks.push_back(quirk); + } + } + size = static_cast(parcel.readInt32()); + for (size_t i = 0; i < size; i++) { + AString mime = AString::FromParcel(parcel); + sp caps = Capabilities::FromParcel(parcel); + if (info != NULL) { + info->mCaps.add(mime, caps); + } + } + return info; +} + +status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const { + mName.writeToParcel(parcel); + parcel->writeInt32(mIsEncoder); + parcel->writeInt32(mQuirks.size()); + for (size_t i = 0; i < mQuirks.size(); i++) { + mQuirks.itemAt(i).writeToParcel(parcel); + } + parcel->writeInt32(mCaps.size()); + for (size_t i = 0; i < mCaps.size(); i++) { + mCaps.keyAt(i).writeToParcel(parcel); + mCaps.valueAt(i)->writeToParcel(parcel); + } + return OK; +} + +ssize_t MediaCodecInfo::getCapabilityIndex(const char *mime) const { + for (size_t ix = 0; ix < mCaps.size(); ix++) { + if (mCaps.keyAt(ix).equalsIgnoreCase(mime)) { + return ix; + } + } + return -1; +} + +MediaCodecInfo::MediaCodecInfo(AString name, bool encoder, const char *mime) + : mName(name), + mIsEncoder(encoder), + mHasSoleMime(false) { + if (mime != NULL) { + addMime(mime); + mHasSoleMime = true; + } +} + +status_t MediaCodecInfo::addMime(const char *mime) { + if (mHasSoleMime) { + ALOGE("Codec '%s' already had its type specified", mName.c_str()); + return -EINVAL; + } + ssize_t ix = getCapabilityIndex(mime); + if (ix >= 0) { + mCurrentCaps = mCaps.valueAt(ix); + } else { + mCurrentCaps = new Capabilities(); + mCaps.add(AString(mime), mCurrentCaps); + } + return OK; +} + +status_t MediaCodecInfo::initializeCapabilities(const CodecCapabilities &caps) { + mCurrentCaps->mProfileLevels.clear(); + mCurrentCaps->mColorFormats.clear(); + + for (size_t i = 0; i < caps.mProfileLevels.size(); ++i) { + const CodecProfileLevel &src = caps.mProfileLevels.itemAt(i); + + ProfileLevel profileLevel; + profileLevel.mProfile = src.mProfile; + profileLevel.mLevel = src.mLevel; + mCurrentCaps->mProfileLevels.push_back(profileLevel); + } + + for (size_t i = 0; i < caps.mColorFormats.size(); ++i) { + mCurrentCaps->mColorFormats.push_back(caps.mColorFormats.itemAt(i)); + } + + mCurrentCaps->mFlags = caps.mFlags; + mCurrentCaps->mDetails = new AMessage; + + return OK; +} + +void MediaCodecInfo::addQuirk(const char *name) { + if (!hasQuirk(name)) { + mQuirks.push(name); + } +} + +void MediaCodecInfo::complete() { + mCurrentCaps = NULL; +} + +void MediaCodecInfo::addDetail(const AString &key, const AString &value) { + mCurrentCaps->mDetails->setString(key.c_str(), value.c_str()); +} + +void MediaCodecInfo::addFeature(const AString &key, int32_t value) { + AString tag = "feature-"; + tag.append(key); + mCurrentCaps->mDetails->setInt32(tag.c_str(), value); +} + +} // namespace android diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 7c02959..a67a933 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -195,16 +195,16 @@ status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) { if (tmp.endsWith(".secure")) { tmp.erase(tmp.size() - 7, 7); } - const MediaCodecList *mcl = MediaCodecList::getInstance(); + const sp mcl = MediaCodecList::getInstance(); ssize_t codecIdx = mcl->findCodecByName(tmp.c_str()); if (codecIdx >= 0) { - Vector types; - if (mcl->getSupportedTypes(codecIdx, &types) == OK) { - for (size_t i = 0; i < types.size(); i++) { - if (types[i].startsWith("video/")) { - needDedicatedLooper = true; - break; - } + const sp info = mcl->getCodecInfo(codecIdx); + Vector mimes; + info->getSupportedMimes(&mimes); + for (size_t i = 0; i < mimes.size(); i++) { + if (mimes[i].startsWith("video/")) { + needDedicatedLooper = true; + break; } } } diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index d021533..60809c1 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -18,13 +18,19 @@ #define LOG_TAG "MediaCodecList" #include -#include +#include + +#include +#include +#include #include #include +#include #include #include #include + #include #include @@ -33,18 +39,32 @@ namespace android { static Mutex sInitMutex; +static MediaCodecList *gCodecList = NULL; + // static -MediaCodecList *MediaCodecList::sCodecList; +sp MediaCodecList::sCodecList; // static -const MediaCodecList *MediaCodecList::getInstance() { +sp MediaCodecList::getLocalInstance() { Mutex::Autolock autoLock(sInitMutex); - if (sCodecList == NULL) { - sCodecList = new MediaCodecList; + if (gCodecList == NULL) { + gCodecList = new MediaCodecList; + if (gCodecList->initCheck() == OK) { + sCodecList = gCodecList; + } } - return sCodecList->initCheck() == OK ? sCodecList : NULL; + return sCodecList; +} + +static Mutex sRemoteInitMutex; + +sp MediaCodecList::sRemoteList; + +// static +sp MediaCodecList::getInstance() { + return getLocalInstance(); } MediaCodecList::MediaCodecList() @@ -59,37 +79,69 @@ void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml) { mHrefBase = AString(codecs_xml, href_base_end - codecs_xml + 1); } - mInitCheck = OK; + mInitCheck = OK; // keeping this here for safety mCurrentSection = SECTION_TOPLEVEL; mDepth = 0; + OMXClient client; + mInitCheck = client.connect(); + if (mInitCheck != OK) { + return; + } + mOMX = client.interface(); parseXMLFile(codecs_xml); + mOMX.clear(); if (mInitCheck != OK) { mCodecInfos.clear(); - mCodecQuirks.clear(); return; } for (size_t i = mCodecInfos.size(); i-- > 0;) { - CodecInfo *info = &mCodecInfos.editItemAt(i); + const MediaCodecInfo &info = *mCodecInfos.itemAt(i).get(); - if (info->mTypes == 0) { + if (info.mCaps.size() == 0) { // No types supported by this component??? ALOGW("Component %s does not support any type of media?", - info->mName.c_str()); + info.mName.c_str()); mCodecInfos.removeAt(i); #if LOG_NDEBUG == 0 } else { - for (size_t type_ix = 0; type_ix < mTypes.size(); ++type_ix) { - uint32_t typeMask = 1ul << mTypes.valueAt(type_ix); - if (info->mTypes & typeMask) { - AString mime = mTypes.keyAt(type_ix); - uint32_t bit = mTypes.valueAt(type_ix); - - ALOGV("%s codec info for %s: %s", info->mName.c_str(), mime.c_str(), - info->mCaps.editValueFor(bit)->debugString().c_str()); + for (size_t type_ix = 0; type_ix < info.mCaps.size(); ++type_ix) { + AString mime = info.mCaps.keyAt(type_ix); + const sp &caps = info.mCaps.valueAt(type_ix); + + ALOGV("%s codec info for %s: %s", info.mName.c_str(), mime.c_str(), + caps->getDetails()->debugString().c_str()); + ALOGV(" flags=%d", caps->getFlags()); + { + Vector colorFormats; + caps->getSupportedColorFormats(&colorFormats); + AString nice; + for (size_t ix = 0; ix < colorFormats.size(); ix++) { + if (ix > 0) { + nice.append(", "); + } + nice.append(colorFormats.itemAt(ix)); + } + ALOGV(" colors=[%s]", nice.c_str()); + } + { + Vector profileLevels; + caps->getSupportedProfileLevels(&profileLevels); + AString nice; + for (size_t ix = 0; ix < profileLevels.size(); ix++) { + if (ix > 0) { + nice.append(", "); + } + const MediaCodecInfo::ProfileLevel &pl = + profileLevels.itemAt(ix); + nice.append(pl.mProfile); + nice.append("/"); + nice.append(pl.mLevel); + } + ALOGV(" levels=[%s]", nice.c_str()); } } #endif @@ -294,9 +346,8 @@ void MediaCodecList::startElementHandler( case SECTION_DECODER_TYPE: case SECTION_ENCODER_TYPE: { - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); // ignore limits and features specified outside of type - bool outside = !inType && info->mSoleType == 0; + bool outside = !inType && !mCurrentInfo->mHasSoleMime; if (outside && (!strcmp(name, "Limit") || !strcmp(name, "Feature"))) { ALOGW("ignoring %s specified outside of a Type", name); } else if (!strcmp(name, "Limit")) { @@ -344,8 +395,7 @@ void MediaCodecList::endElementHandler(const char *name) { (mCurrentSection == SECTION_DECODER_TYPE ? SECTION_DECODER : SECTION_ENCODER); - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - info->mCurrentCaps = NULL; + mCurrentInfo->complete(); } break; } @@ -354,9 +404,8 @@ void MediaCodecList::endElementHandler(const char *name) { { if (!strcmp(name, "MediaCodec")) { mCurrentSection = SECTION_DECODERS; - - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - info->mCurrentCaps = NULL; + mCurrentInfo->complete(); + mCurrentInfo = NULL; } break; } @@ -365,9 +414,8 @@ void MediaCodecList::endElementHandler(const char *name) { { if (!strcmp(name, "MediaCodec")) { mCurrentSection = SECTION_ENCODERS; - - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - info->mCurrentCaps = NULL; + mCurrentInfo->complete();; + mCurrentInfo = NULL; } break; } @@ -418,28 +466,27 @@ status_t MediaCodecList::addMediaCodecFromAttributes( return -EINVAL; } - addMediaCodec(encoder, name, type); - - return OK; + mCurrentInfo = new MediaCodecInfo(name, encoder, type); + mCodecInfos.push_back(mCurrentInfo); + return initializeCapabilities(type); } -void MediaCodecList::addMediaCodec( - bool encoder, const char *name, const char *type) { - mCodecInfos.push(); - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - info->mName = name; - info->mIsEncoder = encoder; - info->mSoleType = 0; - info->mTypes = 0; - info->mQuirks = 0; - info->mCurrentCaps = NULL; - - if (type != NULL) { - addType(type); - // if type was specified in attributes, we do not allow - // subsequent types - info->mSoleType = info->mTypes; +status_t MediaCodecList::initializeCapabilities(const char *type) { + ALOGV("initializeCapabilities %s:%s", + mCurrentInfo->mName.c_str(), type); + + CodecCapabilities caps; + status_t err = QueryCodec( + mOMX, + mCurrentInfo->mName.c_str(), + type, + mCurrentInfo->mIsEncoder, + &caps); + if (err != OK) { + return err; } + + return mCurrentInfo->initializeCapabilities(caps); } status_t MediaCodecList::addQuirk(const char **attrs) { @@ -464,36 +511,13 @@ status_t MediaCodecList::addQuirk(const char **attrs) { return -EINVAL; } - uint32_t bit; - ssize_t index = mCodecQuirks.indexOfKey(name); - if (index < 0) { - bit = mCodecQuirks.size(); - - if (bit == 32) { - ALOGW("Too many distinct quirk names in configuration."); - return OK; - } - - mCodecQuirks.add(name, bit); - } else { - bit = mCodecQuirks.valueAt(index); - } - - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - info->mQuirks |= 1ul << bit; - + mCurrentInfo->addQuirk(name); return OK; } status_t MediaCodecList::addTypeFromAttributes(const char **attrs) { const char *name = NULL; - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - if (info->mSoleType != 0) { - ALOGE("Codec '%s' already had its type specified", info->mName.c_str()); - return -EINVAL; - } - size_t i = 0; while (attrs[i] != NULL) { if (!strcmp(attrs[i], "name")) { @@ -513,54 +537,47 @@ status_t MediaCodecList::addTypeFromAttributes(const char **attrs) { return -EINVAL; } - addType(name); - - return OK; -} - -void MediaCodecList::addType(const char *name) { - uint32_t bit; - ssize_t index = mTypes.indexOfKey(name); - if (index < 0) { - bit = mTypes.size(); - - if (bit == 32) { - ALOGW("Too many distinct type names in configuration."); - return; - } - - mTypes.add(name, bit); - } else { - bit = mTypes.valueAt(index); - } - - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - info->mTypes |= 1ul << bit; - if (info->mCaps.indexOfKey(bit) < 0) { - AMessage *msg = new AMessage(); - info->mCaps.add(bit, msg); + status_t ret = mCurrentInfo->addMime(name); + if (ret == OK) { + ret = initializeCapabilities(name); } - info->mCurrentCaps = info->mCaps.editValueFor(bit); + return ret; } +// legacy method for non-advanced codecs ssize_t MediaCodecList::findCodecByType( const char *type, bool encoder, size_t startIndex) const { - ssize_t typeIndex = mTypes.indexOfKey(type); + static const char *advancedFeatures[] = { + "feature-secure-playback", + "feature-tunneled-playback", + }; - if (typeIndex < 0) { - return -ENOENT; - } + size_t numCodecs = mCodecInfos.size(); + for (; startIndex < numCodecs; ++startIndex) { + const MediaCodecInfo &info = *mCodecInfos.itemAt(startIndex).get(); - uint32_t typeMask = 1ul << mTypes.valueAt(typeIndex); + if (info.isEncoder() != encoder) { + continue; + } + sp capabilities = info.getCapabilitiesFor(type); + if (capabilities == NULL) { + continue; + } + const sp &details = capabilities->getDetails(); - while (startIndex < mCodecInfos.size()) { - const CodecInfo &info = mCodecInfos.itemAt(startIndex); + int32_t required; + bool isAdvanced = false; + for (size_t ix = 0; ix < ARRAY_SIZE(advancedFeatures); ix++) { + if (details->findInt32(advancedFeatures[ix], &required) && + required != 0) { + isAdvanced = true; + break; + } + } - if (info.mIsEncoder == encoder && (info.mTypes & typeMask)) { + if (!isAdvanced) { return startIndex; } - - ++startIndex; } return -ENOENT; @@ -616,12 +633,11 @@ status_t MediaCodecList::addLimit(const char **attrs) { return -EINVAL; } - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - // size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio: range // quality: range + default + [scale] // complexity: range + default bool found; + if (name == "aspect-ratio" || name == "bitrate" || name == "block-count" || name == "blocks-per-second" || name == "complexity" || name == "frame-rate" || name == "quality" || name == "size") { @@ -672,16 +688,16 @@ status_t MediaCodecList::addLimit(const char **attrs) { name = in_; } if (name == "quality") { - info->mCurrentCaps->setString("quality-scale", scale); + mCurrentInfo->addDetail("quality-scale", scale); } if (name == "quality" || name == "complexity") { AString tag = name; tag.append("-default"); - info->mCurrentCaps->setString(tag.c_str(), def); + mCurrentInfo->addDetail(tag, def); } AString tag = name; tag.append("-range"); - info->mCurrentCaps->setString(tag.c_str(), range); + mCurrentInfo->addDetail(tag, range); } else { AString max, value, ranges; if (msg->contains("default")) { @@ -708,13 +724,13 @@ status_t MediaCodecList::addLimit(const char **attrs) { if (max.size()) { AString tag = "max-"; tag.append(name); - info->mCurrentCaps->setString(tag.c_str(), max); + mCurrentInfo->addDetail(tag, max); } else if (value.size()) { - info->mCurrentCaps->setString(name.c_str(), value); + mCurrentInfo->addDetail(name, value); } else if (ranges.size()) { AString tag = name; tag.append("-ranges"); - info->mCurrentCaps->setString(tag.c_str(), ranges); + mCurrentInfo->addDetail(tag, ranges); } else { ALOGW("Ignoring unrecognized limit '%s'", name.c_str()); } @@ -769,16 +785,13 @@ status_t MediaCodecList::addFeature(const char **attrs) { return -EINVAL; } - CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); - AString tag = "feature-"; - tag.append(name); - info->mCurrentCaps->setInt32(tag.c_str(), (required == 1) || (optional == 0)); + mCurrentInfo->addFeature(name, (required == 1) || (optional == 0)); return OK; } ssize_t MediaCodecList::findCodecByName(const char *name) const { for (size_t i = 0; i < mCodecInfos.size(); ++i) { - const CodecInfo &info = mCodecInfos.itemAt(i); + const MediaCodecInfo &info = *mCodecInfos.itemAt(i).get(); if (info.mName == name) { return i; @@ -792,121 +805,4 @@ size_t MediaCodecList::countCodecs() const { return mCodecInfos.size(); } -const char *MediaCodecList::getCodecName(size_t index) const { - if (index >= mCodecInfos.size()) { - return NULL; - } - - const CodecInfo &info = mCodecInfos.itemAt(index); - return info.mName.c_str(); -} - -bool MediaCodecList::isEncoder(size_t index) const { - if (index >= mCodecInfos.size()) { - return false; - } - - const CodecInfo &info = mCodecInfos.itemAt(index); - return info.mIsEncoder; -} - -bool MediaCodecList::codecHasQuirk( - size_t index, const char *quirkName) const { - if (index >= mCodecInfos.size()) { - return false; - } - - const CodecInfo &info = mCodecInfos.itemAt(index); - - if (info.mQuirks != 0) { - ssize_t index = mCodecQuirks.indexOfKey(quirkName); - if (index >= 0 && info.mQuirks & (1ul << mCodecQuirks.valueAt(index))) { - return true; - } - } - - return false; -} - -status_t MediaCodecList::getSupportedTypes( - size_t index, Vector *types) const { - types->clear(); - - if (index >= mCodecInfos.size()) { - return -ERANGE; - } - - const CodecInfo &info = mCodecInfos.itemAt(index); - - for (size_t i = 0; i < mTypes.size(); ++i) { - uint32_t typeMask = 1ul << mTypes.valueAt(i); - - if (info.mTypes & typeMask) { - types->push(mTypes.keyAt(i)); - } - } - - return OK; -} - -status_t MediaCodecList::getCodecCapabilities( - size_t index, const char *type, - Vector *profileLevels, - Vector *colorFormats, - uint32_t *flags, - sp *capabilities) const { - profileLevels->clear(); - colorFormats->clear(); - - if (index >= mCodecInfos.size()) { - return -ERANGE; - } - - const CodecInfo &info = mCodecInfos.itemAt(index); - - ssize_t typeIndex = mTypes.indexOfKey(type); - if (typeIndex < 0) { - return -EINVAL; - } - // essentially doing valueFor without the CHECK abort - typeIndex = mTypes.valueAt(typeIndex); - - OMXClient client; - status_t err = client.connect(); - if (err != OK) { - return err; - } - - CodecCapabilities caps; - err = QueryCodec( - client.interface(), - info.mName.c_str(), type, info.mIsEncoder, &caps); - - if (err != OK) { - return err; - } - - for (size_t i = 0; i < caps.mProfileLevels.size(); ++i) { - const CodecProfileLevel &src = caps.mProfileLevels.itemAt(i); - - ProfileLevel profileLevel; - profileLevel.mProfile = src.mProfile; - profileLevel.mLevel = src.mLevel; - profileLevels->push(profileLevel); - } - - for (size_t i = 0; i < caps.mColorFormats.size(); ++i) { - colorFormats->push(caps.mColorFormats.itemAt(i)); - } - - *flags = caps.mFlags; - - // TODO this check will be removed once JNI side is merged - if (capabilities != NULL) { - *capabilities = info.mCaps.valueFor(typeIndex); - } - - return OK; -} - } // namespace android diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 354712c..da590a2 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -197,7 +197,7 @@ void OMXCodec::findMatchingCodecs( Vector *matchingCodecs) { matchingCodecs->clear(); - const MediaCodecList *list = MediaCodecList::getInstance(); + const sp list = MediaCodecList::getInstance(); if (list == NULL) { return; } @@ -213,7 +213,9 @@ void OMXCodec::findMatchingCodecs( index = matchIndex + 1; - const char *componentName = list->getCodecName(matchIndex); + const sp info = list->getCodecInfo(matchIndex); + CHECK(info != NULL); + const char *componentName = info->getCodecName(); // If a specific codec is requested, skip the non-matching ones. if (matchComponentName && strcmp(componentName, matchComponentName)) { @@ -231,7 +233,7 @@ void OMXCodec::findMatchingCodecs( ssize_t index = matchingCodecs->add(); CodecNameAndQuirks *entry = &matchingCodecs->editItemAt(index); entry->mName = String8(componentName); - entry->mQuirks = getComponentQuirks(list, matchIndex); + entry->mQuirks = getComponentQuirks(info); ALOGV("matching '%s' quirks 0x%08x", entry->mName.string(), entry->mQuirks); @@ -245,18 +247,15 @@ void OMXCodec::findMatchingCodecs( // static uint32_t OMXCodec::getComponentQuirks( - const MediaCodecList *list, size_t index) { + const sp &info) { uint32_t quirks = 0; - if (list->codecHasQuirk( - index, "requires-allocate-on-input-ports")) { + if (info->hasQuirk("requires-allocate-on-input-ports")) { quirks |= kRequiresAllocateBufferOnInputPorts; } - if (list->codecHasQuirk( - index, "requires-allocate-on-output-ports")) { + if (info->hasQuirk("requires-allocate-on-output-ports")) { quirks |= kRequiresAllocateBufferOnOutputPorts; } - if (list->codecHasQuirk( - index, "output-buffers-are-unreadable")) { + if (info->hasQuirk("output-buffers-are-unreadable")) { quirks |= kOutputBuffersAreUnreadable; } @@ -265,8 +264,7 @@ uint32_t OMXCodec::getComponentQuirks( // static bool OMXCodec::findCodecQuirks(const char *componentName, uint32_t *quirks) { - const MediaCodecList *list = MediaCodecList::getInstance(); - + const sp list = MediaCodecList::getInstance(); if (list == NULL) { return false; } @@ -277,7 +275,9 @@ bool OMXCodec::findCodecQuirks(const char *componentName, uint32_t *quirks) { return false; } - *quirks = getComponentQuirks(list, index); + const sp info = list->getCodecInfo(index); + CHECK(info != NULL); + *quirks = getComponentQuirks(info); return true; } -- cgit v1.1