a config file instead.
Change-Id: I5835903ab9f1c4a22ccc605ca99ed966767adf57
sp<FlushingState> mFlushingState;
AString mComponentName;
+ uint32_t mQuirks;
sp<IOMX> mOMX;
IOMX::node_id mNode;
sp<MemoryDealer> mDealer[2];
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef MEDIA_CODEC_LIST_H_
+
+#define MEDIA_CODEC_LIST_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AString.h>
+
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+struct MediaCodecList {
+ static const MediaCodecList *getInstance();
+
+ ssize_t findCodecByType(
+ const char *type, bool encoder, size_t startIndex = 0) const;
+
+ ssize_t findCodecByName(const char *name) const;
+
+ const char *getCodecName(size_t index) const;
+ bool codecHasQuirk(size_t index, const char *quirkName) const;
+
+private:
+ enum Section {
+ SECTION_TOPLEVEL,
+ SECTION_DECODERS,
+ SECTION_DECODER,
+ SECTION_ENCODERS,
+ SECTION_ENCODER,
+ };
+
+ struct CodecInfo {
+ AString mName;
+ bool mIsEncoder;
+ uint32_t mTypes;
+ uint32_t mQuirks;
+ };
+
+ static MediaCodecList *sCodecList;
+
+ status_t mInitCheck;
+ Section mCurrentSection;
+ int32_t mDepth;
+
+ Vector<CodecInfo> mCodecInfos;
+ KeyedVector<AString, size_t> mCodecQuirks;
+ KeyedVector<AString, size_t> mTypes;
+
+ MediaCodecList();
+ ~MediaCodecList();
+
+ status_t initCheck() const;
+ void parseXMLFile(FILE *file);
+
+ static void StartElementHandlerWrapper(
+ void *me, const char *name, const char **attrs);
+
+ static void EndElementHandlerWrapper(void *me, const char *name);
+
+ void startElementHandler(const char *name, const char **attrs);
+ void endElementHandler(const char *name);
+
+ status_t addMediaCodecFromAttributes(bool encoder, const char **attrs);
+ void addMediaCodec(bool encoder, const char *name, const char *type = NULL);
+
+ status_t addQuirk(const char **attrs);
+ status_t addTypeFromAttributes(const char **attrs);
+ void addType(const char *name);
+
+ DISALLOW_EVIL_CONSTRUCTORS(MediaCodecList);
+};
+
+} // namespace android
+
+#endif // MEDIA_CODEC_LIST_H_
+
namespace android {
+struct MediaCodecList;
class MemoryDealer;
struct OMXCodecObserver;
struct CodecProfileLevel;
// from MediaBufferObserver
virtual void signalBufferReturned(MediaBuffer *buffer);
+ enum Quirks {
+ kNeedsFlushBeforeDisable = 1,
+ kWantsNALFragments = 2,
+ kRequiresLoadedToIdleAfterAllocation = 4,
+ kRequiresAllocateBufferOnInputPorts = 8,
+ kRequiresFlushCompleteEmulation = 16,
+ kRequiresAllocateBufferOnOutputPorts = 32,
+ kRequiresFlushBeforeShutdown = 64,
+ kDefersOutputBufferAllocation = 128,
+ kDecoderLiesAboutNumberOfChannels = 256,
+ kInputBufferSizesAreBogus = 512,
+ kSupportsMultipleFramesPerInputBuffer = 1024,
+ kAvoidMemcopyInputRecordingFrames = 2048,
+ kRequiresLargerEncoderOutputBuffer = 4096,
+ kOutputBuffersAreUnreadable = 8192,
+ };
+
// for use by ACodec
static void findMatchingCodecs(
const char *mime,
bool createEncoder, const char *matchComponentName,
uint32_t flags,
- Vector<String8> *matchingCodecs);
+ Vector<String8> *matchingCodecs,
+ Vector<uint32_t> *matchingCodecQuirks = NULL);
+
+ static uint32_t getComponentQuirks(
+ const MediaCodecList *list, size_t index);
+
+ static bool findCodecQuirks(const char *componentName, uint32_t *quirks);
protected:
virtual ~OMXCodec();
SHUTTING_DOWN,
};
- enum Quirks {
- kNeedsFlushBeforeDisable = 1,
- kWantsNALFragments = 2,
- kRequiresLoadedToIdleAfterAllocation = 4,
- kRequiresAllocateBufferOnInputPorts = 8,
- kRequiresFlushCompleteEmulation = 16,
- kRequiresAllocateBufferOnOutputPorts = 32,
- kRequiresFlushBeforeShutdown = 64,
- kDefersOutputBufferAllocation = 128,
- kDecoderLiesAboutNumberOfChannels = 256,
- kInputBufferSizesAreBogus = 512,
- kSupportsMultipleFramesPerInputBuffer = 1024,
- kAvoidMemcopyInputRecordingFrames = 2048,
- kRequiresLargerEncoderOutputBuffer = 4096,
- kOutputBuffersAreUnreadable = 8192,
- };
-
enum BufferStatus {
OWNED_BY_US,
OWNED_BY_COMPONENT,
status_t configureCodec(const sp<MetaData> &meta);
- static uint32_t getComponentQuirks(
- const char *componentName, bool isEncoder);
-
void restorePatchedDataPointer(BufferInfo *info);
status_t applyRotation();
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/NativeWindowWrapper.h>
#include <media/stagefright/OMXClient.h>
////////////////////////////////////////////////////////////////////////////////
ACodec::ACodec()
- : mNode(NULL),
+ : mQuirks(0),
+ mNode(NULL),
mSentFormat(false),
mIsEncoder(false),
mShutdownInProgress(false) {
IOMX::buffer_id buffer;
- if (!strncasecmp(
- mComponentName.c_str(), "OMX.TI.DUCATI1.VIDEO.", 21)) {
- if (portIndex == kPortIndexInput && i == 0) {
- // Only log this warning once per allocation round.
-
- ALOGW("OMX.TI.DUCATI1.VIDEO.* require the use of "
- "OMX_AllocateBuffer instead of the preferred "
- "OMX_UseBuffer. Vendor must fix this.");
- }
+ uint32_t requiresAllocateBufferBit =
+ (portIndex == kPortIndexInput)
+ ? OMXCodec::kRequiresAllocateBufferOnInputPorts
+ : OMXCodec::kRequiresAllocateBufferOnOutputPorts;
+ if (mQuirks & requiresAllocateBufferBit) {
err = mOMX->allocateBufferWithBackup(
mNode, portIndex, mem, &buffer);
} else {
sp<IOMX> omx = client.interface();
Vector<String8> matchingCodecs;
+ Vector<uint32_t> matchingCodecQuirks;
AString mime;
AString componentName;
+ uint32_t quirks;
if (msg->findString("componentName", &componentName)) {
matchingCodecs.push_back(String8(componentName.c_str()));
+
+ if (!OMXCodec::findCodecQuirks(componentName.c_str(), &quirks)) {
+ quirks = 0;
+ }
+ matchingCodecQuirks.push_back(quirks);
} else {
CHECK(msg->findString("mime", &mime));
encoder, // createEncoder
NULL, // matchComponentName
0, // flags
- &matchingCodecs);
+ &matchingCodecs,
+ &matchingCodecQuirks);
}
sp<CodecObserver> observer = new CodecObserver;
for (size_t matchIndex = 0; matchIndex < matchingCodecs.size();
++matchIndex) {
componentName = matchingCodecs.itemAt(matchIndex).string();
+ quirks = matchingCodecQuirks.itemAt(matchIndex);
pid_t tid = androidGetTid();
int prevPriority = androidGetThreadPriority(tid);
observer->setNotificationMessage(notify);
mCodec->mComponentName = componentName;
+ mCodec->mQuirks = quirks;
mCodec->mOMX = omx;
mCodec->mNode = node;
mCodec->mNativeWindow.clear();
mCodec->mNode = NULL;
mCodec->mOMX.clear();
+ mCodec->mQuirks = 0;
mCodec->mComponentName.clear();
mCodec->changeState(mCodec->mUninitializedState);
MediaBuffer.cpp \
MediaBufferGroup.cpp \
MediaCodec.cpp \
+ MediaCodecList.cpp \
MediaDefs.cpp \
MediaExtractor.cpp \
MediaSource.cpp \
$(JNI_H_INCLUDE) \
$(TOP)/frameworks/base/include/media/stagefright/openmax \
$(TOP)/frameworks/base/include/media/stagefright/timedtext \
+ $(TOP)/external/expat/lib \
$(TOP)/external/flac/include \
$(TOP)/external/tremolo \
$(TOP)/external/openssl/include \
LOCAL_SHARED_LIBRARIES := \
libbinder \
- libmedia \
- libutils \
- libcutils \
- libui \
- libsonivox \
- libvorbisidec \
- libstagefright_yuv \
libcamera_client \
- libdrmframework \
+ libchromium_net \
libcrypto \
- libssl \
+ libcutils \
+ libdl \
+ libdrmframework \
+ libexpat \
libgui \
- libstagefright_omx \
- liblog \
- libicuuc \
libicui18n \
+ libicuuc \
+ liblog \
+ libmedia \
+ libsonivox \
+ libssl \
+ libstagefright_omx \
+ libstagefright_yuv \
+ libui \
+ libutils \
+ libvorbisidec \
libz \
- libdl \
- libchromium_net \
LOCAL_STATIC_LIBRARIES := \
libstagefright_color_conversion \
--- /dev/null
+/*
+ * 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
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXCodec.h>
// component in question is buggy or not.
const static uint32_t kMaxColorFormatSupported = 1000;
-struct CodecInfo {
- const char *mime;
- const char *codec;
-};
-
#define FACTORY_CREATE_ENCODER(name) \
static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaData> &meta) { \
return new name(source, meta); \
return NULL;
}
+#undef FACTORY_CREATE_ENCODER
#undef FACTORY_REF
-#undef FACTORY_CREATE
-
-static const CodecInfo kDecoderInfo[] = {
- { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
-// { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
- { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.google.mp3.decoder" },
- { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II, "OMX.Nvidia.mp2.decoder" },
-// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
-// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amr.decoder" },
- { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.decoder" },
-// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amrwb.decoder" },
- { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
- { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.google.amrwb.decoder" },
-// { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.Nvidia.aac.decoder" },
- { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
- { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.google.aac.decoder" },
- { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "OMX.google.g711.alaw.decoder" },
- { MEDIA_MIMETYPE_AUDIO_G711_MLAW, "OMX.google.g711.mlaw.decoder" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.DECODER" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.decode" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.decoder.mpeg4" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Decoder" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.google.mpeg4.decoder" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.DUCATI1.VIDEO.DECODER" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.decode" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.decoder.h263" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Decoder" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.google.h263.decoder" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.DUCATI1.VIDEO.DECODER" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.Nvidia.h264.decode" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.decoder.avc" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.SEC.AVC.Decoder" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.google.h264.decoder" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.google.avc.decoder" },
- { MEDIA_MIMETYPE_AUDIO_VORBIS, "OMX.google.vorbis.decoder" },
- { MEDIA_MIMETYPE_VIDEO_VPX, "OMX.google.vpx.decoder" },
- { MEDIA_MIMETYPE_VIDEO_MPEG2, "OMX.Nvidia.mpeg2v.decode" },
-};
-
-static const CodecInfo kEncoderInfo[] = {
- { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.encode" },
- { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.encoder" },
- { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.encode" },
- { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.google.amrwb.encoder" },
- { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
- { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.google.aac.encoder" },
- { MEDIA_MIMETYPE_AUDIO_AAC, "AACEncoder" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.MPEG4E" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.encoder.mpeg4" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.encoder" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Encoder" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Encoder" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.DUCATI1.VIDEO.MPEG4E" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.encoder.h263" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.encoder" },
- { MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Encoder" },
- { MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Encoder" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.DUCATI1.VIDEO.H264E" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.encoder.avc" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.Nvidia.h264.encoder" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.SEC.AVC.Encoder" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "AVCEncoder" },
-};
-
-#undef OPTIONAL
#define CODEC_LOGI(x, ...) ALOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
#define CODEC_LOGV(x, ...) ALOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
OMXCodecObserver &operator=(const OMXCodecObserver &);
};
-static const char *GetCodec(const CodecInfo *info, size_t numInfos,
- const char *mime, int index) {
- CHECK(index >= 0);
- for(size_t i = 0; i < numInfos; ++i) {
- if (!strcasecmp(mime, info[i].mime)) {
- if (index == 0) {
- return info[i].codec;
- }
-
- --index;
- }
- }
-
- return NULL;
-}
-
template<class T>
static void InitOMXParams(T *params) {
params->nSize = sizeof(T);
}
// static
-uint32_t OMXCodec::getComponentQuirks(
- const char *componentName, bool isEncoder) {
- uint32_t quirks = 0;
-
- if (!strcmp(componentName, "OMX.Nvidia.amr.decoder") ||
- !strcmp(componentName, "OMX.Nvidia.amrwb.decoder") ||
- !strcmp(componentName, "OMX.Nvidia.aac.decoder") ||
- !strcmp(componentName, "OMX.Nvidia.mp3.decoder")) {
- quirks |= kDecoderLiesAboutNumberOfChannels;
- }
-
- if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
- quirks |= kNeedsFlushBeforeDisable;
- quirks |= kDecoderLiesAboutNumberOfChannels;
- }
- if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
- quirks |= kNeedsFlushBeforeDisable;
- quirks |= kRequiresFlushCompleteEmulation;
- quirks |= kSupportsMultipleFramesPerInputBuffer;
- }
- if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
- quirks |= kRequiresLoadedToIdleAfterAllocation;
- quirks |= kRequiresAllocateBufferOnInputPorts;
- quirks |= kRequiresAllocateBufferOnOutputPorts;
- if (!strncmp(componentName, "OMX.qcom.video.encoder.avc", 26)) {
-
- // The AVC encoder advertises the size of output buffers
- // based on the input video resolution and assumes
- // the worst/least compression ratio is 0.5. It is found that
- // sometimes, the output buffer size is larger than
- // size advertised by the encoder.
- quirks |= kRequiresLargerEncoderOutputBuffer;
- }
- }
- if (!strncmp(componentName, "OMX.qcom.7x30.video.encoder.", 28)) {
- }
- if (!strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
- quirks |= kRequiresAllocateBufferOnOutputPorts;
- quirks |= kDefersOutputBufferAllocation;
- }
- if (!strncmp(componentName, "OMX.qcom.7x30.video.decoder.", 28)) {
- quirks |= kRequiresAllocateBufferOnInputPorts;
- quirks |= kRequiresAllocateBufferOnOutputPorts;
- quirks |= kDefersOutputBufferAllocation;
- }
-
- if (!strcmp(componentName, "OMX.TI.DUCATI1.VIDEO.DECODER")) {
- quirks |= kRequiresAllocateBufferOnInputPorts;
- quirks |= kRequiresAllocateBufferOnOutputPorts;
- }
-
- // FIXME:
- // Remove the quirks after the work is done.
- else if (!strcmp(componentName, "OMX.TI.DUCATI1.VIDEO.MPEG4E") ||
- !strcmp(componentName, "OMX.TI.DUCATI1.VIDEO.H264E")) {
-
- quirks |= kRequiresAllocateBufferOnInputPorts;
- quirks |= kRequiresAllocateBufferOnOutputPorts;
- }
- else if (!strncmp(componentName, "OMX.TI.", 7)) {
- // Apparently I must not use OMX_UseBuffer on either input or
- // output ports on any of the TI components or quote:
- // "(I) may have unexpected problem (sic) which can be timing related
- // and hard to reproduce."
-
- quirks |= kRequiresAllocateBufferOnInputPorts;
- quirks |= kRequiresAllocateBufferOnOutputPorts;
- if (!strncmp(componentName, "OMX.TI.Video.encoder", 20)) {
- quirks |= kAvoidMemcopyInputRecordingFrames;
- }
- }
-
- if (!strcmp(componentName, "OMX.TI.Video.Decoder")) {
- quirks |= kInputBufferSizesAreBogus;
- }
-
- if (!strncmp(componentName, "OMX.SEC.", 8) && !isEncoder) {
- // These output buffers contain no video data, just some
- // opaque information that allows the overlay to display their
- // contents.
- quirks |= kOutputBuffersAreUnreadable;
- }
-
- return quirks;
-}
-
-// static
void OMXCodec::findMatchingCodecs(
const char *mime,
bool createEncoder, const char *matchComponentName,
uint32_t flags,
- Vector<String8> *matchingCodecs) {
+ Vector<String8> *matchingCodecs,
+ Vector<uint32_t> *matchingCodecQuirks) {
matchingCodecs->clear();
- for (int index = 0;; ++index) {
- const char *componentName;
+ if (matchingCodecQuirks) {
+ matchingCodecQuirks->clear();
+ }
- if (createEncoder) {
- componentName = GetCodec(
- kEncoderInfo,
- sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
- mime, index);
- } else {
- componentName = GetCodec(
- kDecoderInfo,
- sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
- mime, index);
- }
+ const MediaCodecList *list = MediaCodecList::getInstance();
+ if (list == NULL) {
+ return;
+ }
- if (!componentName) {
+ size_t index = 0;
+ for (;;) {
+ ssize_t matchIndex =
+ list->findCodecByType(mime, createEncoder, index);
+
+ if (matchIndex < 0) {
break;
}
+ index = matchIndex + 1;
+
+ const char *componentName = list->getCodecName(matchIndex);
+
// If a specific codec is requested, skip the non-matching ones.
if (matchComponentName && strcmp(componentName, matchComponentName)) {
continue;
(!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) {
matchingCodecs->push(String8(componentName));
+
+ if (matchingCodecQuirks) {
+ matchingCodecQuirks->push(getComponentQuirks(list, matchIndex));
+ }
}
}
}
// static
+uint32_t OMXCodec::getComponentQuirks(
+ const MediaCodecList *list, size_t index) {
+ uint32_t quirks = 0;
+ if (list->codecHasQuirk(
+ index, "requires-allocate-on-input-ports")) {
+ quirks |= kRequiresAllocateBufferOnInputPorts;
+ }
+ if (list->codecHasQuirk(
+ index, "requires-allocate-on-output-ports")) {
+ quirks |= kRequiresAllocateBufferOnOutputPorts;
+ }
+ if (list->codecHasQuirk(
+ index, "output-buffers-are-unreadable")) {
+ quirks |= kOutputBuffersAreUnreadable;
+ }
+
+ return quirks;
+}
+
+// static
+bool OMXCodec::findCodecQuirks(const char *componentName, uint32_t *quirks) {
+ const MediaCodecList *list = MediaCodecList::getInstance();
+
+ if (list == NULL) {
+ return false;
+ }
+
+ ssize_t index = list->findCodecByName(componentName);
+
+ if (index < 0) {
+ return false;
+ }
+
+ *quirks = getComponentQuirks(list, index);
+
+ return true;
+}
+
+// static
sp<MediaSource> OMXCodec::Create(
const sp<IOMX> &omx,
const sp<MetaData> &meta, bool createEncoder,
CHECK(success);
Vector<String8> matchingCodecs;
+ Vector<uint32_t> matchingCodecQuirks;
findMatchingCodecs(
- mime, createEncoder, matchComponentName, flags, &matchingCodecs);
+ mime, createEncoder, matchComponentName, flags,
+ &matchingCodecs, &matchingCodecQuirks);
if (matchingCodecs.isEmpty()) {
return NULL;
for (size_t i = 0; i < matchingCodecs.size(); ++i) {
const char *componentNameBase = matchingCodecs[i].string();
+ uint32_t quirks = matchingCodecQuirks[i];
const char *componentName = componentNameBase;
AString tmp;
ALOGV("Attempting to allocate OMX node '%s'", componentName);
- uint32_t quirks = getComponentQuirks(componentNameBase, createEncoder);
-
if (!createEncoder
&& (quirks & kOutputBuffersAreUnreadable)
&& (flags & kClientNeedsFramebuffer)) {