Merge change 21949 into eclair

* changes:
  Better (proper) parsing of the AVCDecoderConfigurationRecord, respect hardware decoder profile/level limits.
This commit is contained in:
Android (Google) Code Review
2009-08-19 14:32:18 -07:00

View File

@@ -30,6 +30,7 @@
#include <media/stagefright/MetaData.h> #include <media/stagefright/MetaData.h>
#include <media/stagefright/MmapSource.h> #include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXCodec.h> #include <media/stagefright/OMXCodec.h>
#include <media/stagefright/Utils.h>
#include <utils/Vector.h> #include <utils/Vector.h>
#include <OMX_Audio.h> #include <OMX_Audio.h>
@@ -116,6 +117,39 @@ static const char *GetCodec(const CodecInfo *info, size_t numInfos,
return NULL; 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 // static
sp<OMXCodec> OMXCodec::Create( sp<OMXCodec> OMXCodec::Create(
const sp<IOMX> &omx, const sp<IOMX> &omx,
@@ -189,29 +223,72 @@ sp<OMXCodec> OMXCodec::Create(
} else if (meta->findData(kKeyAVCC, &type, &data, &size)) { } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
printf("found avcc of size %d\n", 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; 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; ptr += 2;
size -= 2; size -= 2;
// printf("length = %d, size = %d\n", length, size);
CHECK(size >= length); CHECK(size >= length);
codec->addCodecSpecificData(ptr, length); codec->addCodecSpecificData(ptr, length);
ptr += length; ptr += length;
size -= length; size -= length;
}
if (size <= 1) { CHECK(size >= 1);
break; size_t numPictureParameterSets = *ptr;
} ++ptr;
--size;
ptr++; // XXX skip trailing 0x01 byte??? for (size_t i = 0; i < numPictureParameterSets; ++i) {
--size; 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;
} }
} }