summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/MPEG4Extractor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/MPEG4Extractor.cpp')
-rwxr-xr-x[-rw-r--r--]media/libstagefright/MPEG4Extractor.cpp368
1 files changed, 304 insertions, 64 deletions
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 92cc771..a1af3aa 100644..100755
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -358,6 +358,8 @@ static bool AdjustChannelsAndRate(uint32_t fourcc, uint32_t *channels, uint32_t
MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
: mMoofOffset(0),
+ mMoofFound(false),
+ mMdatFound(false),
mDataSource(source),
mInitCheck(NO_INIT),
mHasVideo(false),
@@ -494,7 +496,9 @@ status_t MPEG4Extractor::readMetaData() {
off64_t offset = 0;
status_t err;
- while (true) {
+ bool sawMoovOrSidx = false;
+
+ while (!(sawMoovOrSidx && (mMdatFound || mMoofFound))) {
off64_t orig_offset = offset;
err = parseChunk(&offset, 0);
@@ -503,26 +507,12 @@ status_t MPEG4Extractor::readMetaData() {
} else if (offset <= orig_offset) {
// only continue parsing if the offset was advanced,
// otherwise we might end up in an infinite loop
- ALOGE("did not advance: 0x%lld->0x%lld", orig_offset, offset);
+ ALOGE("did not advance: %lld->%lld", (long long)orig_offset, (long long)offset);
err = ERROR_MALFORMED;
break;
- } else if (err == OK) {
- continue;
- }
-
- uint32_t hdr[2];
- if (mDataSource->readAt(offset, hdr, 8) < 8) {
- break;
+ } else if (err == UNKNOWN_ERROR) {
+ sawMoovOrSidx = true;
}
- uint32_t chunk_type = ntohl(hdr[1]);
- if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
- // store the offset of the first segment
- mMoofOffset = offset;
- } else if (chunk_type != FOURCC('m', 'd', 'a', 't')) {
- // keep parsing until we get to the data
- continue;
- }
- break;
}
if (mInitCheck == OK) {
@@ -539,11 +529,11 @@ status_t MPEG4Extractor::readMetaData() {
CHECK_NE(err, (status_t)NO_INIT);
// copy pssh data into file metadata
- int psshsize = 0;
+ uint64_t psshsize = 0;
for (size_t i = 0; i < mPssh.size(); i++) {
psshsize += 20 + mPssh[i].datalen;
}
- if (psshsize) {
+ if (psshsize > 0 && psshsize <= UINT32_MAX) {
char *buf = (char*)malloc(psshsize);
char *ptr = buf;
for (size_t i = 0; i < mPssh.size(); i++) {
@@ -753,6 +743,17 @@ static bool underMetaDataPath(const Vector<uint32_t> &path) {
&& path[3] == FOURCC('i', 'l', 's', 't');
}
+static bool underQTMetaPath(const Vector<uint32_t> &path, int32_t depth) {
+ return path.size() >= 2
+ && path[0] == FOURCC('m', 'o', 'o', 'v')
+ && path[1] == FOURCC('m', 'e', 't', 'a')
+ && (depth == 2
+ || (depth == 3
+ && (path[2] == FOURCC('h', 'd', 'l', 'r')
+ || path[2] == FOURCC('i', 'l', 's', 't')
+ || path[2] == FOURCC('k', 'e', 'y', 's'))));
+}
+
// Given a time in seconds since Jan 1 1904, produce a human-readable string.
static void convertTimeToDate(int64_t time_1904, String8 *s) {
time_t time_1970 = time_1904 - (((66 * 365 + 17) * 24) * 3600);
@@ -764,7 +765,7 @@ static void convertTimeToDate(int64_t time_1904, String8 *s) {
}
status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
- ALOGV("entering parseChunk %lld/%d", *offset, depth);
+ ALOGV("entering parseChunk %lld/%d", (long long)*offset, depth);
uint32_t hdr[2];
if (mDataSource->readAt(*offset, hdr, 8) < 8) {
return ERROR_IO;
@@ -808,7 +809,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
char chunk[5];
MakeFourCCString(chunk_type, chunk);
- ALOGV("chunk: %s @ %lld, %d", chunk, *offset, depth);
+ ALOGV("chunk: %s @ %lld, %d", chunk, (long long)*offset, depth);
if (kUseHexDump) {
static const char kWhitespace[] = " ";
@@ -868,6 +869,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 'c', 'h', 'i'):
case FOURCC('e', 'd', 't', 's'):
{
+ if (chunk_type == FOURCC('m', 'o', 'o', 'f') && !mMoofFound) {
+ // store the offset of the first segment
+ mMoofFound = true;
+ mMoofOffset = *offset;
+ }
+
if (chunk_type == FOURCC('s', 't', 'b', 'l')) {
ALOGV("sampleTable chunk is %" PRIu64 " bytes long.", chunk_size);
@@ -882,6 +889,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
}
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->sampleTable = new SampleTable(mDataSource);
}
@@ -1036,6 +1046,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
}
original_fourcc = ntohl(original_fourcc);
ALOGV("read original format: %d", original_fourcc);
+
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(original_fourcc));
uint32_t num_channels = 0;
uint32_t sample_rate = 0;
@@ -1091,6 +1105,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setInt32(kKeyCryptoMode, defaultAlgorithmId);
mLastTrack->meta->setInt32(kKeyCryptoDefaultIVSize, defaultIVSize);
mLastTrack->meta->setData(kKeyCryptoKey, 'tenc', defaultKeyId, 16);
@@ -1125,7 +1142,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
}
pssh.datalen = ntohl(psshdatalen);
ALOGV("pssh data size: %d", pssh.datalen);
- if (pssh.datalen + 20 > chunk_size) {
+ if (chunk_size < 20 || pssh.datalen > chunk_size - 20) {
// pssh data length exceeds size of containing box
return ERROR_MALFORMED;
}
@@ -1206,7 +1223,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
duration = ntohl(duration32);
}
}
- if (duration != 0) {
+ if (duration != 0 && mLastTrack->timescale != 0) {
mLastTrack->meta->setInt64(
kKeyDuration, (duration * 1000000) / mLastTrack->timescale);
}
@@ -1270,6 +1287,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
// display the timed text.
// For encrypted files, there may also be more than one entry.
const char *mime;
+
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) &&
strcasecmp(mime, "application/octet-stream")) {
@@ -1316,6 +1337,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
uint16_t sample_size = U16_AT(&buffer[18]);
uint32_t sample_rate = U32_AT(&buffer[24]) >> 16;
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
if (chunk_type != FOURCC('e', 'n', 'c', 'a')) {
// if the chunk type is enca, we'll get the type from the sinf/frma box later
mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
@@ -1377,6 +1401,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
// printf("*** coding='%s' width=%d height=%d\n",
// chunk, width, height);
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
if (chunk_type != FOURCC('e', 'n', 'c', 'v')) {
// if the chunk type is encv, we'll get the type from the sinf/frma box later
mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
@@ -1402,6 +1429,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 'c', 'o'):
case FOURCC('c', 'o', '6', '4'):
{
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ return ERROR_MALFORMED;
+
status_t err =
mLastTrack->sampleTable->setChunkOffsetParams(
chunk_type, data_offset, chunk_data_size);
@@ -1417,6 +1447,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 's', 'c'):
{
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ return ERROR_MALFORMED;
+
status_t err =
mLastTrack->sampleTable->setSampleToChunkParams(
data_offset, chunk_data_size);
@@ -1433,6 +1466,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 's', 'z'):
case FOURCC('s', 't', 'z', '2'):
{
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ return ERROR_MALFORMED;
+
status_t err =
mLastTrack->sampleTable->setSampleSizeParams(
chunk_type, data_offset, chunk_data_size);
@@ -1514,6 +1550,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 't', 's'):
{
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ return ERROR_MALFORMED;
+
*offset += chunk_size;
status_t err =
@@ -1529,6 +1568,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('c', 't', 't', 's'):
{
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ return ERROR_MALFORMED;
+
*offset += chunk_size;
status_t err =
@@ -1544,6 +1586,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 's', 's'):
{
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ return ERROR_MALFORMED;
+
*offset += chunk_size;
status_t err =
@@ -1557,13 +1602,13 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
break;
}
- // ©xyz
+ // \xA9xyz
case FOURCC(0xA9, 'x', 'y', 'z'):
{
*offset += chunk_size;
- // Best case the total data length inside "©xyz" box
- // would be 8, for instance "©xyz" + "\x00\x04\x15\xc7" + "0+0/",
+ // Best case the total data length inside "\xA9xyz" box
+ // would be 8, for instance "\xA9xyz" + "\x00\x04\x15\xc7" + "0+0/",
// where "\x00\x04" is the text string length with value = 4,
// "\0x15\xc7" is the language code = en, and "0+0" is a
// location (string) value with longitude = 0 and latitude = 0.
@@ -1616,6 +1661,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_MALFORMED;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setData(
kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4);
@@ -1633,7 +1681,18 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return err;
}
}
-
+ if (mPath.size() >= 2
+ && mPath[mPath.size() - 2] == FOURCC('m', 'p', '4', 'v')) {
+ // Check if the video is MPEG2
+ ESDS esds(&buffer[4], chunk_data_size - 4);
+
+ uint8_t objectTypeIndication;
+ if (esds.getObjectTypeIndication(&objectTypeIndication) == OK) {
+ if (objectTypeIndication >= 0x60 && objectTypeIndication <= 0x65) {
+ mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
+ }
+ }
+ }
break;
}
@@ -1648,6 +1707,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setData(
kKeyAVCC, kTypeAVCC, buffer->data(), chunk_data_size);
@@ -1662,6 +1724,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setData(
kKeyHVCC, kTypeHVCC, buffer->data(), chunk_data_size);
@@ -1686,7 +1751,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
char buffer[23];
if (chunk_data_size != 7 &&
chunk_data_size != 23) {
- ALOGE("Incorrect D263 box size %lld", chunk_data_size);
+ ALOGE("Incorrect D263 box size %lld", (long long)chunk_data_size);
return ERROR_MALFORMED;
}
@@ -1695,6 +1760,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setData(kKeyD263, kTypeD263, buffer, chunk_data_size);
break;
@@ -1702,31 +1770,35 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('m', 'e', 't', 'a'):
{
- uint8_t buffer[4];
- if (chunk_data_size < (off64_t)sizeof(buffer)) {
- *offset += chunk_size;
- return ERROR_MALFORMED;
- }
+ off64_t stop_offset = *offset + chunk_size;
+ *offset = data_offset;
+ bool isParsingMetaKeys = underQTMetaPath(mPath, 2);
+ if (!isParsingMetaKeys) {
+ uint8_t buffer[4];
+ if (chunk_data_size < (off64_t)sizeof(buffer)) {
+ *offset += chunk_size;
+ return ERROR_MALFORMED;
+ }
- if (mDataSource->readAt(
- data_offset, buffer, 4) < 4) {
- *offset += chunk_size;
- return ERROR_IO;
- }
+ if (mDataSource->readAt(
+ data_offset, buffer, 4) < 4) {
+ *offset += chunk_size;
+ return ERROR_IO;
+ }
- if (U32_AT(buffer) != 0) {
- // Should be version 0, flags 0.
+ if (U32_AT(buffer) != 0) {
+ // Should be version 0, flags 0.
- // If it's not, let's assume this is one of those
- // apparently malformed chunks that don't have flags
- // and completely different semantics than what's
- // in the MPEG4 specs and skip it.
- *offset += chunk_size;
- return OK;
+ // If it's not, let's assume this is one of those
+ // apparently malformed chunks that don't have flags
+ // and completely different semantics than what's
+ // in the MPEG4 specs and skip it.
+ *offset += chunk_size;
+ return OK;
+ }
+ *offset += sizeof(buffer);
}
- off64_t stop_offset = *offset + chunk_size;
- *offset = data_offset + sizeof(buffer);
while (*offset < stop_offset) {
status_t err = parseChunk(offset, depth + 1);
if (err != OK) {
@@ -1792,7 +1864,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
}
duration = d32;
}
- if (duration != 0) {
+ if (duration != 0 && mHeaderTimescale != 0) {
mFileMetaData->setInt64(kKeyDuration, duration * 1000000 / mHeaderTimescale);
}
@@ -1841,7 +1913,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_MALFORMED;
}
- if (duration != 0) {
+ if (duration != 0 && mHeaderTimescale != 0) {
mFileMetaData->setInt64(kKeyDuration, duration * 1000000 / mHeaderTimescale);
}
@@ -1851,6 +1923,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('m', 'd', 'a', 't'):
{
ALOGV("mdat chunk, drm: %d", mIsDrm);
+
+ mMdatFound = true;
+
if (!mIsDrm) {
*offset += chunk_size;
break;
@@ -1867,6 +1942,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
{
*offset += chunk_size;
+ if (underQTMetaPath(mPath, 3)) {
+ break;
+ }
+
uint32_t buffer;
if (mDataSource->readAt(
data_offset + 8, &buffer, 4) < 4) {
@@ -1878,12 +1957,24 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
// shall be 'text'. We also want to support 'sbtl' handler type
// for a practical reason as various MPEG4 containers use it.
if (type == FOURCC('t', 'e', 'x', 't') || type == FOURCC('s', 'b', 't', 'l')) {
- mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
+ if (mLastTrack != NULL) {
+ mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
+ }
}
break;
}
+ case FOURCC('k', 'e', 'y', 's'):
+ {
+ *offset += chunk_size;
+
+ if (underQTMetaPath(mPath, 3)) {
+ parseQTMetaKey(data_offset, chunk_data_size);
+ }
+ break;
+ }
+
case FOURCC('t', 'r', 'e', 'x'):
{
*offset += chunk_size;
@@ -1905,6 +1996,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('t', 'x', '3', 'g'):
{
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
uint32_t type;
const void *data;
size_t size = 0;
@@ -1950,8 +2044,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
*offset += chunk_size;
if (mFileMetaData != NULL) {
- ALOGV("chunk_data_size = %lld and data_offset = %lld",
- chunk_data_size, data_offset);
+ ALOGV("chunk_data_size = %" PRId64 " and data_offset = %" PRId64,
+ chunk_data_size, data_offset);
if (chunk_data_size < 0 || static_cast<uint64_t>(chunk_data_size) >= SIZE_MAX - 1) {
return ERROR_MALFORMED;
@@ -2023,6 +2117,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
default:
{
+ // check if we're parsing 'ilst' for meta keys
+ // if so, treat type as a number (key-id).
+ if (underQTMetaPath(mPath, 3)) {
+ parseQTMetaVal(chunk_type, data_offset, chunk_data_size);
+ }
+
*offset += chunk_size;
break;
}
@@ -2058,6 +2158,8 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) {
return ERROR_MALFORMED;
}
ALOGV("sidx refid/timescale: %d/%d", referenceId, timeScale);
+ if (timeScale == 0)
+ return ERROR_MALFORMED;
uint64_t earliestPresentationTime;
uint64_t firstOffset;
@@ -2141,6 +2243,9 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) {
uint64_t sidxDuration = total_duration * 1000000 / timeScale;
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
int64_t metaDuration;
if (!mLastTrack->meta->findInt64(kKeyDuration, &metaDuration) || metaDuration == 0) {
mLastTrack->meta->setInt64(kKeyDuration, sidxDuration);
@@ -2148,7 +2253,108 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) {
return OK;
}
+status_t MPEG4Extractor::parseQTMetaKey(off64_t offset, size_t size) {
+ if (size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ uint32_t count;
+ if (!mDataSource->getUInt32(offset + 4, &count)) {
+ return ERROR_MALFORMED;
+ }
+
+ if (mMetaKeyMap.size() > 0) {
+ ALOGW("'keys' atom seen again, discarding existing entries");
+ mMetaKeyMap.clear();
+ }
+
+ off64_t keyOffset = offset + 8;
+ off64_t stopOffset = offset + size;
+ for (size_t i = 1; i <= count; i++) {
+ if (keyOffset + 8 > stopOffset) {
+ return ERROR_MALFORMED;
+ }
+
+ uint32_t keySize;
+ if (!mDataSource->getUInt32(keyOffset, &keySize)
+ || keySize < 8
+ || keyOffset + keySize > stopOffset) {
+ return ERROR_MALFORMED;
+ }
+
+ uint32_t type;
+ if (!mDataSource->getUInt32(keyOffset + 4, &type)
+ || type != FOURCC('m', 'd', 't', 'a')) {
+ return ERROR_MALFORMED;
+ }
+
+ keySize -= 8;
+ keyOffset += 8;
+
+ sp<ABuffer> keyData = new ABuffer(keySize);
+ if (keyData->data() == NULL) {
+ return ERROR_MALFORMED;
+ }
+ if (mDataSource->readAt(
+ keyOffset, keyData->data(), keySize) < (ssize_t) keySize) {
+ return ERROR_MALFORMED;
+ }
+ AString key((const char *)keyData->data(), keySize);
+ mMetaKeyMap.add(i, key);
+
+ keyOffset += keySize;
+ }
+ return OK;
+}
+
+status_t MPEG4Extractor::parseQTMetaVal(
+ int32_t keyId, off64_t offset, size_t size) {
+ ssize_t index = mMetaKeyMap.indexOfKey(keyId);
+ if (index < 0) {
+ // corresponding key is not present, ignore
+ return ERROR_MALFORMED;
+ }
+
+ if (size <= 16) {
+ return ERROR_MALFORMED;
+ }
+ uint32_t dataSize;
+ if (!mDataSource->getUInt32(offset, &dataSize)
+ || dataSize > size || dataSize <= 16) {
+ return ERROR_MALFORMED;
+ }
+ uint32_t atomFourCC;
+ if (!mDataSource->getUInt32(offset + 4, &atomFourCC)
+ || atomFourCC != FOURCC('d', 'a', 't', 'a')) {
+ return ERROR_MALFORMED;
+ }
+ uint32_t dataType;
+ if (!mDataSource->getUInt32(offset + 8, &dataType)
+ || ((dataType & 0xff000000) != 0)) {
+ // not well-known type
+ return ERROR_MALFORMED;
+ }
+
+ dataSize -= 16;
+ offset += 16;
+
+ if (dataType == 23 && dataSize >= 4) {
+ // BE Float32
+ uint32_t val;
+ if (!mDataSource->getUInt32(offset, &val)) {
+ return ERROR_MALFORMED;
+ }
+ if (!strcasecmp(mMetaKeyMap[index].c_str(), "com.android.capture.fps")) {
+ mFileMetaData->setFloat(kKeyCaptureFramerate, *(float *)&val);
+ }
+ } else {
+ // add more keys if needed
+ ALOGV("ignoring key: type %d, size %d", dataType, dataSize);
+ }
+
+ return OK;
+}
status_t MPEG4Extractor::parseTrackHeader(
off64_t data_offset, off64_t data_size) {
@@ -2191,6 +2397,9 @@ status_t MPEG4Extractor::parseTrackHeader(
return ERROR_UNSUPPORTED;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setInt32(kKeyTrackID, id);
size_t matrixOffset = dynSize + 16;
@@ -2262,7 +2471,7 @@ status_t MPEG4Extractor::parseITunesMetaData(off64_t offset, size_t size) {
uint32_t metadataKey = 0;
char chunk[5];
MakeFourCCString(mPath[4], chunk);
- ALOGV("meta: %s @ %lld", chunk, offset);
+ ALOGV("meta: %s @ %lld", chunk, (long long)offset);
switch ((int32_t)mPath[4]) {
case FOURCC(0xa9, 'a', 'l', 'b'):
{
@@ -2379,6 +2588,9 @@ status_t MPEG4Extractor::parseITunesMetaData(off64_t offset, size_t size) {
int32_t delay, padding;
if (sscanf(mLastCommentData,
" %*x %x %x %*x", &delay, &padding) == 2) {
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setInt32(kKeyEncoderDelay, delay);
mLastTrack->meta->setInt32(kKeyEncoderPadding, padding);
}
@@ -2667,6 +2879,7 @@ status_t MPEG4Extractor::verifyTrack(Track *track) {
return ERROR_MALFORMED;
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
+ || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2)
|| !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
if (!track->meta->findData(kKeyESDS, &type, &data, &size)
|| type != kTypeESDS) {
@@ -2751,6 +2964,9 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
if (objectTypeIndication == 0xe1) {
// This isn't MPEG4 audio at all, it's QCELP 14k...
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_QCELP);
return OK;
}
@@ -2771,7 +2987,7 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
}
if (kUseHexDump) {
- printf("ESD of size %d\n", csd_size);
+ printf("ESD of size %zu\n", csd_size);
hexdump(csd, csd_size);
}
@@ -2799,6 +3015,9 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
objectType = 32 + br.getBits(6);
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
//keep AOT type
mLastTrack->meta->setInt32(kKeyAACAOT, objectType);
@@ -2807,12 +3026,11 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
int32_t sampleRate = 0;
int32_t numChannels = 0;
if (freqIndex == 15) {
- if (csd_size < 5) {
- return ERROR_MALFORMED;
- }
+ if (br.numBitsLeft() < 28) return ERROR_MALFORMED;
sampleRate = br.getBits(24);
numChannels = br.getBits(4);
} else {
+ if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
numChannels = br.getBits(4);
if (freqIndex == 13 || freqIndex == 14) {
@@ -2823,12 +3041,14 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
}
if (objectType == AOT_SBR || objectType == AOT_PS) {//SBR specific config per 14496-3 table 1.13
+ if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
uint32_t extFreqIndex = br.getBits(4);
int32_t extSampleRate __unused;
if (extFreqIndex == 15) {
if (csd_size < 8) {
return ERROR_MALFORMED;
}
+ if (br.numBitsLeft() < 24) return ERROR_MALFORMED;
extSampleRate = br.getBits(24);
} else {
if (extFreqIndex == 13 || extFreqIndex == 14) {
@@ -2865,20 +3085,24 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
{
if (objectType == AOT_SBR || objectType == AOT_PS) {
+ if (br.numBitsLeft() < 5) return ERROR_MALFORMED;
objectType = br.getBits(5);
if (objectType == AOT_ESCAPE) {
+ if (br.numBitsLeft() < 6) return ERROR_MALFORMED;
objectType = 32 + br.getBits(6);
}
}
if (objectType == AOT_AAC_LC || objectType == AOT_ER_AAC_LC ||
objectType == AOT_ER_AAC_LD || objectType == AOT_ER_AAC_SCAL ||
objectType == AOT_ER_BSAC) {
+ if (br.numBitsLeft() < 2) return ERROR_MALFORMED;
const int32_t frameLengthFlag __unused = br.getBits(1);
const int32_t dependsOnCoreCoder = br.getBits(1);
if (dependsOnCoreCoder ) {
+ if (br.numBitsLeft() < 14) return ERROR_MALFORMED;
const int32_t coreCoderDelay __unused = br.getBits(14);
}
@@ -2898,7 +3122,7 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
extensionFlag = 1;
break;
default:
- TRESPASS();
+ return ERROR_MALFORMED;
break;
}
ALOGW("csd missing extension flag; assuming %d for object type %u.",
@@ -2908,6 +3132,9 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
if (numChannels == 0) {
int32_t channelsEffectiveNum = 0;
int32_t channelsNum = 0;
+ if (br.numBitsLeft() < 32) {
+ return ERROR_MALFORMED;
+ }
const int32_t ElementInstanceTag __unused = br.getBits(4);
const int32_t Profile __unused = br.getBits(2);
const int32_t SamplingFrequencyIndex __unused = br.getBits(4);
@@ -2919,35 +3146,44 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
const int32_t NumValidCcElements __unused = br.getBits(4);
const int32_t MonoMixdownPresent = br.getBits(1);
+
if (MonoMixdownPresent != 0) {
+ if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
const int32_t MonoMixdownElementNumber __unused = br.getBits(4);
}
+ if (br.numBitsLeft() < 1) return ERROR_MALFORMED;
const int32_t StereoMixdownPresent = br.getBits(1);
if (StereoMixdownPresent != 0) {
+ if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
const int32_t StereoMixdownElementNumber __unused = br.getBits(4);
}
+ if (br.numBitsLeft() < 1) return ERROR_MALFORMED;
const int32_t MatrixMixdownIndexPresent = br.getBits(1);
if (MatrixMixdownIndexPresent != 0) {
+ if (br.numBitsLeft() < 3) return ERROR_MALFORMED;
const int32_t MatrixMixdownIndex __unused = br.getBits(2);
const int32_t PseudoSurroundEnable __unused = br.getBits(1);
}
int i;
for (i=0; i < NumFrontChannelElements; i++) {
+ if (br.numBitsLeft() < 5) return ERROR_MALFORMED;
const int32_t FrontElementIsCpe = br.getBits(1);
const int32_t FrontElementTagSelect __unused = br.getBits(4);
channelsNum += FrontElementIsCpe ? 2 : 1;
}
for (i=0; i < NumSideChannelElements; i++) {
+ if (br.numBitsLeft() < 5) return ERROR_MALFORMED;
const int32_t SideElementIsCpe = br.getBits(1);
const int32_t SideElementTagSelect __unused = br.getBits(4);
channelsNum += SideElementIsCpe ? 2 : 1;
}
for (i=0; i < NumBackChannelElements; i++) {
+ if (br.numBitsLeft() < 5) return ERROR_MALFORMED;
const int32_t BackElementIsCpe = br.getBits(1);
const int32_t BackElementTagSelect __unused = br.getBits(4);
channelsNum += BackElementIsCpe ? 2 : 1;
@@ -2955,6 +3191,7 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
channelsEffectiveNum = channelsNum;
for (i=0; i < NumLfeChannelElements; i++) {
+ if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
const int32_t LfeElementTagSelect __unused = br.getBits(4);
channelsNum += 1;
}
@@ -2969,6 +3206,9 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
return ERROR_UNSUPPORTED;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
int32_t prevSampleRate;
CHECK(mLastTrack->meta->findInt32(kKeySampleRate, &prevSampleRate));
@@ -3180,7 +3420,7 @@ status_t MPEG4Source::parseChunk(off64_t *offset) {
char chunk[5];
MakeFourCCString(chunk_type, chunk);
- ALOGV("MPEG4Source chunk %s @ %llx", chunk, *offset);
+ ALOGV("MPEG4Source chunk %s @ %#llx", chunk, (long long)*offset);
off64_t chunk_data_size = *offset + chunk_size - data_offset;
@@ -3660,7 +3900,7 @@ status_t MPEG4Source::parseTrackFragmentRun(off64_t offset, off64_t size) {
sampleCtsOffset = 0;
}
- if (size < (off64_t)sampleCount * bytesPerSample) {
+ if (size < (off64_t)(sampleCount * bytesPerSample)) {
return -EINVAL;
}
@@ -4459,7 +4699,7 @@ static bool BetterSniffMPEG4(
char chunkstring[5];
MakeFourCCString(chunkType, chunkstring);
- ALOGV("saw chunk type %s, size %" PRIu64 " @ %lld", chunkstring, chunkSize, offset);
+ ALOGV("saw chunk type %s, size %" PRIu64 " @ %lld", chunkstring, chunkSize, (long long)offset);
switch (chunkType) {
case FOURCC('f', 't', 'y', 'p'):
{
@@ -4522,7 +4762,7 @@ static bool BetterSniffMPEG4(
*meta = new AMessage;
(*meta)->setInt64("meta-data-size", moovAtomEndOffset);
- ALOGV("found metadata size: %lld", moovAtomEndOffset);
+ ALOGV("found metadata size: %lld", (long long)moovAtomEndOffset);
}
return true;