Merge "Instead of hardcoding OMX component names in our code, support"

This commit is contained in:
Andreas Huber
2012-03-01 12:41:10 -08:00
committed by Android (Google) Code Review
8 changed files with 706 additions and 253 deletions

View File

@@ -118,6 +118,7 @@ private:
sp<FlushingState> mFlushingState;
AString mComponentName;
uint32_t mQuirks;
sp<IOMX> mOMX;
IOMX::node_id mNode;
sp<MemoryDealer> mDealer[2];

View File

@@ -0,0 +1,95 @@
/*
* 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_

View File

@@ -26,6 +26,7 @@
namespace android {
struct MediaCodecList;
class MemoryDealer;
struct OMXCodecObserver;
struct CodecProfileLevel;
@@ -82,12 +83,35 @@ struct OMXCodec : public MediaSource,
// 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();
@@ -125,23 +149,6 @@ private:
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,
@@ -327,9 +334,6 @@ private:
status_t configureCodec(const sp<MetaData> &meta);
static uint32_t getComponentQuirks(
const char *componentName, bool isEncoder);
void restorePatchedDataPointer(BufferInfo *info);
status_t applyRotation();

View File

@@ -186,8 +186,8 @@ public:
inline const_iterator end() const { return array() + size(); }
inline void reserve(size_t n) { setCapacity(n); }
inline bool empty() const{ return isEmpty(); }
inline void push_back(const TYPE& item) { insertAt(item, size()); }
inline void push_front(const TYPE& item) { insertAt(item, 0); }
inline void push_back(const TYPE& item) { insertAt(item, size(), 1); }
inline void push_front(const TYPE& item) { insertAt(item, 0, 1); }
inline iterator erase(iterator pos) {
return begin() + removeItemsAt(pos-array());
}

View File

@@ -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);

View File

@@ -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 \
libcrypto \
libssl \
libgui \
libstagefright_omx \
liblog \
libicuuc \
libicui18n \
libz \
libdl \
libchromium_net \
libcrypto \
libcutils \
libdl \
libdrmframework \
libexpat \
libgui \
libicui18n \
libicuuc \
liblog \
libmedia \
libsonivox \
libssl \
libstagefright_omx \
libstagefright_yuv \
libui \
libutils \
libvorbisidec \
libz \
LOCAL_STATIC_LIBRARIES := \
libstagefright_color_conversion \

View File

@@ -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

View File

@@ -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);
@@ -277,120 +182,37 @@ static int CompareSoftwareCodecsFirst(
return 0;
}
// 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));
}
}
}
@@ -413,6 +239,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,
@@ -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)) {