Bug 1044498 - Fix a bunch of WebM buffered range bugs. r=cajbir
authorMatthew Gregan <kinetik@flim.org>
Tue, 26 Aug 2014 18:23:02 +1200
changeset 223930 adcb3f7a437bc42c4bc2595e07649ffecb0b2a54
parent 223929 676e7fc0984e5e7748a8466ef0c3260ba7c2932a
child 223931 e50fd1470da5d512a905d0934e705abddbf06451
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscajbir
bugs1044498
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 1044498 - Fix a bunch of WebM buffered range bugs. r=cajbir
content/media/webm/WebMBufferedParser.cpp
content/media/webm/WebMReader.cpp
--- a/content/media/webm/WebMBufferedParser.cpp
+++ b/content/media/webm/WebMBufferedParser.cpp
@@ -179,26 +179,42 @@ void WebMBufferedParser::Append(const un
       break;
     }
   }
 
   NS_ASSERTION(p == aBuffer + aLength, "Must have parsed to end of data.");
   mCurrentOffset += aLength;
 }
 
+// SyncOffsetComparator and TimeComparator are slightly confusing, in that
+// the nsTArray they're used with (mTimeMapping) is sorted by mEndOffset and
+// these comparators are used on the other fields of WebMTimeDataOffset.
+// This is only valid because timecodes are required to be monotonically
+// increasing within a file (thus establishing an ordering relationship with
+// mTimecode), and mEndOffset is derived from mSyncOffset.
 struct SyncOffsetComparator {
   bool Equals(const WebMTimeDataOffset& a, const int64_t& b) const {
     return a.mSyncOffset == b;
   }
 
   bool LessThan(const WebMTimeDataOffset& a, const int64_t& b) const {
     return a.mSyncOffset < b;
   }
 };
 
+struct TimeComparator {
+  bool Equals(const WebMTimeDataOffset& a, const uint64_t& b) const {
+    return a.mTimecode == b;
+  }
+
+  bool LessThan(const WebMTimeDataOffset& a, const uint64_t& b) const {
+    return a.mTimecode < b;
+  }
+};
+
 bool WebMBufferedState::CalculateBufferedForRange(int64_t aStartOffset, int64_t aEndOffset,
                                                   uint64_t* aStartTime, uint64_t* aEndTime)
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
   // Find the first WebMTimeDataOffset at or after aStartOffset.
   uint32_t start = mTimeMapping.IndexOfFirstElementGt(aStartOffset - 1, SyncOffsetComparator());
   if (start == mTimeMapping.Length()) {
@@ -232,26 +248,27 @@ bool WebMBufferedState::CalculateBuffere
   *aStartTime = mTimeMapping[start].mTimecode;
   *aEndTime = mTimeMapping[end].mTimecode + frameDuration;
   return true;
 }
 
 bool WebMBufferedState::GetOffsetForTime(uint64_t aTime, int64_t* aOffset)
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-  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;
-    }
+  uint64_t time = aTime;
+  if (time > 0) {
+    time = time - 1;
+  }
+  uint32_t idx = mTimeMapping.IndexOfFirstElementGt(time, TimeComparator());
+  if (idx == mTimeMapping.Length()) {
+    return false;
   }
 
-  *aOffset = result.mSyncOffset;
+  *aOffset = mTimeMapping[idx].mSyncOffset;
   return true;
 }
 
 void WebMBufferedState::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   uint32_t idx = mRangeParsers.IndexOfFirstElementGt(aOffset - 1);
   if (idx == 0 || !(mRangeParsers[idx-1] == aOffset)) {
--- a/content/media/webm/WebMReader.cpp
+++ b/content/media/webm/WebMReader.cpp
@@ -993,35 +993,38 @@ WebMReader::PushVideoPacket(NesteggPacke
 }
 
 nsresult WebMReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime,
                           int64_t aCurrentTime)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
 
   LOG(PR_LOG_DEBUG, ("Reader [%p] for Decoder [%p]: About to seek to %fs",
-                     this, mDecoder, aTarget/1000000.0));
+                     this, mDecoder, double(aTarget) / USECS_PER_S));
   if (NS_FAILED(ResetDecode())) {
     return NS_ERROR_FAILURE;
   }
   uint32_t trackToSeek = mHasVideo ? mVideoTrack : mAudioTrack;
   uint64_t target = aTarget * NS_PER_USEC;
+
   if (mSeekPreroll) {
     target = std::max(static_cast<uint64_t>(aStartTime * NS_PER_USEC), target - mSeekPreroll);
   }
   int r = nestegg_track_seek(mContext, trackToSeek, target);
   if (r != 0) {
     // Try seeking directly based on cluster information in memory.
     int64_t offset = 0;
-    bool rv = mBufferedState->GetOffsetForTime((aTarget - aStartTime)/NS_PER_USEC, &offset);
+    bool rv = mBufferedState->GetOffsetForTime(target, &offset);
     if (!rv) {
       return NS_ERROR_FAILURE;
     }
 
     r = nestegg_offset_seek(mContext, offset);
+    LOG(PR_LOG_DEBUG, ("Reader [%p]: track_seek for %u failed, offset_seek to %lld r=%d",
+                       this, trackToSeek, offset, r));
     if (r != 0) {
       return NS_ERROR_FAILURE;
     }
   }
   return NS_OK;
 }
 
 nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
@@ -1074,16 +1077,16 @@ nsresult WebMReader::GetBuffered(dom::Ti
 void WebMReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
 {
   mBufferedState->NotifyDataArrived(aBuffer, aLength, aOffset);
 }
 
 int64_t WebMReader::GetEvictionOffset(double aTime)
 {
   int64_t offset;
-  if (!mBufferedState->GetOffsetForTime(aTime / NS_PER_USEC, &offset)) {
+  if (!mBufferedState->GetOffsetForTime(aTime * NS_PER_S, &offset)) {
     return -1;
   }
 
   return offset;
 }
 
 } // namespace mozilla