Bug 1195073: [webm] P2. Add WebMBufferedState::GetLastBlockOffset method. r=kinetik a=ritu
☠☠ backed out by 5bb661db5c6c ☠ ☠
authorJean-Yves Avenard <jyavenard@mozilla.com>
Wed, 19 Aug 2015 15:22:31 +1000
changeset 288979 d2ed0c5abd35f821508afe5097394c9824ce7eb3
parent 288978 73daa8e4568dff87d1e8c488d9ab1278c3d9e578
child 288980 efb94d2f8b6832edc408b5deb4d771316b195715
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik, ritu
bugs1195073
milestone42.0a2
Bug 1195073: [webm] P2. Add WebMBufferedState::GetLastBlockOffset method. r=kinetik a=ritu MSE may input partial media segment, which could cause the WebMDemuxer and libnestegg to error upon encountering an incomplete block which can't be recovered from. this will allow to limit read to known complete blocks.
dom/media/webm/WebMBufferedParser.cpp
dom/media/webm/WebMBufferedParser.h
--- a/dom/media/webm/WebMBufferedParser.cpp
+++ b/dom/media/webm/WebMBufferedParser.cpp
@@ -187,17 +187,19 @@ void WebMBufferedParser::Append(const un
       }
       break;
     case SKIP_DATA:
       if (mSkipBytes) {
         uint32_t left = aLength - (p - aBuffer);
         left = std::min(left, mSkipBytes);
         p += left;
         mSkipBytes -= left;
-      } else {
+      }
+      if (!mSkipBytes) {
+        mBlockEndOffset = mCurrentOffset + (p - aBuffer);
         mState = mNextState;
       }
       break;
     case CHECK_INIT_FOUND:
       if (mSkipBytes) {
         uint32_t left = aLength - (p - aBuffer);
         left = std::min(left, mSkipBytes);
         p += left;
@@ -339,16 +341,23 @@ void WebMBufferedState::NotifyDataArrive
     if (mRangeParsers[i].mCurrentOffset >= mRangeParsers[i + 1].mStartOffset) {
       mRangeParsers[i + 1].mStartOffset = mRangeParsers[i].mStartOffset;
       mRangeParsers[i + 1].mInitEndOffset = mRangeParsers[i].mInitEndOffset;
       mRangeParsers.RemoveElementAt(i);
     } else {
       i += 1;
     }
   }
+
+  if (mRangeParsers.IsEmpty()) {
+    return;
+  }
+
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  mLastBlockOffset = mRangeParsers.LastElement().mBlockEndOffset;
 }
 
 void WebMBufferedState::Reset() {
   mRangeParsers.Clear();
   mTimeMapping.Clear();
 }
 
 void WebMBufferedState::UpdateIndex(const nsTArray<MediaByteRange>& aRanges, MediaResource* aResource)
@@ -393,16 +402,23 @@ void WebMBufferedState::UpdateIndex(cons
 int64_t WebMBufferedState::GetInitEndOffset()
 {
   if (mRangeParsers.IsEmpty()) {
     return -1;
   }
   return mRangeParsers[0].mInitEndOffset;
 }
 
+int64_t WebMBufferedState::GetLastBlockOffset()
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+
+  return mLastBlockOffset;
+}
+
 bool WebMBufferedState::GetStartTime(uint64_t *aTime)
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
   if (mTimeMapping.IsEmpty()) {
     return false;
   }
 
--- a/dom/media/webm/WebMBufferedParser.h
+++ b/dom/media/webm/WebMBufferedParser.h
@@ -42,19 +42,25 @@ struct WebMTimeDataOffset
 // 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.
 struct WebMBufferedParser
 {
   explicit WebMBufferedParser(int64_t aOffset)
-    : mStartOffset(aOffset), mCurrentOffset(aOffset), mInitEndOffset(-1),
-      mState(READ_ELEMENT_ID), mVIntRaw(false), mClusterSyncPos(0),
-      mTimecodeScale(1000000), mGotTimecodeScale(false)
+    : mStartOffset(aOffset)
+    , mCurrentOffset(aOffset)
+    , mInitEndOffset(-1)
+    , mBlockEndOffset(-1)
+    , mState(READ_ELEMENT_ID)
+    , mVIntRaw(false)
+    , mClusterSyncPos(0)
+    , mTimecodeScale(1000000)
+    , mGotTimecodeScale(false)
   {
     if (mStartOffset != 0) {
       mState = FIND_CLUSTER_SYNC;
     }
   }
 
   uint32_t GetTimecodeScale() {
     MOZ_ASSERT(mGotTimecodeScale);
@@ -91,16 +97,20 @@ struct WebMBufferedParser
   // Current offset with the stream.  Updated in chunks as Append() consumes
   // data.
   int64_t mCurrentOffset;
 
   // Tracks element's end offset. This indicates the end of the init segment.
   // Will only be set if a Segment Information has been found.
   int64_t mInitEndOffset;
 
+  // End offset of the last block.
+  // Will only be set if a full block has been parsed.
+  int64_t mBlockEndOffset;
+
 private:
   enum State {
     // Parser start state.  Expects to begin at a valid EBML element.  Move
     // to READ_VINT with mVIntRaw true, then return to READ_ELEMENT_SIZE.
     READ_ELEMENT_ID,
 
     // Store element ID read into mVInt into mElement.mID.  Move to
     // READ_VINT with mVIntRaw false, then return to PARSE_ELEMENT.
@@ -220,52 +230,59 @@ private:
   bool mGotTimecodeScale;
 };
 
 class WebMBufferedState final
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebMBufferedState)
 
 public:
-  WebMBufferedState() : mReentrantMonitor("WebMBufferedState") {
+  WebMBufferedState()
+    : mReentrantMonitor("WebMBufferedState")
+    , mLastBlockOffset(-1)
+  {
     MOZ_COUNT_CTOR(WebMBufferedState);
   }
 
   void NotifyDataArrived(const unsigned char* aBuffer, uint32_t aLength, int64_t aOffset);
   void Reset();
   void UpdateIndex(const nsTArray<MediaByteRange>& aRanges, MediaResource* aResource);
   bool CalculateBufferedForRange(int64_t aStartOffset, int64_t aEndOffset,
                                  uint64_t* aStartTime, uint64_t* aEndTime);
 
   // Returns true if aTime is is present in mTimeMapping and sets aOffset to
   // the latest offset for which decoding can resume without data
   // dependencies to arrive at aTime.
   bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset);
 
   // Returns end offset of init segment or -1 if none found.
   int64_t GetInitEndOffset();
+  // Returns the end offset of the last complete block or -1 if none found.
+  int64_t GetLastBlockOffset();
 
   // Returns start time
   bool GetStartTime(uint64_t *aTime);
 
   // Returns keyframe for time
   bool GetNextKeyframeTime(uint64_t aTime, uint64_t* aKeyframeTime);
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   ~WebMBufferedState() {
     MOZ_COUNT_DTOR(WebMBufferedState);
   }
 
-  // Synchronizes access to the mTimeMapping array.
+  // Synchronizes access to the mTimeMapping array and mLastBlockOffset.
   ReentrantMonitor mReentrantMonitor;
 
   // Sorted (by offset) map of data offsets to timecodes.  Populated
   // on the main thread as data is received and parsed by WebMBufferedParsers.
   nsTArray<WebMTimeDataOffset> mTimeMapping;
+  // The last complete block parsed. -1 if not set.
+  int64_t mLastBlockOffset;
 
   // Sorted (by offset) live parser instances.  Main thread only.
   nsTArray<WebMBufferedParser> mRangeParsers;
 };
 
 } // namespace mozilla
 
 #endif