From e13526ad926bfee99778a4f21ea5e4f8a6c8984f Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Thu, 22 Oct 2009 10:43:34 -0700 Subject: [PATCH] Prefer software decoders over hardware for thumbnail extraction. While our hardware decoders clearly outperform the software decoders in terms of raw throughput, their startup latency makes them less suitable for thumbnail extraction. --- include/media/stagefright/OMXCodec.h | 14 +- .../StagefrightMetadataRetriever.cpp | 3 +- media/libstagefright/OMXCodec.cpp | 154 +++++++++++++----- 3 files changed, 128 insertions(+), 43 deletions(-) diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index dfc902e12c33f..d0f4f1720416b 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -30,11 +30,15 @@ struct OMXCodecObserver; struct OMXCodec : public MediaSource, public MediaBufferObserver { + enum CreationFlags { + kPreferSoftwareCodecs = 1, + }; static sp Create( const sp &omx, const sp &meta, bool createEncoder, const sp &source, - const char *matchComponentName = NULL); + const char *matchComponentName = NULL, + uint32_t flags = 0); static void setComponentRole( const sp &omx, IOMX::node_id node, bool isEncoder, @@ -207,6 +211,14 @@ private: void dumpPortStatus(OMX_U32 portIndex); + static uint32_t getComponentQuirks(const char *componentName); + + static void findMatchingCodecs( + const char *mime, + bool createEncoder, const char *matchComponentName, + uint32_t flags, + Vector *matchingCodecs); + OMXCodec(const OMXCodec &); OMXCodec &operator=(const OMXCodec &); }; diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp index 5ac59c8faaf06..fced87bf8ec10 100644 --- a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp +++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp @@ -122,7 +122,8 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() { sp decoder = OMXCodec::Create( - mClient.interface(), meta, false, source); + mClient.interface(), meta, false, source, + NULL, OMXCodec::kPreferSoftwareCodecs); if (decoder.get() == NULL) { LOGE("unable to instantiate video decoder."); diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index f8c0bda807990..e0f9563a24dc6 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -172,49 +172,35 @@ static void InitOMXParams(T *params) { params->nVersion.s.nStep = 0; } -// static -sp OMXCodec::Create( - const sp &omx, - const sp &meta, bool createEncoder, - const sp &source, - const char *matchComponentName) { - const char *mime; - bool success = meta->findCString(kKeyMIMEType, &mime); - CHECK(success); - - const char *componentName = NULL; - sp observer = new OMXCodecObserver; - IOMX::node_id node = 0; - for (int index = 0;; ++index) { - if (createEncoder) { - componentName = GetCodec( - kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]), - mime, index); - } else { - componentName = GetCodec( - kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]), - mime, index); - } - - if (!componentName) { - return NULL; - } - - // If a specific codec is requested, skip the non-matching ones. - if (matchComponentName && strcmp(componentName, matchComponentName)) { - continue; - } - - LOGV("Attempting to allocate OMX node '%s'", componentName); - - status_t err = omx->allocateNode(componentName, observer, &node); - if (err == OK) { - LOGV("Successfully allocated OMX node '%s'", componentName); - break; - } +static bool IsSoftwareCodec(const char *componentName) { + if (!strncmp("OMX.PV.", componentName, 7)) { + return true; } + return false; +} + +static int CompareSoftwareCodecsFirst( + const String8 *elem1, const String8 *elem2) { + bool isSoftwareCodec1 = IsSoftwareCodec(elem1->string()); + bool isSoftwareCodec2 = IsSoftwareCodec(elem2->string()); + + if (isSoftwareCodec1) { + if (isSoftwareCodec2) { return 0; } + return -1; + } + + if (isSoftwareCodec2) { + return 1; + } + + return 0; +} + +// static +uint32_t OMXCodec::getComponentQuirks(const char *componentName) { uint32_t quirks = 0; + if (!strcmp(componentName, "OMX.PV.avcdec")) { quirks |= kWantsNALFragments; } @@ -244,8 +230,94 @@ sp OMXCodec::Create( quirks |= kRequiresAllocateBufferOnOutputPorts; } + return quirks; +} + +// static +void OMXCodec::findMatchingCodecs( + const char *mime, + bool createEncoder, const char *matchComponentName, + uint32_t flags, + Vector *matchingCodecs) { + matchingCodecs->clear(); + + for (int index = 0;; ++index) { + const char *componentName; + + if (createEncoder) { + componentName = GetCodec( + kEncoderInfo, + sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]), + mime, index); + } else { + componentName = GetCodec( + kDecoderInfo, + sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]), + mime, index); + } + + if (!componentName) { + break; + } + + // If a specific codec is requested, skip the non-matching ones. + if (matchComponentName && strcmp(componentName, matchComponentName)) { + continue; + } + + matchingCodecs->push(String8(componentName)); + } + + if (flags & kPreferSoftwareCodecs) { + matchingCodecs->sort(CompareSoftwareCodecsFirst); + } +} + +// static +sp OMXCodec::Create( + const sp &omx, + const sp &meta, bool createEncoder, + const sp &source, + const char *matchComponentName, + uint32_t flags) { + const char *mime; + bool success = meta->findCString(kKeyMIMEType, &mime); + CHECK(success); + + Vector matchingCodecs; + findMatchingCodecs( + mime, createEncoder, matchComponentName, flags, &matchingCodecs); + + if (matchingCodecs.isEmpty()) { + return NULL; + } + + sp observer = new OMXCodecObserver; + IOMX::node_id node = 0; + success = false; + + const char *componentName; + for (size_t i = 0; i < matchingCodecs.size(); ++i) { + componentName = matchingCodecs[i].string(); + + LOGV("Attempting to allocate OMX node '%s'", componentName); + + status_t err = omx->allocateNode(componentName, observer, &node); + if (err == OK) { + LOGV("Successfully allocated OMX node '%s'", componentName); + + success = true; + break; + } + } + + if (!success) { + return NULL; + } + sp codec = new OMXCodec( - omx, node, quirks, createEncoder, mime, componentName, + omx, node, getComponentQuirks(componentName), + createEncoder, mime, componentName, source); observer->setCodec(codec);