Bug 1059049 - Defer parsing of saio/saiz boxes until after trun - r=ajones
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -150,16 +150,26 @@ private:
uint32_t ctsOffset;
uint8_t iv[16];
Vector<uint16_t> clearsizes;
Vector<uint32_t> encryptedsizes;
};
Vector<Sample> mCurrentSamples;
MPEG4Extractor::TrackExtends mTrackExtends;
+ // XXX hack -- demuxer expects a track's trun to be seen before saio or
+ // saiz. Here we store saiz/saio box offsets for parsing *after* the trun
+ // has been parsed.
+ struct AuxRange {
+ off64_t mStart;
+ off64_t mSize;
+ };
+ Vector<AuxRange> mDeferredSaiz;
+ Vector<AuxRange> mDeferredSaio;
+
MPEG4Source(const MPEG4Source &);
MPEG4Source &operator=(const MPEG4Source &);
};
// This custom data source wraps an existing one and satisfies requests
// falling entirely within a cached range from the cache while forwarding
// all remaining requests to the wrapped datasource.
// This is used to cache the full sampletable metadata for a single track,
@@ -2601,26 +2611,30 @@ status_t MPEG4Source::parseChunk(off64_t
}
*offset += chunk_size;
break;
}
case FOURCC('s', 'a', 'i', 'z'): {
status_t err;
- if ((err = parseSampleAuxiliaryInformationSizes(data_offset, chunk_data_size)) != OK) {
- return err;
+ if (mLastParsedTrackId == mTrackId) {
+ if ((err = parseSampleAuxiliaryInformationSizes(data_offset, chunk_data_size)) != OK) {
+ return err;
+ }
}
*offset += chunk_size;
break;
}
case FOURCC('s', 'a', 'i', 'o'): {
status_t err;
- if ((err = parseSampleAuxiliaryInformationOffsets(data_offset, chunk_data_size)) != OK) {
- return err;
+ if (mLastParsedTrackId == mTrackId) {
+ if ((err = parseSampleAuxiliaryInformationOffsets(data_offset, chunk_data_size)) != OK) {
+ return err;
+ }
}
*offset += chunk_size;
break;
}
case FOURCC('m', 'd', 'a', 't'): {
// parse DRM info if present
ALOGV("MPEG4Source::parseChunk mdat");
@@ -2635,16 +2649,28 @@ status_t MPEG4Source::parseChunk(off64_t
}
}
return OK;
}
status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size) {
ALOGV("parseSampleAuxiliaryInformationSizes");
// 14496-12 8.7.12
+
+ if (mCurrentSamples.isEmpty()) {
+ // XXX hack -- we haven't seen trun yet; defer parsing this box until
+ // after trun.
+ ALOGW("deferring processing of saiz box");
+ AuxRange range;
+ range.mStart = offset;
+ range.mSize = size;
+ mDeferredSaiz.add(range);
+ return OK;
+ }
+
uint8_t version;
if (mDataSource->readAt(
offset, &version, sizeof(version))
< (ssize_t)sizeof(version)) {
return ERROR_IO;
}
if (version != 0) {
@@ -2697,28 +2723,45 @@ status_t MPEG4Source::parseSampleAuxilia
mDataSource->readAt(offset, mCurrentSampleInfoSizes, smplcnt);
return OK;
}
status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size) {
ALOGV("parseSampleAuxiliaryInformationOffsets");
// 14496-12 8.7.13
+
+ if (mCurrentSamples.isEmpty()) {
+ // XXX hack -- we haven't seen trun yet; defer parsing this box until
+ // after trun.
+ ALOGW("deferring processing of saio box");
+ AuxRange range;
+ range.mStart = offset;
+ range.mSize = size;
+ mDeferredSaio.add(range);
+ return OK;
+ }
+
uint8_t version;
if (mDataSource->readAt(offset, &version, sizeof(version)) != 1) {
return ERROR_IO;
}
offset++;
uint32_t flags;
if (!mDataSource->getUInt24(offset, &flags)) {
return ERROR_IO;
}
offset += 3;
+ if (flags & 1) {
+ // Skip uint32s aux_info_type and aux_info_type_parameter
+ offset += 8;
+ }
+
uint32_t entrycount;
if (!mDataSource->getUInt32(offset, &entrycount)) {
return ERROR_IO;
}
offset += 4;
if (entrycount > mCurrentSampleInfoOffsetsAllocSize) {
mCurrentSampleInfoOffsets = (uint64_t*) realloc(mCurrentSampleInfoOffsets, entrycount * 8);
@@ -3091,16 +3134,23 @@ status_t MPEG4Source::parseTrackFragment
tmp.ctsOffset = sampleCtsOffset;
mCurrentSamples.add(tmp);
dataOffset += sampleSize;
}
mTrackFragmentHeaderInfo.mDataOffset = dataOffset;
+ for (size_t i = 0; i < mDeferredSaio.size() && i < mDeferredSaiz.size(); i++) {
+ const auto& saio = mDeferredSaio[i];
+ const auto& saiz = mDeferredSaiz[i];
+ parseSampleAuxiliaryInformationSizes(saiz.mStart, saiz.mSize);
+ parseSampleAuxiliaryInformationOffsets(saio.mStart, saio.mSize);
+ }
+
return OK;
}
sp<MetaData> MPEG4Source::getFormat() {
Mutex::Autolock autoLock(mLock);
return mFormat;
}
@@ -3533,16 +3583,18 @@ status_t MPEG4Source::fragmentedRead(
}
break;
}
totalTime += se->mDurationUs;
totalOffset += se->mSize;
}
mCurrentMoofOffset = totalOffset;
mCurrentSamples.clear();
+ mDeferredSaio.clear();
+ mDeferredSaiz.clear();
mCurrentSampleIndex = 0;
mTrackFragmentData.mPresent = false;
parseChunk(&totalOffset);
mCurrentTime = totalTime * mTimescale / 1000000ll;
if (mTrackFragmentData.mPresent) {
mCurrentTime += mTrackFragmentData.mBaseMediaDecodeTime;
}
}
@@ -3564,16 +3616,18 @@ status_t MPEG4Source::fragmentedRead(
bool newBuffer = false;
if (mBuffer == NULL) {
newBuffer = true;
if (mCurrentSampleIndex >= mCurrentSamples.size()) {
// move to next fragment
off64_t nextMoof = mNextMoofOffset; // lastSample.offset + lastSample.size;
mCurrentSamples.clear();
+ mDeferredSaio.clear();
+ mDeferredSaiz.clear();
mCurrentSampleIndex = 0;
mTrackFragmentData.mPresent = false;
uint32_t hdr[2];
do {
if (mDataSource->readAt(nextMoof, hdr, 8) < 8) {
return ERROR_END_OF_STREAM;
}
uint64_t chunk_size = ntohl(hdr[0]);