diff options
Diffstat (limited to 'media/libstagefright/MediaCodecList.cpp')
-rw-r--r-- | media/libstagefright/MediaCodecList.cpp | 259 |
1 files changed, 231 insertions, 28 deletions
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index cf6e937..26798ae 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -18,6 +18,8 @@ #define LOG_TAG "MediaCodecList" #include <utils/Log.h> +#include "MediaCodecListOverrides.h" + #include <binder/IServiceManager.h> #include <media/IMediaCodecList.h> @@ -31,6 +33,7 @@ #include <media/stagefright/OMXClient.h> #include <media/stagefright/OMXCodec.h> +#include <sys/stat.h> #include <utils/threads.h> #include <libexpat/expat.h> @@ -41,21 +44,58 @@ static Mutex sInitMutex; static MediaCodecList *gCodecList = NULL; +static const char *kProfilingResults = "/data/misc/media/media_codecs_profiling_results.xml"; + +static bool parseBoolean(const char *s) { + if (!strcasecmp(s, "true") || !strcasecmp(s, "yes") || !strcasecmp(s, "y")) { + return true; + } + char *end; + unsigned long res = strtoul(s, &end, 10); + return *s != '\0' && *end == '\0' && res > 0; +} + // static sp<IMediaCodecList> MediaCodecList::sCodecList; // static sp<IMediaCodecList> MediaCodecList::getLocalInstance() { - Mutex::Autolock autoLock(sInitMutex); - - if (gCodecList == NULL) { - gCodecList = new MediaCodecList; - if (gCodecList->initCheck() == OK) { - sCodecList = gCodecList; + bool profilingNeeded = false; + KeyedVector<AString, CodecSettings> updates; + Vector<sp<MediaCodecInfo>> infos; + + { + Mutex::Autolock autoLock(sInitMutex); + + if (gCodecList == NULL) { + gCodecList = new MediaCodecList; + if (gCodecList->initCheck() == OK) { + sCodecList = gCodecList; + + struct stat s; + if (stat(kProfilingResults, &s) == -1) { + // profiling results doesn't existed + profilingNeeded = true; + for (size_t i = 0; i < gCodecList->countCodecs(); ++i) { + infos.push_back(gCodecList->getCodecInfo(i)); + } + } + } } } - return sCodecList; + if (profilingNeeded) { + profileCodecs(infos, &updates); + } + + { + Mutex::Autolock autoLock(sInitMutex); + if (updates.size() > 0) { + gCodecList->updateDetailsForMultipleCodecs(updates); + } + + return sCodecList; + } } static Mutex sRemoteInitMutex; @@ -94,11 +134,27 @@ sp<IMediaCodecList> MediaCodecList::getInstance() { } MediaCodecList::MediaCodecList() - : mInitCheck(NO_INIT) { + : mInitCheck(NO_INIT), + mUpdate(false), + mGlobalSettings(new AMessage()) { parseTopLevelXMLFile("/etc/media_codecs.xml"); + parseTopLevelXMLFile(kProfilingResults, true/* ignore_errors */); +} + +void MediaCodecList::updateDetailsForMultipleCodecs( + const KeyedVector<AString, CodecSettings>& updates) { + if (updates.size() == 0) { + return; + } + + exportResultsToXML(kProfilingResults, updates); + + for (size_t i = 0; i < updates.size(); ++i) { + applyCodecSettings(updates.keyAt(i), updates.valueAt(i), &mCodecInfos); + } } -void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml) { +void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml, bool ignore_errors) { // get href_base char *href_base_end = strrchr(codecs_xml, '/'); if (href_base_end != NULL) { @@ -119,13 +175,16 @@ void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml) { mOMX.clear(); if (mInitCheck != OK) { + if (ignore_errors) { + mInitCheck = OK; + return; + } mCodecInfos.clear(); return; } for (size_t i = mCodecInfos.size(); i-- > 0;) { const MediaCodecInfo &info = *mCodecInfos.itemAt(i).get(); - if (info.mCaps.size() == 0) { // No types supported by this component??? ALOGW("Component %s does not support any type of media?", @@ -169,6 +228,16 @@ void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml) { } ALOGV(" levels=[%s]", nice.c_str()); } + { + AString quirks; + for (size_t ix = 0; ix < info.mQuirks.size(); ix++) { + if (ix > 0) { + quirks.append(", "); + } + quirks.append(info.mQuirks[ix]); + } + ALOGV(" quirks=[%s]", quirks.c_str()); + } } #endif } @@ -328,6 +397,16 @@ void MediaCodecList::startElementHandler( mCurrentSection = SECTION_DECODERS; } else if (!strcmp(name, "Encoders")) { mCurrentSection = SECTION_ENCODERS; + } else if (!strcmp(name, "Settings")) { + mCurrentSection = SECTION_SETTINGS; + } + break; + } + + case SECTION_SETTINGS: + { + if (!strcmp(name, "Setting")) { + mInitCheck = addSettingFromAttributes(attrs); } break; } @@ -397,6 +476,14 @@ void MediaCodecList::endElementHandler(const char *name) { } switch (mCurrentSection) { + case SECTION_SETTINGS: + { + if (!strcmp(name, "Settings")) { + mCurrentSection = SECTION_TOPLEVEL; + } + break; + } + case SECTION_DECODERS: { if (!strcmp(name, "Decoders")) { @@ -462,10 +549,10 @@ void MediaCodecList::endElementHandler(const char *name) { --mDepth; } -status_t MediaCodecList::addMediaCodecFromAttributes( - bool encoder, const char **attrs) { +status_t MediaCodecList::addSettingFromAttributes(const char **attrs) { const char *name = NULL; - const char *type = NULL; + const char *value = NULL; + const char *update = NULL; size_t i = 0; while (attrs[i] != NULL) { @@ -475,11 +562,17 @@ status_t MediaCodecList::addMediaCodecFromAttributes( } name = attrs[i + 1]; ++i; - } else if (!strcmp(attrs[i], "type")) { + } else if (!strcmp(attrs[i], "value")) { if (attrs[i + 1] == NULL) { return -EINVAL; } - type = attrs[i + 1]; + value = attrs[i + 1]; + ++i; + } else if (!strcmp(attrs[i], "update")) { + if (attrs[i + 1] == NULL) { + return -EINVAL; + } + update = attrs[i + 1]; ++i; } else { return -EINVAL; @@ -488,10 +581,34 @@ status_t MediaCodecList::addMediaCodecFromAttributes( ++i; } - if (name == NULL) { + if (name == NULL || value == NULL) { return -EINVAL; } + mUpdate = (update != NULL) && parseBoolean(update); + if (mUpdate != mGlobalSettings->contains(name)) { + return -EINVAL; + } + + mGlobalSettings->setString(name, value); + return OK; +} + +void MediaCodecList::setCurrentCodecInfo(bool encoder, const char *name, const char *type) { + for (size_t i = 0; i < mCodecInfos.size(); ++i) { + if (AString(name) == mCodecInfos[i]->getCodecName()) { + if (mCodecInfos[i]->getCapabilitiesFor(type) == NULL) { + ALOGW("Overrides with an unexpected mime %s", type); + // Create a new MediaCodecInfo (but don't add it to mCodecInfos) to hold the + // overrides we don't want. + mCurrentInfo = new MediaCodecInfo(name, encoder, type); + } else { + mCurrentInfo = mCodecInfos.editItemAt(i); + mCurrentInfo->updateMime(type); // to set the current cap + } + return; + } + } mCurrentInfo = new MediaCodecInfo(name, encoder, type); // The next step involves trying to load the codec, which may // fail. Only list the codec if this succeeds. @@ -500,6 +617,78 @@ status_t MediaCodecList::addMediaCodecFromAttributes( if (initializeCapabilities(type) == OK) { mCodecInfos.push_back(mCurrentInfo); } +} + +status_t MediaCodecList::addMediaCodecFromAttributes( + bool encoder, const char **attrs) { + const char *name = NULL; + const char *type = NULL; + const char *update = NULL; + + size_t i = 0; + while (attrs[i] != NULL) { + if (!strcmp(attrs[i], "name")) { + if (attrs[i + 1] == NULL) { + return -EINVAL; + } + name = attrs[i + 1]; + ++i; + } else if (!strcmp(attrs[i], "type")) { + if (attrs[i + 1] == NULL) { + return -EINVAL; + } + type = attrs[i + 1]; + ++i; + } else if (!strcmp(attrs[i], "update")) { + if (attrs[i + 1] == NULL) { + return -EINVAL; + } + update = attrs[i + 1]; + ++i; + } else { + return -EINVAL; + } + + ++i; + } + + if (name == NULL) { + return -EINVAL; + } + + mUpdate = (update != NULL) && parseBoolean(update); + ssize_t index = -1; + for (size_t i = 0; i < mCodecInfos.size(); ++i) { + if (AString(name) == mCodecInfos[i]->getCodecName()) { + index = i; + } + } + if (mUpdate != (index >= 0)) { + return -EINVAL; + } + + if (index >= 0) { + // existing codec + mCurrentInfo = mCodecInfos.editItemAt(index); + if (type != NULL) { + // existing type + if (mCodecInfos[index]->getCapabilitiesFor(type) == NULL) { + return -EINVAL; + } + mCurrentInfo->updateMime(type); + } + } else { + // new codec + mCurrentInfo = new MediaCodecInfo(name, encoder, type); + // The next step involves trying to load the codec, which may + // fail. Only list the codec if this succeeds. + // However, keep mCurrentInfo object around until parsing + // of full codec info is completed. + if (initializeCapabilities(type) == OK) { + mCodecInfos.push_back(mCurrentInfo); + } + } + return OK; } @@ -553,6 +742,7 @@ status_t MediaCodecList::addQuirk(const char **attrs) { status_t MediaCodecList::addTypeFromAttributes(const char **attrs) { const char *name = NULL; + const char *update = NULL; size_t i = 0; while (attrs[i] != NULL) { @@ -562,6 +752,12 @@ status_t MediaCodecList::addTypeFromAttributes(const char **attrs) { } name = attrs[i + 1]; ++i; + } else if (!strcmp(attrs[i], "update")) { + if (attrs[i + 1] == NULL) { + return -EINVAL; + } + update = attrs[i + 1]; + ++i; } else { return -EINVAL; } @@ -573,14 +769,25 @@ status_t MediaCodecList::addTypeFromAttributes(const char **attrs) { return -EINVAL; } - status_t ret = mCurrentInfo->addMime(name); + bool isExistingType = (mCurrentInfo->getCapabilitiesFor(name) != NULL); + if (mUpdate != isExistingType) { + return -EINVAL; + } + + status_t ret; + if (mUpdate) { + ret = mCurrentInfo->updateMime(name); + } else { + ret = mCurrentInfo->addMime(name); + } + if (ret != OK) { return ret; } // The next step involves trying to load the codec, which may // fail. Handle this gracefully (by not reporting such mime). - if (initializeCapabilities(name) != OK) { + if (!mUpdate && initializeCapabilities(name) != OK) { mCurrentInfo->removeMime(name); } return OK; @@ -758,7 +965,8 @@ status_t MediaCodecList::addLimit(const char **attrs) { return limitFoundMissingAttr(name, "ranges", found); } else if (msg->contains("scale")) { return limitFoundMissingAttr(name, "scale"); - } else if ((name == "alignment" || name == "block-size") ^ + } else if ((name == "alignment" || name == "block-size" + || name == "max-supported-instances") ^ (found = msg->findString("value", &value))) { return limitFoundMissingAttr(name, "value", found); } @@ -780,15 +988,6 @@ status_t MediaCodecList::addLimit(const char **attrs) { return OK; } -static bool parseBoolean(const char *s) { - if (!strcasecmp(s, "true") || !strcasecmp(s, "yes") || !strcasecmp(s, "y")) { - return true; - } - char *end; - unsigned long res = strtoul(s, &end, 10); - return *s != '\0' && *end == '\0' && res > 0; -} - status_t MediaCodecList::addFeature(const char **attrs) { size_t i = 0; const char *name = NULL; @@ -860,4 +1059,8 @@ size_t MediaCodecList::countCodecs() const { return mCodecInfos.size(); } +const sp<AMessage> MediaCodecList::getGlobalSettings() const { + return mGlobalSettings; +} + } // namespace android |