Bug 1203367: Ensure WebMBufferedState is only used after reading metadata. r=kinetik
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 14 Sep 2015 15:01:01 +1000
changeset 294892 c93cd72f8d4057f536fd87cda8088828bd1bd5ef
parent 294891 e768739ec8121d115a722df1e6af328f5b6483ca
child 294893 849943de58017e76de754f34a3eca9a33e8a3d53
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1203367
milestone43.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 1203367: Ensure WebMBufferedState is only used after reading metadata. r=kinetik We also now limit the use of the WebMBufferedState for calculating the buffered range and seeking on buffered data.
dom/media/webm/WebMDemuxer.cpp
dom/media/webm/WebMDemuxer.h
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -156,48 +156,43 @@ WebMDemuxer::~WebMDemuxer()
 {
   Reset();
   Cleanup();
 }
 
 nsRefPtr<WebMDemuxer::InitPromise>
 WebMDemuxer::Init()
 {
-  if (InitBufferedState() != NS_OK) {
-    return InitPromise::CreateAndReject(DemuxerFailureReason::WAITING_FOR_DATA, __func__);
-  }
-  if (ReadMetadata() != NS_OK) {
+  InitBufferedState();
+
+  if (NS_FAILED(ReadMetadata())) {
     return InitPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__);
   }
 
   if (!GetNumberTracks(TrackInfo::kAudioTrack) &&
       !GetNumberTracks(TrackInfo::kVideoTrack)) {
     return InitPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__);
   }
 
   return InitPromise::CreateAndResolve(NS_OK, __func__);
 }
 
-nsresult
+void
 WebMDemuxer::InitBufferedState()
 {
-  if(!mBufferedState) {
-    mBufferedState = new WebMBufferedState;
-  }
-  EnsureUpToDateIndex();
-  return NS_OK;
+  MOZ_ASSERT(!mBufferedState);
+  mBufferedState = new WebMBufferedState;
 }
 
 already_AddRefed<MediaDataDemuxer>
 WebMDemuxer::Clone() const
 {
   nsRefPtr<WebMDemuxer> demuxer = new WebMDemuxer(mResource.GetResource());
-  demuxer->mInitData = mInitData;
-  if (demuxer->InitBufferedState() != NS_OK ||
-      demuxer->ReadMetadata() != NS_OK) {
+  demuxer->InitBufferedState();
+  if (NS_FAILED(demuxer->ReadMetadata())) {
     NS_WARNING("Couldn't recreate WebMDemuxer");
     return nullptr;
   }
   return demuxer.forget();
 }
 
 bool
 WebMDemuxer::HasTrackType(TrackInfo::TrackType aType) const
@@ -266,22 +261,36 @@ WebMDemuxer::Cleanup()
 nsresult
 WebMDemuxer::ReadMetadata()
 {
   nestegg_io io;
   io.read = webmdemux_read;
   io.seek = webmdemux_seek;
   io.tell = webmdemux_tell;
   io.userdata = this;
-  int64_t maxOffset = mBufferedState->GetInitEndOffset();
-  if (maxOffset == -1) {
-    maxOffset = mResource.GetLength();
+  int r = nestegg_init(&mContext, io, &webmdemux_log,
+                       IsMediaSource() ? mResource.GetLength() : -1);
+  if (r == -1) {
+    return NS_ERROR_FAILURE;
   }
-  int r = nestegg_init(&mContext, io, &webmdemux_log, maxOffset);
-  if (r == -1) {
+  {
+    // Check how much data nestegg read and force feed it to BufferedState.
+    nsRefPtr<MediaByteBuffer> buffer = mResource.MediaReadAt(0, mResource.Tell());
+    if (!buffer) {
+      return NS_ERROR_FAILURE;
+    }
+    mBufferedState->NotifyDataArrived(buffer->Elements(), buffer->Length(), 0);
+    if (mBufferedState->GetInitEndOffset() < 0) {
+      return NS_ERROR_FAILURE;
+    }
+    MOZ_ASSERT(mBufferedState->GetInitEndOffset() <= mResource.Tell());
+  }
+  mInitData = mResource.MediaReadAt(0, mBufferedState->GetInitEndOffset());
+  if (!mInitData ||
+      mInitData->Length() != size_t(mBufferedState->GetInitEndOffset())) {
     return NS_ERROR_FAILURE;
   }
 
   unsigned int ntracks = 0;
   r = nestegg_track_count(mContext, &ntracks);
   if (r == -1) {
     return NS_ERROR_FAILURE;
   }
@@ -438,32 +447,27 @@ bool
 WebMDemuxer::IsSeekable() const
 {
   return mContext && nestegg_has_cues(mContext);
 }
 
 void
 WebMDemuxer::EnsureUpToDateIndex()
 {
-  if (!mNeedReIndex) {
+  if (!mNeedReIndex || !mInitData) {
     return;
   }
-  if (mInitData && mBufferedState->GetInitEndOffset() == -1) {
-    mBufferedState->NotifyDataArrived(mInitData->Elements(), mInitData->Length(), 0);
-  }
   AutoPinned<MediaResource> resource(mResource.GetResource());
   nsTArray<MediaByteRange> byteRanges;
   nsresult rv = resource->GetCachedRanges(byteRanges);
   if (NS_FAILED(rv) || !byteRanges.Length()) {
     return;
   }
   mBufferedState->UpdateIndex(byteRanges, resource);
-  if (!mInitData && mBufferedState->GetInitEndOffset() != -1) {
-    mInitData = mResource.MediaReadAt(0, mBufferedState->GetInitEndOffset());
-  }
+
   mNeedReIndex = false;
 
   if (!mIsMediaSource) {
     return;
   }
   mLastWebMBlockOffset = mBufferedState->GetLastBlockOffset();
   MOZ_ASSERT(mLastWebMBlockOffset <= mResource.GetLength());
 }
@@ -474,29 +478,33 @@ WebMDemuxer::NotifyDataArrived(uint32_t 
   WEBM_DEBUG("length: %ld offset: %ld", aLength, aOffset);
   mNeedReIndex = true;
 }
 
 void
 WebMDemuxer::NotifyDataRemoved()
 {
   mBufferedState->Reset();
+  if (mInitData) {
+    mBufferedState->NotifyDataArrived(mInitData->Elements(), mInitData->Length(), 0);
+  }
   mNeedReIndex = true;
 }
 
 UniquePtr<EncryptionInfo>
 WebMDemuxer::GetCrypto()
 {
   return nullptr;
 }
 
 bool
 WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples)
 {
   if (mIsMediaSource) {
+    // To ensure mLastWebMBlockOffset is properly up to date.
     EnsureUpToDateIndex();
   }
 
   nsRefPtr<NesteggPacketHolder> holder(NextPacket(aType));
 
   if (!holder) {
     return false;
   }
--- a/dom/media/webm/WebMDemuxer.h
+++ b/dom/media/webm/WebMDemuxer.h
@@ -125,17 +125,17 @@ public:
     return mIsMediaSource;
   }
 
 private:
   friend class WebMTrackDemuxer;
 
   ~WebMDemuxer();
   void Cleanup();
-  nsresult InitBufferedState();
+  void InitBufferedState();
   nsresult ReadMetadata();
   void NotifyDataArrived(uint32_t aLength, int64_t aOffset) override;
   void NotifyDataRemoved() override;
   void EnsureUpToDateIndex();
   media::TimeIntervals GetBuffered();
   virtual nsresult SeekInternal(const media::TimeUnit& aTarget);
 
   // Read a packet from the nestegg file. Returns nullptr if all packets for