Bug 1098990 - Correctly parse version 1 trun segments where the composition time is signed. r=ajones
authorMatt Woodrow <mwoodrow@mozilla.com>
Mon, 17 Nov 2014 15:30:02 +1300
changeset 240270 5492e9dc06f1f9d006a7ecdae12f6f9c28087b32
parent 240269 495cec2bc029eac35665c4ca0811a52618b9b1c8
child 240271 53ebcaa07a4bad42711a1853716dfdba0124198f
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersajones
bugs1098990
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1098990 - Correctly parse version 1 trun segments where the composition time is signed. r=ajones
media/libstagefright/binding/MoofParser.cpp
media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
--- a/media/libstagefright/binding/MoofParser.cpp
+++ b/media/libstagefright/binding/MoofParser.cpp
@@ -169,16 +169,17 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, 
 
   BoxReader reader(aBox);
   uint32_t flags = reader->ReadU32();
   if ((flags & 0x404) == 0x404) {
     // Can't use these flags together
     reader->DiscardRemaining();
     return;
   }
+  uint8_t version = flags >> 24;
 
   uint32_t sampleCount = reader->ReadU32();
   if (sampleCount == 0) {
     return;
   }
 
   uint64_t offset = aTfhd.mBaseDataOffset + (flags & 1 ? reader->ReadU32() : 0);
   bool hasFirstSampleFlags = flags & 4;
@@ -189,17 +190,24 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, 
     uint32_t sampleDuration =
       flags & 0x100 ? reader->ReadU32() : aTfhd.mDefaultSampleDuration;
     uint32_t sampleSize =
       flags & 0x200 ? reader->ReadU32() : aTfhd.mDefaultSampleSize;
     uint32_t sampleFlags =
       flags & 0x400 ? reader->ReadU32() : hasFirstSampleFlags && i == 0
                                             ? firstSampleFlags
                                             : aTfhd.mDefaultSampleFlags;
-    uint32_t ctsOffset = flags & 0x800 ? reader->ReadU32() : 0;
+    int64_t ctsOffset = 0;
+    if (flags & 0x800) {
+      if (version == 0) {
+        ctsOffset = reader->ReadU32();
+      } else {
+        ctsOffset = reader->Read32();
+      }
+    }
 
     Sample sample;
     sample.mByteRange = MediaByteRange(offset, offset + sampleSize);
     offset += sampleSize;
 
     sample.mCompositionRange = Interval<Microseconds>(
       aMdhd.ToMicroseconds(decodeTime + ctsOffset),
       aMdhd.ToMicroseconds(decodeTime + ctsOffset + sampleDuration));
--- a/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
@@ -71,16 +71,26 @@ public:
     auto ptr = Read(4);
     if (!ptr) {
       MOZ_ASSERT(false);
       return 0;
     }
     return mozilla::BigEndian::readUint32(ptr);
   }
 
+  int64_t Read32()
+  {
+    auto ptr = Read(4);
+    if (!ptr) {
+      MOZ_ASSERT(false);
+      return 0;
+    }
+    return mozilla::BigEndian::readInt32(ptr);
+  }
+
   uint64_t ReadU64()
   {
     auto ptr = Read(8);
     if (!ptr) {
       MOZ_ASSERT(false);
       return 0;
     }
     return mozilla::BigEndian::readUint64(ptr);
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -134,17 +134,17 @@ private:
         uint64_t mDataOffset;
     };
     TrackFragmentHeaderInfo mTrackFragmentHeaderInfo;
 
     struct Sample {
         off64_t offset;
         uint32_t size;
         uint32_t duration;
-        uint32_t ctsOffset;
+        int64_t ctsOffset;
         uint32_t flags;
         uint8_t iv[16];
         Vector<uint16_t> clearsizes;
         Vector<uint32_t> encryptedsizes;
 
         bool isSync() const { return !(flags & 0x1010000); }
     };
     Vector<Sample> mCurrentSamples;
@@ -2988,22 +2988,20 @@ status_t MPEG4Source::parseTrackFragment
         kSampleFlagsPresent                 = 0x400,
         kSampleCompositionTimeOffsetPresent = 0x800,
     };
 
     uint32_t flags;
     if (!mDataSource->getUInt32(offset, &flags)) {
         return ERROR_MALFORMED;
     }
+    uint8_t version = flags >> 24;
     ALOGV("fragment run flags: %08x", flags);
 
-    // Some videos have the 0x01000000 flag (unknown) present, and ignoring
-    // it doesn't appear to affect playerback. Assume other flags in the high
-    // byte are invalid.
-    if (flags & 0xfe000000) {
+    if (version > 1) {
         return -EINVAL;
     }
 
     if ((flags & kFirstSampleFlagsPresent) && (flags & kSampleFlagsPresent)) {
         // These two shall not be used together.
         return -EINVAL;
     }
 
@@ -3122,17 +3120,21 @@ status_t MPEG4Source::parseTrackFragment
                 dataOffset, sampleSize, sampleDuration,
                 (flags & kFirstSampleFlagsPresent) && i == 0
                     ? firstSampleFlags : sampleFlags);
         tmp.flags = (flags & kFirstSampleFlagsPresent) && i == 0
                 ? firstSampleFlags : sampleFlags;
         tmp.offset = dataOffset;
         tmp.size = sampleSize;
         tmp.duration = sampleDuration;
-        tmp.ctsOffset = sampleCtsOffset;
+        if (version == 0) {
+          tmp.ctsOffset = sampleCtsOffset;
+        } else {
+          tmp.ctsOffset = (int32_t)sampleCtsOffset;
+        }
         mCurrentSamples.add(tmp);
 
         dataOffset += sampleSize;
     }
 
     mTrackFragmentHeaderInfo.mDataOffset = dataOffset;
 
     for (size_t i = 0; i < mDeferredSaio.size() && i < mDeferredSaiz.size(); i++) {
@@ -3647,17 +3649,17 @@ status_t MPEG4Source::fragmentedRead(
         }
 
         // fall through
     }
 
     off64_t offset = 0;
     size_t size = 0;
     uint32_t dts = 0;
-    uint32_t cts = 0;
+    int64_t cts = 0;
     uint32_t duration = 0;
     bool isSyncSample = false;
     bool newBuffer = false;
     if (mBuffer == NULL) {
         newBuffer = true;
 
         if (mCurrentSampleIndex >= mCurrentSamples.size()) {
             // move to next fragment
@@ -3738,17 +3740,17 @@ status_t MPEG4Source::fragmentedRead(
             CHECK(mBuffer != NULL);
             mBuffer->set_range(0, size);
             if (!mTimescale) {
                 return ERROR_MALFORMED;
             }
             mBuffer->meta_data()->setInt64(
                     kKeyDecodingTime, ((int64_t)dts * 1000000) / mTimescale);
             mBuffer->meta_data()->setInt64(
-                    kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
+                    kKeyTime, (cts * 1000000) / mTimescale);
             mBuffer->meta_data()->setInt64(
                     kKeyDuration, ((int64_t)duration * 1000000) / mTimescale);
 
             if (targetSampleTimeUs >= 0) {
                 mBuffer->meta_data()->setInt64(
                         kKeyTargetTime, targetSampleTimeUs);
             }
 
@@ -3867,17 +3869,17 @@ status_t MPEG4Source::fragmentedRead(
         }
 
         if (!mTimescale) {
             return ERROR_MALFORMED;
         }
         mBuffer->meta_data()->setInt64(
                 kKeyDecodingTime, ((int64_t)dts * 1000000) / mTimescale);
         mBuffer->meta_data()->setInt64(
-                kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
+                kKeyTime, (cts * 1000000) / mTimescale);
         mBuffer->meta_data()->setInt64(
                 kKeyDuration, ((int64_t)duration * 1000000) / mTimescale);
 
         if (targetSampleTimeUs >= 0) {
             mBuffer->meta_data()->setInt64(
                     kKeyTargetTime, targetSampleTimeUs);
         }