Bug 1119456 - Work around the fact that media cache does not quite guarantee the property we want. r=roc, a=sledru
authorBobby Holley <bobbyholley@gmail.com>
Sun, 11 Jan 2015 13:24:26 -0800
changeset 242850 18f7174682d3
parent 242849 fa0128cdef95
child 242851 23f5b373f676
push id4321
push userryanvm@gmail.com
push date2015-01-14 15:04 +0000
treeherdermozilla-beta@a78eb4dd84f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, sledru
bugs1119456
milestone36.0
Bug 1119456 - Work around the fact that media cache does not quite guarantee the property we want. r=roc, a=sledru
dom/media/fmp4/MP4Reader.cpp
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -87,20 +87,38 @@ InvokeAndRetry(ThisType* aThisVal, Retur
     if (result) {
       return result;
     }
     MP4Stream::ReadRecord failure(-1, 0);
     if (!stream->LastReadFailed(&failure) || failure == prevFailure) {
       return result;
     }
     prevFailure = failure;
-    nsAutoArrayPtr<uint8_t> dummyBuffer(new uint8_t[failure.mCount]);
+
+    // Our goal here is to forcibly read the data we want into the cache: since
+    // the stream is pinned, the data is guaranteed to stay in the cache once
+    // it's there, which means that retrying the non-blocking read from inside
+    // the demuxer should succeed.
+    //
+    // But there's one wrinkle: if we read less than an entire cache line and
+    // the data ends up in MediaCacheStream's mPartialBlockBuffer, the data can
+    // be returned by a blocking read but never actually committed to the cache,
+    // and abandoned by a subsequent seek (possibly by another stream accessing
+    // the same underlying resource).
+    //
+    // The way to work around this problem is to round our "priming" read up to the
+    // size of an entire cache block. Note that this may hit EOS for bytes that the
+    // original demuxer read never actually requested. This is OK though because the
+    // call to BlockingReadAt will still return true (just with a less-than-expected
+    // number of actually read bytes, which we ignore).
+    size_t bufferSize = failure.mCount + (MediaCacheStream::BLOCK_SIZE - failure.mCount % MediaCacheStream::BLOCK_SIZE);
+    nsAutoArrayPtr<uint8_t> dummyBuffer(new uint8_t[bufferSize]);
+    MonitorAutoUnlock unlock(*aMonitor);
     size_t ignored;
-    MonitorAutoUnlock unlock(*aMonitor);
-    if (!stream->BlockingReadAt(failure.mOffset, dummyBuffer, failure.mCount, &ignored)) {
+    if (NS_WARN_IF(!stream->BlockingReadAt(failure.mOffset, dummyBuffer, bufferSize, &ignored))) {
       return result;
     }
   }
 }
 
 
 MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
   : MediaDecoderReader(aDecoder)