Bug 1118589: MSE: Run appendBuffer internal's asynchronously. r=cajbir
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 26 Jan 2015 21:33:56 +1100
changeset 225767 a20b290d8c86d41a15fcdfa7052a49360bad40a4
parent 225766 48171dc1a53572825f050cc8f82a1975930fb2be
child 225768 40a5dd69da69828a00ccc36f092e498e306a1d5c
push id28175
push userryanvm@gmail.com
push dateMon, 26 Jan 2015 21:33:41 +0000
treeherdermozilla-central@a6f037b538ed [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscajbir
bugs1118589
milestone38.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 1118589: MSE: Run appendBuffer internal's asynchronously. r=cajbir
dom/media/mediasource/SourceBuffer.cpp
dom/media/mediasource/SourceBuffer.h
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/MediaSourceBinding.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "nsError.h"
 #include "nsIEventTarget.h"
 #include "nsIRunnable.h"
 #include "nsThreadUtils.h"
 #include "prlog.h"
+#include <time.h>
 
 struct JSContext;
 class JSObject;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetMediaSourceLog();
 extern PRLogModuleInfo* GetMediaSourceAPILog();
 
@@ -31,24 +32,47 @@ extern PRLogModuleInfo* GetMediaSourceAP
 #define MSE_DEBUGV(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG+1, (__VA_ARGS__))
 #define MSE_API(...) PR_LOG(GetMediaSourceAPILog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
 #define MSE_DEBUG(...)
 #define MSE_DEBUGV(...)
 #define MSE_API(...)
 #endif
 
-// RangeRemoval must be synchronous if appendBuffer is also synchronous.
-// While waiting for bug 1118589 to land, ensure RangeRemoval is synchronous
-#define APPENDBUFFER_IS_SYNCHRONOUS
-
 namespace mozilla {
 
 namespace dom {
 
+class AppendDataRunnable : public nsRunnable {
+public:
+  AppendDataRunnable(SourceBuffer* aSourceBuffer,
+                     const uint8_t* aData,
+                     uint32_t aLength,
+                     double aTimestampOffset)
+  : mSourceBuffer(aSourceBuffer)
+  , mTimestampOffset(aTimestampOffset)
+  {
+    mData.AppendElements(aData, aLength);
+  }
+
+  NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL {
+
+    mSourceBuffer->AppendData(mData.Elements(),
+                              mData.Length(),
+                              mTimestampOffset);
+
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<SourceBuffer> mSourceBuffer;
+  nsTArray<uint8_t> mData;
+  double mTimestampOffset;
+};
+
 class RangeRemovalRunnable : public nsRunnable {
 public:
   RangeRemovalRunnable(SourceBuffer* aSourceBuffer,
                      double aStart,
                      double aEnd)
   : mSourceBuffer(aSourceBuffer)
   , mStart(aStart)
   , mEnd(aEnd)
@@ -235,46 +259,34 @@ SourceBuffer::Remove(double aStart, doub
   RangeRemoval(aStart, aEnd);
 }
 
 void
 SourceBuffer::RangeRemoval(double aStart, double aEnd)
 {
   StartUpdating();
 
-#if defined(APPENDBUFFER_IS_SYNCHRONOUS)
-  DoRangeRemoval(aStart, aEnd);
-
-  // Run the final step of the buffer append algorithm asynchronously to
-  // ensure the SourceBuffer's updating flag transition behaves as required
-  // by the spec.
-  nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
-  NS_DispatchToMainThread(event);
-#else
   nsRefPtr<nsIRunnable> task = new RangeRemovalRunnable(this, aStart, aEnd);
   NS_DispatchToMainThread(task);
-#endif
 }
 
 void
 SourceBuffer::DoRangeRemoval(double aStart, double aEnd)
 {
   if (!mUpdating) {
     // abort was called in between.
     return;
   }
   if (mTrackBuffer && !IsInfinite(aStart)) {
     int64_t start = aStart * USECS_PER_S;
     int64_t end = IsInfinite(aEnd) ? INT64_MAX : (int64_t)(aEnd * USECS_PER_S);
     mTrackBuffer->RangeRemoval(start, end);
   }
 
-#if !defined(APPENDBUFFER_IS_SYNCHRONOUS)
   StopUpdating();
-#endif
 }
 
 void
 SourceBuffer::Detach()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("SourceBuffer(%p)::Detach", this);
   Abort();
@@ -400,36 +412,51 @@ SourceBuffer::AppendData(const uint8_t* 
   MSE_DEBUG("SourceBuffer(%p)::AppendData(aLength=%u)", this, aLength);
   if (!PrepareAppend(aRv)) {
     return;
   }
   StartUpdating();
 
   MOZ_ASSERT(mAppendMode == SourceBufferAppendMode::Segments,
              "We don't handle timestampOffset for sequence mode yet");
+  nsRefPtr<nsIRunnable> task =
+    new AppendDataRunnable(this, aData, aLength, mTimestampOffset);
+  NS_DispatchToMainThread(task);
+}
+
+void
+SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, double aTimestampOffset)
+{
+  if (!mUpdating) {
+    // The buffer append algorithm has been interrupted by abort().
+    //
+    // If the sequence appendBuffer(), abort(), appendBuffer() occurs before
+    // the first StopUpdating() runnable runs, then a second StopUpdating()
+    // runnable will be scheduled, but still only one (the first) will queue
+    // events.
+    return;
+  }
+
+  MOZ_ASSERT(mMediaSource);
+
   if (aLength) {
-    if (!mTrackBuffer->AppendData(aData, aLength, mTimestampOffset * USECS_PER_S)) {
-      nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethodWithArg<bool>(this, &SourceBuffer::AppendError, true);
-      NS_DispatchToMainThread(event);
+    if (!mTrackBuffer->AppendData(aData, aLength, aTimestampOffset * USECS_PER_S)) {
+      AppendError(true);
       return;
     }
 
     if (mTrackBuffer->HasInitSegment()) {
       mMediaSource->QueueInitializationEvent();
     }
 
     CheckEndTime();
   }
 
-  // Run the final step of the buffer append algorithm asynchronously to
-  // ensure the SourceBuffer's updating flag transition behaves as required
-  // by the spec.
-  nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
-  NS_DispatchToMainThread(event);
-}
+  StopUpdating();
+ }
 
 void
 SourceBuffer::AppendError(bool aDecoderError)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mUpdating) {
     // The buffer append algorithm has been interrupted by abort().
     return;
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -117,31 +117,34 @@ public:
 #if defined(DEBUG)
   void Dump(const char* aPath);
 #endif
 
 private:
   ~SourceBuffer();
 
   friend class AsyncEventRunner<SourceBuffer>;
+  friend class AppendDataRunnable;
   void DispatchSimpleEvent(const char* aName);
   void QueueAsyncSimpleEvent(const char* aName);
 
   // Update mUpdating and fire the appropriate events.
   void StartUpdating();
   void StopUpdating();
   void AbortUpdating();
 
   // If the media segment contains data beyond the current duration,
   // then run the duration change algorithm with new duration set to the
   // maximum of the current duration and the group end timestamp.
   void CheckEndTime();
 
   // Shared implementation of AppendBuffer overloads.
   void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
+  void AppendData(const uint8_t* aData, uint32_t aLength,
+                  double aTimestampOffset);
 
   // Implement the "Append Error Algorithm".
   // Will call endOfStream() with "decode" error if aDecodeError is true.
   // 3.5.3 Append Error Algorithm
   // http://w3c.github.io/media-source/#sourcebuffer-append-error
   void AppendError(bool aDecoderError);
 
   // Implements the "Prepare Append Algorithm".  Returns true if the append