Bug 1059049 - Defer parsing of saio/saiz boxes until after trun - r=ajones
authorEdwin Flores <eflores@mozilla.com>
Tue, 14 Oct 2014 11:04:59 +1300
changeset 210244 6dc9dc5e1b73cdd5ad704ecfbbfeb1fa1e32b903
parent 210243 85634997827efd7a5b330b27f1b48f7f2d806be5
child 210245 eedb87c0217fa335826f123ac46d12714b865477
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersajones
bugs1059049
milestone35.0a1
Bug 1059049 - Defer parsing of saio/saiz boxes until after trun - r=ajones
media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
--- 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]);