Bug 1093880 - Delay decoder initialization until data has been appended. r=cajbir
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 06 Nov 2014 15:09:19 +1100
changeset 214365 06275a674a574b703405e51cdb710351f2c1bc36
parent 214364 71c607c0f4f2d4906d64700ee6e1a0459c1520cb
child 214366 df7d159e62250d512480c3dd22499a961f41607b
push id27780
push userkwierso@gmail.com
push dateFri, 07 Nov 2014 02:25:05 +0000
treeherdermozilla-central@e6d47abb6a7b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscajbir
bugs1093880
milestone36.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 1093880 - Delay decoder initialization until data has been appended. r=cajbir
dom/media/mediasource/TrackBuffer.cpp
dom/media/mediasource/TrackBuffer.h
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -63,16 +63,45 @@ public:
     mDecoder = nullptr;
     return NS_OK;
   }
 
 private:
   nsRefPtr<SourceBufferDecoder> mDecoder;
 };
 
+MOZ_STACK_CLASS class DecodersToInitialize MOZ_FINAL {
+public:
+  explicit DecodersToInitialize(TrackBuffer* aOwner)
+    : mOwner(aOwner)
+  {
+  }
+
+  ~DecodersToInitialize()
+  {
+    for (size_t i = 0; i < mDecoders.Length(); i++) {
+      mOwner->QueueInitializeDecoder(mDecoders[i]);
+    }
+  }
+
+  bool NewDecoder()
+  {
+    nsRefPtr<SourceBufferDecoder> decoder = mOwner->NewDecoder();
+    if (!decoder) {
+      return false;
+    }
+    mDecoders.AppendElement(decoder);
+    return true;
+  }
+
+private:
+  TrackBuffer* mOwner;
+  nsAutoTArray<nsRefPtr<SourceBufferDecoder>,2> mDecoders;
+};
+
 void
 TrackBuffer::Shutdown()
 {
   // Finish any decoder initialization, which may add to mInitializedDecoders.
   // Shutdown waits for any pending events, which may require the monitor,
   // so we must not hold the monitor during this call.
   mParentDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
   mTaskQueue->Shutdown();
@@ -85,37 +114,38 @@ TrackBuffer::Shutdown()
   mInitializedDecoders.Clear();
   mParentDecoder = nullptr;
 }
 
 bool
 TrackBuffer::AppendData(const uint8_t* aData, uint32_t aLength)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  DecodersToInitialize decoders(this);
   // TODO: Run more of the buffer append algorithm asynchronously.
   if (mParser->IsInitSegmentPresent(aData, aLength)) {
     MSE_DEBUG("TrackBuffer(%p)::AppendData: New initialization segment.", this);
-    if (!NewDecoder()) {
+    if (!decoders.NewDecoder()) {
       return false;
     }
   } else if (!mParser->HasInitData()) {
     MSE_DEBUG("TrackBuffer(%p)::AppendData: Non-init segment appended during initialization.", this);
     return false;
   }
 
   int64_t start, end;
   if (mParser->ParseStartAndEndTimestamps(aData, aLength, start, end)) {
     if (mParser->IsMediaSegmentPresent(aData, aLength) &&
         !mParser->TimestampsFuzzyEqual(start, mLastEndTimestamp)) {
       MSE_DEBUG("TrackBuffer(%p)::AppendData: Data last=[%lld, %lld] overlaps [%lld, %lld]",
                 this, mLastStartTimestamp, mLastEndTimestamp, start, end);
 
       // This data is earlier in the timeline than data we have already
       // processed, so we must create a new decoder to handle the decoding.
-      if (!NewDecoder()) {
+      if (!decoders.NewDecoder()) {
         return false;
       }
       MSE_DEBUG("TrackBuffer(%p)::AppendData: Decoder marked as initialized.", this);
       const nsTArray<uint8_t>& initData = mParser->InitData();
       AppendDataToCurrentResource(initData.Elements(), initData.Length());
       mLastStartTimestamp = start;
     }
     mLastEndTimestamp = end;
@@ -213,37 +243,37 @@ TrackBuffer::Buffered(dom::TimeRanges* a
       highestEndTime = std::max(highestEndTime, r->GetEndTime());
       aRanges->Union(r);
     }
   }
 
   return highestEndTime;
 }
 
-bool
+already_AddRefed<SourceBufferDecoder>
 TrackBuffer::NewDecoder()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mParentDecoder);
 
   DiscardDecoder();
 
   nsRefPtr<SourceBufferDecoder> decoder = mParentDecoder->CreateSubDecoder(mType);
   if (!decoder) {
-    return false;
+    return nullptr;
   }
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   mCurrentDecoder = decoder;
   mDecoders.AppendElement(decoder);
 
   mLastStartTimestamp = 0;
   mLastEndTimestamp = 0;
 
   decoder->SetTaskQueue(mTaskQueue);
-  return QueueInitializeDecoder(decoder);
+  return decoder.forget();
 }
 
 bool
 TrackBuffer::QueueInitializeDecoder(SourceBufferDecoder* aDecoder)
 {
   RefPtr<nsIRunnable> task =
     NS_NewRunnableMethodWithArg<SourceBufferDecoder*>(this,
                                                       &TrackBuffer::InitializeDecoder,
--- a/dom/media/mediasource/TrackBuffer.h
+++ b/dom/media/mediasource/TrackBuffer.h
@@ -77,22 +77,25 @@ public:
   nsresult SetCDMProxy(CDMProxy* aProxy);
 #endif
 
 #if defined(DEBUG)
   void Dump(const char* aPath);
 #endif
 
 private:
+  friend class DecodersToInitialize;
   ~TrackBuffer();
 
-  // Create a new decoder, set mCurrentDecoder to the new decoder, and queue
-  // the decoder for initialization.  The decoder is not considered
-  // initialized until it is added to mDecoders.
-  bool NewDecoder();
+  // Create a new decoder, set mCurrentDecoder to the new decoder and
+  // returns it. The new decoder must be queued using QueueInitializeDecoder
+  // for initialization.
+  // The decoder is not considered initialized until it is added to
+  // mInitializedDecoders.
+  already_AddRefed<SourceBufferDecoder> NewDecoder();
 
   // Helper for AppendData, ensures NotifyDataArrived is called whenever
   // data is appended to the current decoder's SourceBufferResource.
   bool AppendDataToCurrentResource(const uint8_t* aData, uint32_t aLength);
 
   // Queue execution of InitializeDecoder on mTaskQueue.
   bool QueueInitializeDecoder(SourceBufferDecoder* aDecoder);