Bug 1050083 - Changes to WebM buffered range handling. r=cajbir
authorMatthew Gregan <kinetik@flim.org>
Mon, 11 Aug 2014 14:05:09 +1200
changeset 198819 1588a78a2feb61322a212cf55658ec6a4f3a6a7d
parent 198818 a3ce4466a3daa2d76cd218bdc2831b994c1fa35a
child 198820 c9c9e94945fe7bddadca0f20bcf79aab66cd57a5
push id27286
push usernigelbabu@gmail.com
push dateMon, 11 Aug 2014 06:26:45 +0000
treeherdermozilla-central@8c4a1b3a2a8b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscajbir
bugs1050083
milestone34.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 1050083 - Changes to WebM buffered range handling. r=cajbir Include the frame duration in the range end. Also handle (ignore) invalid negative timestamps when parsing. Include cluster offset in time/data offset record. Cluster offset will be used when calculating discard/resync points in MSE.
content/media/webm/WebMBufferedParser.cpp
content/media/webm/WebMBufferedParser.h
--- a/content/media/webm/WebMBufferedParser.cpp
+++ b/content/media/webm/WebMBufferedParser.cpp
@@ -27,18 +27,18 @@ VIntLength(unsigned char aFirstByte, uin
   if (aMask) {
     *aMask = mask;
   }
   NS_ASSERTION(count >= 1 && count <= 8, "Insane VInt length.");
   return count;
 }
 
 void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
-                                  nsTArray<WebMTimeDataOffset>& aMapping,
-                                  ReentrantMonitor& aReentrantMonitor)
+                                nsTArray<WebMTimeDataOffset>& aMapping,
+                                ReentrantMonitor& aReentrantMonitor)
 {
   static const unsigned char CLUSTER_ID[] = { 0x1f, 0x43, 0xb6, 0x75 };
   static const unsigned char TIMECODE_ID = 0xe7;
   static const unsigned char BLOCKGROUP_ID = 0xa0;
   static const unsigned char BLOCK_ID = 0xa1;
   static const unsigned char SIMPLEBLOCK_ID = 0xa3;
 
   const unsigned char* p = aBuffer;
@@ -55,16 +55,17 @@ void WebMBufferedParser::Append(const un
       } else {
         mClusterIDPos = 0;
       }
       // Cluster ID found, it's likely this is a valid sync point.  If this
       // is a spurious match, the later parse steps will encounter an error
       // and return to CLUSTER_SYNC.
       if (mClusterIDPos == sizeof(CLUSTER_ID)) {
         mClusterIDPos = 0;
+        mClusterOffset = mCurrentOffset + (p - aBuffer) - 1;
         mState = READ_VINT;
         mNextState = TIMECODE_SYNC;
       }
       break;
     case READ_VINT: {
       unsigned char c = *p++;
       uint32_t mask;
       mVIntLength = VIntLength(c, &mask);
@@ -135,19 +136,24 @@ void WebMBufferedParser::Append(const un
         mBlockTimecode |= *p++;
         mBlockTimecodeLength -= 1;
       } else {
         // It's possible we've parsed this data before, so avoid inserting
         // duplicate WebMTimeDataOffset entries.
         {
           ReentrantMonitorAutoEnter mon(aReentrantMonitor);
           uint32_t idx = aMapping.IndexOfFirstElementGt(mBlockOffset);
-          if (idx == 0 || !(aMapping[idx-1] == mBlockOffset)) {
-            WebMTimeDataOffset entry(mBlockOffset, mClusterTimecode + mBlockTimecode);
-            aMapping.InsertElementAt(idx, entry);
+          if (idx == 0 || !(aMapping[idx - 1] == mBlockOffset)) {
+            // Don't insert invalid negative timecodes.
+            if (mBlockOffset > 0 || mClusterTimecode > uint16_t(abs(mBlockOffset))) {
+              WebMTimeDataOffset entry(mBlockOffset,
+                                       mClusterTimecode + mBlockTimecode,
+                                       mClusterOffset);
+              aMapping.InsertElementAt(idx, entry);
+            }
           }
         }
 
         // Skip rest of block header and the block's payload.
         mBlockSize -= mVIntLength;
         mBlockSize -= 2;
         mSkipBytes = uint32_t(mBlockSize);
         mState = SKIP_DATA;
@@ -172,28 +178,28 @@ void WebMBufferedParser::Append(const un
     }
   }
 
   NS_ASSERTION(p == aBuffer + aLength, "Must have parsed to end of data.");
   mCurrentOffset += aLength;
 }
 
 bool WebMBufferedState::CalculateBufferedForRange(int64_t aStartOffset, int64_t aEndOffset,
-                                                    uint64_t* aStartTime, uint64_t* aEndTime)
+                                                  uint64_t* aStartTime, uint64_t* aEndTime)
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
   // Find the first WebMTimeDataOffset at or after aStartOffset.
-  uint32_t start = mTimeMapping.IndexOfFirstElementGt(aStartOffset-1);
+  uint32_t start = mTimeMapping.IndexOfFirstElementGt(aStartOffset - 1);
   if (start == mTimeMapping.Length()) {
     return false;
   }
 
   // Find the first WebMTimeDataOffset at or before aEndOffset.
-  uint32_t end = mTimeMapping.IndexOfFirstElementGt(aEndOffset-1);
+  uint32_t end = mTimeMapping.IndexOfFirstElementGt(aEndOffset - 1);
   if (end > 0) {
     end -= 1;
   }
 
   // Range is empty.
   if (end <= start) {
     return false;
   }
@@ -211,23 +217,24 @@ bool WebMBufferedState::CalculateBuffere
   }
 
   // The timestamp of the first media sample, in ns. We must subtract this
   // from the ranges' start and end timestamps, so that those timestamps are
   // normalized in the range [0,duration].
 
   *aStartTime = mTimeMapping[start].mTimecode;
   *aEndTime = mTimeMapping[end].mTimecode;
+  *aEndTime += mTimeMapping[end].mTimecode - mTimeMapping[end - 1].mTimecode;
   return true;
 }
 
 bool WebMBufferedState::GetOffsetForTime(uint64_t aTime, int64_t* aOffset)
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-  WebMTimeDataOffset result(0,0);
+  WebMTimeDataOffset result(0, 0, 0);
 
   for (uint32_t i = 0; i < mTimeMapping.Length(); ++i) {
     WebMTimeDataOffset o = mTimeMapping[i];
     if (o.mTimecode < aTime && o.mTimecode > result.mTimecode) {
       result = o;
     }
   }
 
--- a/content/media/webm/WebMBufferedParser.h
+++ b/content/media/webm/WebMBufferedParser.h
@@ -16,30 +16,31 @@ namespace dom {
 class TimeRanges;
 }
 
 // Stores a stream byte offset and the scaled timecode of the block at
 // that offset.  The timecode must be scaled by the stream's timecode
 // scale before use.
 struct WebMTimeDataOffset
 {
-  WebMTimeDataOffset(int64_t aOffset, uint64_t aTimecode)
-    : mOffset(aOffset), mTimecode(aTimecode)
+  WebMTimeDataOffset(int64_t aOffset, uint64_t aTimecode, int64_t aSyncOffset)
+    : mOffset(aOffset), mTimecode(aTimecode), mSyncOffset(aSyncOffset)
   {}
 
   bool operator==(int64_t aOffset) const {
     return mOffset == aOffset;
   }
 
   bool operator<(int64_t aOffset) const {
     return mOffset < aOffset;
   }
 
   int64_t mOffset;
   uint64_t mTimecode;
+  int64_t mSyncOffset;
 };
 
 // A simple WebM parser that produces data offset to timecode pairs as it
 // consumes blocks.  A new parser is created for each distinct range of data
 // received and begins parsing from the first WebM cluster within that
 // range.  Old parsers are destroyed when their range merges with a later
 // parser or an already parsed range.  The parser may start at any position
 // within the stream.
@@ -160,16 +161,21 @@ private:
 
   // Size of the block currently being parsed.  Any unused data within the
   // block is skipped once the block timecode has been parsed.
   uint64_t mBlockSize;
 
   // Cluster-level timecode.
   uint64_t mClusterTimecode;
 
+  // Start offset of the cluster currently being parsed.  Used as the sync
+  // point offset for the offset-to-time mapping as each block timecode is
+  // been parsed.
+  int64_t mClusterOffset;
+
   // Start offset of the block currently being parsed.  Used as the byte
   // offset for the offset-to-time mapping once the block timecode has been
   // parsed.
   int64_t mBlockOffset;
 
   // Block-level timecode.  This is summed with mClusterTimecode to produce
   // an absolute timecode for the offset-to-time mapping.
   int16_t mBlockTimecode;