diff options
author | Andreas Huber <andih@google.com> | 2012-02-29 15:47:17 -0800 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2012-03-01 11:30:10 -0800 |
commit | 3d3864fff49715fe528b6c4a919ef75f4c2f90e2 (patch) | |
tree | e6726a13b58caaffe241aa3be8c727d5e2d2547d /media/libstagefright | |
parent | ae9029938aa108153bf48157b69459362eca124e (diff) | |
download | frameworks_base-3d3864fff49715fe528b6c4a919ef75f4c2f90e2.zip frameworks_base-3d3864fff49715fe528b6c4a919ef75f4c2f90e2.tar.gz frameworks_base-3d3864fff49715fe528b6c4a919ef75f4c2f90e2.tar.bz2 |
Instead of hardcoding OMX component names in our code, support
a config file instead.
Change-Id: I5835903ab9f1c4a22ccc605ca99ed966767adf57
Diffstat (limited to 'media/libstagefright')
-rw-r--r-- | media/libstagefright/ACodec.cpp | 31 | ||||
-rw-r--r-- | media/libstagefright/Android.mk | 31 | ||||
-rw-r--r-- | media/libstagefright/MediaCodecList.cpp | 475 | ||||
-rwxr-xr-x | media/libstagefright/OMXCodec.cpp | 270 |
4 files changed, 580 insertions, 227 deletions
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 9a9d094..09e4e45 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -26,6 +26,7 @@ #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> @@ -328,7 +329,8 @@ private: //////////////////////////////////////////////////////////////////////////////// ACodec::ACodec() - : mNode(NULL), + : mQuirks(0), + mNode(NULL), mSentFormat(false), mIsEncoder(false), mShutdownInProgress(false) { @@ -427,16 +429,12 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { 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 { @@ -2588,12 +2586,19 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { 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)); @@ -2607,7 +2612,8 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { encoder, // createEncoder NULL, // matchComponentName 0, // flags - &matchingCodecs); + &matchingCodecs, + &matchingCodecQuirks); } sp<CodecObserver> observer = new CodecObserver; @@ -2616,6 +2622,7 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { 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); @@ -2646,6 +2653,7 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { observer->setNotificationMessage(notify); mCodec->mComponentName = componentName; + mCodec->mQuirks = quirks; mCodec->mOMX = omx; mCodec->mNode = node; @@ -2692,6 +2700,7 @@ void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) { mCodec->mNativeWindow.clear(); mCodec->mNode = NULL; mCodec->mOMX.clear(); + mCodec->mQuirks = 0; mCodec->mComponentName.clear(); mCodec->changeState(mCodec->mUninitializedState); diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 95bcada..21d6866 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -30,6 +30,7 @@ LOCAL_SRC_FILES:= \ MediaBuffer.cpp \ MediaBufferGroup.cpp \ MediaCodec.cpp \ + MediaCodecList.cpp \ MediaDefs.cpp \ MediaExtractor.cpp \ MediaSource.cpp \ @@ -59,31 +60,33 @@ LOCAL_C_INCLUDES:= \ $(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 \ 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 diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 1325462..b471837 100755 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -33,6 +33,7 @@ #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> @@ -57,11 +58,6 @@ const static int64_t kBufferFilledEventTimeOutNs = 3000000000LL; // 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); \ @@ -96,83 +92,8 @@ static sp<MediaSource> InstantiateSoftwareEncoder( 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__) @@ -207,22 +128,6 @@ private: 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); @@ -278,119 +183,36 @@ static int CompareSoftwareCodecsFirst( } // 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; @@ -405,6 +227,10 @@ void OMXCodec::findMatchingCodecs( (!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) { matchingCodecs->push(String8(componentName)); + + if (matchingCodecQuirks) { + matchingCodecQuirks->push(getComponentQuirks(list, matchIndex)); + } } } @@ -414,6 +240,45 @@ void OMXCodec::findMatchingCodecs( } // 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, @@ -435,8 +300,10 @@ sp<MediaSource> OMXCodec::Create( 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; @@ -447,6 +314,7 @@ sp<MediaSource> OMXCodec::Create( 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; @@ -470,8 +338,6 @@ sp<MediaSource> OMXCodec::Create( ALOGV("Attempting to allocate OMX node '%s'", componentName); - uint32_t quirks = getComponentQuirks(componentNameBase, createEncoder); - if (!createEncoder && (quirks & kOutputBuffersAreUnreadable) && (flags & kClientNeedsFramebuffer)) { |