summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/MediaCodecList.cpp
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2012-02-29 15:47:17 -0800
committerAndreas Huber <andih@google.com>2012-03-01 11:30:10 -0800
commitafc16d667afa23f5aa00154ccad62f8c45cf5419 (patch)
treee7a7573397177303112c1809f0087b25c8a30397 /media/libstagefright/MediaCodecList.cpp
parentdf94a547d8036619d15975873a1ff5736b0f14fe (diff)
downloadframeworks_av-afc16d667afa23f5aa00154ccad62f8c45cf5419.zip
frameworks_av-afc16d667afa23f5aa00154ccad62f8c45cf5419.tar.gz
frameworks_av-afc16d667afa23f5aa00154ccad62f8c45cf5419.tar.bz2
Instead of hardcoding OMX component names in our code, support
a config file instead. Change-Id: I5835903ab9f1c4a22ccc605ca99ed966767adf57
Diffstat (limited to 'media/libstagefright/MediaCodecList.cpp')
-rw-r--r--media/libstagefright/MediaCodecList.cpp475
1 files changed, 475 insertions, 0 deletions
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
new file mode 100644
index 0000000..6b64e21
--- /dev/null
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -0,0 +1,475 @@
+/*
+ * Copyright 2012, 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 "MediaCodecList"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaCodecList.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+
+#include <expat.h>
+
+namespace android {
+
+static Mutex sInitMutex;
+
+// static
+MediaCodecList *MediaCodecList::sCodecList;
+
+// static
+const MediaCodecList *MediaCodecList::getInstance() {
+ Mutex::Autolock autoLock(sInitMutex);
+
+ if (sCodecList == NULL) {
+ sCodecList = new MediaCodecList;
+ }
+
+ return sCodecList->initCheck() == OK ? sCodecList : NULL;
+}
+
+MediaCodecList::MediaCodecList()
+ : mInitCheck(NO_INIT) {
+ FILE *file = fopen("/etc/media_codecs.xml", "r");
+
+ if (file == NULL) {
+ ALOGW("unable to open media codecs configuration xml file.");
+ return;
+ }
+
+ parseXMLFile(file);
+
+ if (mInitCheck == OK) {
+ // These are currently still used by the video editing suite.
+
+ addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm");
+ addMediaCodec(true /* encoder */, "AVCEncoder", "video/avc");
+
+ addMediaCodec(true /* encoder */, "M4vH263Encoder");
+ addType("video/3gpp");
+ addType("video/mp4v-es");
+ }
+
+#if 0
+ for (size_t i = 0; i < mCodecInfos.size(); ++i) {
+ const CodecInfo &info = mCodecInfos.itemAt(i);
+
+ AString line = info.mName;
+ line.append(" supports ");
+ for (size_t j = 0; j < mTypes.size(); ++j) {
+ uint32_t value = mTypes.valueAt(j);
+
+ if (info.mTypes & (1ul << value)) {
+ line.append(mTypes.keyAt(j));
+ line.append(" ");
+ }
+ }
+
+ ALOGI("%s", line.c_str());
+ }
+#endif
+
+ fclose(file);
+ file = NULL;
+}
+
+MediaCodecList::~MediaCodecList() {
+}
+
+status_t MediaCodecList::initCheck() const {
+ return mInitCheck;
+}
+
+void MediaCodecList::parseXMLFile(FILE *file) {
+ mInitCheck = OK;
+ mCurrentSection = SECTION_TOPLEVEL;
+ mDepth = 0;
+
+ XML_Parser parser = ::XML_ParserCreate(NULL);
+ CHECK(parser != NULL);
+
+ ::XML_SetUserData(parser, this);
+ ::XML_SetElementHandler(
+ parser, StartElementHandlerWrapper, EndElementHandlerWrapper);
+
+ const int BUFF_SIZE = 512;
+ while (mInitCheck == OK) {
+ void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
+ if (buff == NULL) {
+ ALOGE("failed to in call to XML_GetBuffer()");
+ mInitCheck = UNKNOWN_ERROR;
+ break;
+ }
+
+ int bytes_read = ::fread(buff, 1, BUFF_SIZE, file);
+ if (bytes_read < 0) {
+ ALOGE("failed in call to read");
+ mInitCheck = ERROR_IO;
+ break;
+ }
+
+ if (::XML_ParseBuffer(parser, bytes_read, bytes_read == 0)
+ != XML_STATUS_OK) {
+ mInitCheck = ERROR_MALFORMED;
+ break;
+ }
+
+ if (bytes_read == 0) {
+ break;
+ }
+ }
+
+ ::XML_ParserFree(parser);
+
+ if (mInitCheck == OK) {
+ for (size_t i = mCodecInfos.size(); i-- > 0;) {
+ CodecInfo *info = &mCodecInfos.editItemAt(i);
+
+ if (info->mTypes == 0) {
+ // No types supported by this component???
+
+ ALOGW("Component %s does not support any type of media?",
+ info->mName.c_str());
+
+ mCodecInfos.removeAt(i);
+ }
+ }
+ }
+
+ if (mInitCheck != OK) {
+ mCodecInfos.clear();
+ mCodecQuirks.clear();
+ }
+}
+
+// static
+void MediaCodecList::StartElementHandlerWrapper(
+ void *me, const char *name, const char **attrs) {
+ static_cast<MediaCodecList *>(me)->startElementHandler(name, attrs);
+}
+
+// static
+void MediaCodecList::EndElementHandlerWrapper(void *me, const char *name) {
+ static_cast<MediaCodecList *>(me)->endElementHandler(name);
+}
+
+void MediaCodecList::startElementHandler(
+ const char *name, const char **attrs) {
+ if (mInitCheck != OK) {
+ return;
+ }
+
+ switch (mCurrentSection) {
+ case SECTION_TOPLEVEL:
+ {
+ if (!strcmp(name, "Decoders")) {
+ mCurrentSection = SECTION_DECODERS;
+ } else if (!strcmp(name, "Encoders")) {
+ mCurrentSection = SECTION_ENCODERS;
+ }
+ break;
+ }
+
+ case SECTION_DECODERS:
+ {
+ if (!strcmp(name, "MediaCodec")) {
+ mInitCheck =
+ addMediaCodecFromAttributes(false /* encoder */, attrs);
+
+ mCurrentSection = SECTION_DECODER;
+ }
+ break;
+ }
+
+ case SECTION_ENCODERS:
+ {
+ if (!strcmp(name, "MediaCodec")) {
+ mInitCheck =
+ addMediaCodecFromAttributes(true /* encoder */, attrs);
+
+ mCurrentSection = SECTION_ENCODER;
+ }
+ break;
+ }
+
+ case SECTION_DECODER:
+ case SECTION_ENCODER:
+ {
+ if (!strcmp(name, "Quirk")) {
+ mInitCheck = addQuirk(attrs);
+ } else if (!strcmp(name, "Type")) {
+ mInitCheck = addTypeFromAttributes(attrs);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ ++mDepth;
+}
+
+void MediaCodecList::endElementHandler(const char *name) {
+ if (mInitCheck != OK) {
+ return;
+ }
+
+ switch (mCurrentSection) {
+ case SECTION_DECODERS:
+ {
+ if (!strcmp(name, "Decoders")) {
+ mCurrentSection = SECTION_TOPLEVEL;
+ }
+ break;
+ }
+
+ case SECTION_ENCODERS:
+ {
+ if (!strcmp(name, "Encoders")) {
+ mCurrentSection = SECTION_TOPLEVEL;
+ }
+ break;
+ }
+
+ case SECTION_DECODER:
+ {
+ if (!strcmp(name, "MediaCodec")) {
+ mCurrentSection = SECTION_DECODERS;
+ }
+ break;
+ }
+
+ case SECTION_ENCODER:
+ {
+ if (!strcmp(name, "MediaCodec")) {
+ mCurrentSection = SECTION_ENCODERS;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ --mDepth;
+}
+
+status_t MediaCodecList::addMediaCodecFromAttributes(
+ bool encoder, const char **attrs) {
+ const char *name = NULL;
+ const char *type = 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 {
+ return -EINVAL;
+ }
+
+ ++i;
+ }
+
+ if (name == NULL) {
+ return -EINVAL;
+ }
+
+ addMediaCodec(encoder, name, type);
+
+ return OK;
+}
+
+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->mTypes = 0;
+ info->mQuirks = 0;
+
+ if (type != NULL) {
+ addType(type);
+ }
+}
+
+status_t MediaCodecList::addQuirk(const char **attrs) {
+ const char *name = 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 {
+ return -EINVAL;
+ }
+
+ ++i;
+ }
+
+ if (name == NULL) {
+ 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;
+
+ return OK;
+}
+
+status_t MediaCodecList::addTypeFromAttributes(const char **attrs) {
+ const char *name = 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 {
+ return -EINVAL;
+ }
+
+ ++i;
+ }
+
+ if (name == NULL) {
+ 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;
+}
+
+ssize_t MediaCodecList::findCodecByType(
+ const char *type, bool encoder, size_t startIndex) const {
+ ssize_t typeIndex = mTypes.indexOfKey(type);
+
+ if (typeIndex < 0) {
+ return -ENOENT;
+ }
+
+ uint32_t typeMask = 1ul << mTypes.valueAt(typeIndex);
+
+ while (startIndex < mCodecInfos.size()) {
+ const CodecInfo &info = mCodecInfos.itemAt(startIndex);
+
+ if (info.mIsEncoder == encoder && (info.mTypes & typeMask)) {
+ return startIndex;
+ }
+
+ ++startIndex;
+ }
+
+ return -ENOENT;
+}
+
+ssize_t MediaCodecList::findCodecByName(const char *name) const {
+ for (size_t i = 0; i < mCodecInfos.size(); ++i) {
+ const CodecInfo &info = mCodecInfos.itemAt(i);
+
+ if (info.mName == name) {
+ return i;
+ }
+ }
+
+ return -ENOENT;
+}
+
+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::codecHasQuirk(
+ size_t index, const char *quirkName) const {
+ if (index >= mCodecInfos.size()) {
+ return NULL;
+ }
+
+ 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;
+}
+
+} // namespace android