Merge change 21949 into eclair
* changes: Better (proper) parsing of the AVCDecoderConfigurationRecord, respect hardware decoder profile/level limits.
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user