summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/MediaCodecList.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/MediaCodecList.cpp')
-rw-r--r--media/libstagefright/MediaCodecList.cpp259
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