Better (proper) parsing of the AVCDecoderConfigurationRecord, respect hardware decoder profile/level limits.
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 70ab0b5..1774eaf 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -30,6 +30,7 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/Utils.h>
#include <utils/Vector.h>
#include <OMX_Audio.h>
@@ -116,6 +117,39 @@
return NULL;
}
+enum {
+ kAVCProfileBaseline = 0x42,
+ kAVCProfileMain = 0x4d,
+ kAVCProfileExtended = 0x58,
+ kAVCProfileHigh = 0x64,
+ kAVCProfileHigh10 = 0x6e,
+ kAVCProfileHigh422 = 0x7a,
+ kAVCProfileHigh444 = 0xf4,
+ kAVCProfileCAVLC444Intra = 0x2c
+};
+
+static const char *AVCProfileToString(uint8_t profile) {
+ switch (profile) {
+ case kAVCProfileBaseline:
+ return "Baseline";
+ case kAVCProfileMain:
+ return "Main";
+ case kAVCProfileExtended:
+ return "Extended";
+ case kAVCProfileHigh:
+ return "High";
+ case kAVCProfileHigh10:
+ return "High 10";
+ case kAVCProfileHigh422:
+ return "High 422";
+ case kAVCProfileHigh444:
+ return "High 444";
+ case kAVCProfileCAVLC444Intra:
+ return "CAVLC 444 Intra";
+ default: return "Unknown";
+ }
+}
+
// static
sp<OMXCodec> OMXCodec::Create(
const sp<IOMX> &omx,
@@ -189,29 +223,72 @@
} else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
printf("found avcc of size %d\n", size);
- const uint8_t *ptr = (const uint8_t *)data + 6;
+ // Parse the AVCDecoderConfigurationRecord
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ CHECK(size >= 7);
+ CHECK_EQ(ptr[0], 1); // configurationVersion == 1
+ uint8_t profile = ptr[1];
+ uint8_t level = ptr[3];
+
+ CHECK((ptr[4] >> 2) == 0x3f); // reserved
+
+ size_t lengthSize = 1 + (ptr[4] & 3);
+
+ // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
+ // violates it...
+ // CHECK((ptr[5] >> 5) == 7); // reserved
+
+ size_t numSeqParameterSets = ptr[5] & 31;
+
+ ptr += 6;
size -= 6;
- while (size >= 2) {
- size_t length = ptr[0] << 8 | ptr[1];
+
+ for (size_t i = 0; i < numSeqParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
ptr += 2;
size -= 2;
- // printf("length = %d, size = %d\n", length, size);
-
CHECK(size >= length);
codec->addCodecSpecificData(ptr, length);
ptr += length;
size -= length;
+ }
- if (size <= 1) {
- break;
- }
+ CHECK(size >= 1);
+ size_t numPictureParameterSets = *ptr;
+ ++ptr;
+ --size;
- ptr++; // XXX skip trailing 0x01 byte???
- --size;
+ for (size_t i = 0; i < numPictureParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
+
+ ptr += 2;
+ size -= 2;
+
+ CHECK(size >= length);
+
+ codec->addCodecSpecificData(ptr, length);
+
+ ptr += length;
+ size -= length;
+ }
+
+ LOGI("AVC profile = %d (%s), level = %d",
+ (int)profile, AVCProfileToString(profile), (int)level / 10);
+
+ if (!strcmp(componentName, "OMX.TI.Video.Decoder")
+ && (profile != kAVCProfileBaseline || level > 39)) {
+ // This stream exceeds the decoder's capabilities.
+
+ LOGE("Profile and/or level exceed the decoder's capabilities.");
+ return NULL;
}
}
@@ -529,7 +606,7 @@
OMXCodec::OMXCodec(
const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
- bool isEncoder,
+ bool isEncoder,
const char *mime,
const char *componentName,
const sp<MediaSource> &source)
@@ -569,7 +646,7 @@
free(mComponentName);
mComponentName = NULL;
-
+
free(mMIME);
mMIME = NULL;
}
@@ -772,7 +849,7 @@
mBufferFilled.signal();
} else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
-
+
MediaBuffer *buffer = info->mMediaBuffer;
buffer->set_range(
@@ -1383,7 +1460,7 @@
CHECK_EQ(def.eDomain, OMX_PortDomainImage);
OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
-
+
CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
imageDef->eColorFormat = format;
imageDef->nFrameWidth = width;
@@ -1460,7 +1537,7 @@
if (mState != LOADED) {
return UNKNOWN_ERROR;
}
-
+
sp<MetaData> params = new MetaData;
if (mQuirks & kWantsNALFragments) {
params->setInt32(kKeyWantsNALFragments, true);
@@ -1630,7 +1707,7 @@
"OMX_COLOR_Format16bitBGR565",
"OMX_COLOR_Format18bitRGB666",
"OMX_COLOR_Format18bitARGB1665",
- "OMX_COLOR_Format19bitARGB1666",
+ "OMX_COLOR_Format19bitARGB1666",
"OMX_COLOR_Format24bitRGB888",
"OMX_COLOR_Format24bitBGR888",
"OMX_COLOR_Format24bitARGB1887",
@@ -1653,11 +1730,11 @@
"OMX_COLOR_FormatRawBayer8bit",
"OMX_COLOR_FormatRawBayer10bit",
"OMX_COLOR_FormatRawBayer8bitcompressed",
- "OMX_COLOR_FormatL2",
- "OMX_COLOR_FormatL4",
- "OMX_COLOR_FormatL8",
- "OMX_COLOR_FormatL16",
- "OMX_COLOR_FormatL24",
+ "OMX_COLOR_FormatL2",
+ "OMX_COLOR_FormatL4",
+ "OMX_COLOR_FormatL8",
+ "OMX_COLOR_FormatL16",
+ "OMX_COLOR_FormatL24",
"OMX_COLOR_FormatL32",
"OMX_COLOR_FormatYUV420PackedSemiPlanar",
"OMX_COLOR_FormatYUV422PackedSemiPlanar",