Bug 1171330: P5. Split AppendData task to be closer to spec. r=cajbir.
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 11 Jun 2015 15:49:50 +1000
changeset 248269 5d30edb9048a289f28c7ef6dd13d4a53fb0170d8
parent 248268 5d48cf35d58bbcfaefff22580e8e6e5449e8d52e
child 248270 cd08ea9d91939991327b01020d53e9d7f4b1e02f
push id28893
push userkwierso@gmail.com
push dateFri, 12 Jun 2015 00:02:58 +0000
treeherderautoland@8cf9d3e497f9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscajbir
bugs1171330
milestone41.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 1171330: P5. Split AppendData task to be closer to spec. r=cajbir.
dom/media/mediasource/SourceBuffer.cpp
dom/media/mediasource/SourceBuffer.h
dom/media/mediasource/SourceBufferContentManager.h
dom/media/mediasource/TrackBuffer.cpp
dom/media/mediasource/TrackBuffer.h
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -32,40 +32,34 @@ extern PRLogModuleInfo* GetMediaSourceAP
 #define MSE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, ("SourceBuffer(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
 #define MSE_DEBUGV(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Verbose, ("SourceBuffer(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
 #define MSE_API(arg, ...) MOZ_LOG(GetMediaSourceAPILog(), mozilla::LogLevel::Debug, ("SourceBuffer(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
 
 namespace mozilla {
 
 namespace dom {
 
-class AppendDataRunnable : public nsRunnable {
+class BufferAppendRunnable : public nsRunnable {
 public:
-  AppendDataRunnable(SourceBuffer* aSourceBuffer,
-                     MediaLargeByteBuffer* aData,
-                     TimeUnit aTimestampOffset,
-                     uint32_t aUpdateID)
+  BufferAppendRunnable(SourceBuffer* aSourceBuffer,
+                       uint32_t aUpdateID)
   : mSourceBuffer(aSourceBuffer)
-  , mData(aData)
-  , mTimestampOffset(aTimestampOffset)
   , mUpdateID(aUpdateID)
   {
   }
 
   NS_IMETHOD Run() override final {
 
-    mSourceBuffer->AppendData(mData, mTimestampOffset, mUpdateID);
+    mSourceBuffer->BufferAppend(mUpdateID);
 
     return NS_OK;
   }
 
 private:
   nsRefPtr<SourceBuffer> mSourceBuffer;
-  nsRefPtr<MediaLargeByteBuffer> mData;
-  TimeUnit mTimestampOffset;
   uint32_t mUpdateID;
 };
 
 class RangeRemovalRunnable : public nsRunnable {
 public:
   RangeRemovalRunnable(SourceBuffer* aSourceBuffer,
                        double aStart,
                        double aEnd)
@@ -408,48 +402,43 @@ void
 SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
 {
   MSE_DEBUG("AppendData(aLength=%u)", aLength);
 
   nsRefPtr<MediaLargeByteBuffer> data = PrepareAppend(aData, aLength, aRv);
   if (!data) {
     return;
   }
+  mContentManager->AppendData(data, TimeUnit::FromSeconds(mTimestampOffset));
+
   StartUpdating();
 
   MOZ_ASSERT(mAppendMode == SourceBufferAppendMode::Segments,
              "We don't handle timestampOffset for sequence mode yet");
-  nsCOMPtr<nsIRunnable> task =
-    new AppendDataRunnable(this, data, TimeUnit::FromSeconds(mTimestampOffset), mUpdateID);
+  nsCOMPtr<nsIRunnable> task = new BufferAppendRunnable(this, mUpdateID);
   NS_DispatchToMainThread(task);
 }
 
 void
-SourceBuffer::AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset,
-                         uint32_t aUpdateID)
+SourceBuffer::BufferAppend(uint32_t aUpdateID)
 {
   if (!mUpdating || aUpdateID != mUpdateID) {
     // 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);
   MOZ_ASSERT(!mPendingAppend.Exists());
 
-  if (!aData->Length()) {
-    StopUpdating();
-    return;
-  }
-
-  mPendingAppend.Begin(mContentManager->AppendData(aData, aTimestampOffset)
+  mPendingAppend.Begin(mContentManager->BufferAppend()
                        ->Then(AbstractThread::MainThread(), __func__, this,
                               &SourceBuffer::AppendDataCompletedWithSuccess,
                               &SourceBuffer::AppendDataErrored));
 }
 
 void
 SourceBuffer::AppendDataCompletedWithSuccess(bool aHasActiveTracks)
 {
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -128,35 +128,34 @@ public:
 #if defined(DEBUG)
   void Dump(const char* aPath);
 #endif
 
 private:
   ~SourceBuffer();
 
   friend class AsyncEventRunner<SourceBuffer>;
-  friend class AppendDataRunnable;
+  friend class BufferAppendRunnable;
   friend class RangeRemovalRunnable;
   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(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset,
-                  uint32_t aAppendID);
+  void BufferAppend(uint32_t aAppendID);
 
   // 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 MediaLargeByteBuffer object
--- a/dom/media/mediasource/SourceBufferContentManager.h
+++ b/dom/media/mediasource/SourceBufferContentManager.h
@@ -23,21 +23,25 @@ class SourceBufferContentManager {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SourceBufferContentManager);
 
   typedef MediaPromise<bool, nsresult, /* IsExclusive = */ true> AppendPromise;
 
   static already_AddRefed<SourceBufferContentManager>
   CreateManager(MediaSourceDecoder* aParentDecoder, const nsACString& aType);
 
-  // Append data to the current decoder.  Also responsible for calling
-  // NotifyDataArrived on the decoder to keep buffered range computation up
-  // to date.  Returns false if the append failed.
-  virtual nsRefPtr<AppendPromise>
-  AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset /* microseconds */) = 0;
+  // Add data to the end of the input buffer.
+  // Returns false if the append failed.
+  virtual bool
+  AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset) = 0;
+
+  // Run MSE Buffer Append Algorithm
+  // 3.5.5 Buffer Append Algorithm.
+  // http://w3c.github.io/media-source/index.html#sourcebuffer-buffer-append
+  virtual nsRefPtr<AppendPromise> BufferAppend() = 0;
 
   // Abort any pending AppendData.
   virtual void AbortAppendData() = 0;
 
   // Run MSE Reset Parser State Algorithm.
   // 3.5.2 Reset Parser State
   // http://w3c.github.io/media-source/#sourcebuffer-reset-parser-state
   virtual void ResetParserState() = 0;
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -133,81 +133,95 @@ TrackBuffer::ContinueShutdown()
 
   MOZ_ASSERT(!mCurrentDecoder, "Detach() should have been called");
   mInitializedDecoders.Clear();
   mParentDecoder = nullptr;
 
   mShutdownPromise.Resolve(true, __func__);
 }
 
-nsRefPtr<TrackBuffer::AppendPromise>
+bool
 TrackBuffer::AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  mInputBuffer = aData;
+  mTimestampOffset = aTimestampOffset;
+  return true;
+}
+
+nsRefPtr<TrackBuffer::AppendPromise>
+TrackBuffer::BufferAppend()
+{
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mInitializationPromise.IsEmpty());
+  MOZ_ASSERT(mInputBuffer);
+
+  if (mInputBuffer->IsEmpty()) {
+    return AppendPromise::CreateAndResolve(false, __func__);
+  }
 
   DecodersToInitialize decoders(this);
   nsRefPtr<AppendPromise> p = mInitializationPromise.Ensure(__func__);
   bool hadInitData = mParser->HasInitData();
   bool hadCompleteInitData = mParser->HasCompleteInitData();
   nsRefPtr<MediaLargeByteBuffer> oldInit = mParser->InitData();
-  bool newInitData = mParser->IsInitSegmentPresent(aData);
+  bool newInitData = mParser->IsInitSegmentPresent(mInputBuffer);
 
   // TODO: Run more of the buffer append algorithm asynchronously.
   if (newInitData) {
     MSE_DEBUG("New initialization segment.");
   } else if (!hadInitData) {
     MSE_DEBUG("Non-init segment appended during initialization.");
     mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
     return p;
   }
 
   int64_t start = 0, end = 0;
-  bool gotMedia = mParser->ParseStartAndEndTimestamps(aData, start, end);
+  bool gotMedia = mParser->ParseStartAndEndTimestamps(mInputBuffer, start, end);
   bool gotInit = mParser->HasCompleteInitData();
 
   if (newInitData) {
     if (!gotInit) {
       // We need a new decoder, but we can't initialize it yet.
       nsRefPtr<SourceBufferDecoder> decoder =
-        NewDecoder(aTimestampOffset);
+        NewDecoder(mTimestampOffset);
       // The new decoder is stored in mDecoders/mCurrentDecoder, so we
       // don't need to do anything with 'decoder'. It's only a placeholder.
       if (!decoder) {
         mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
         return p;
       }
     } else {
-      if (!decoders.NewDecoder(aTimestampOffset)) {
+      if (!decoders.NewDecoder(mTimestampOffset)) {
         mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
         return p;
       }
     }
   } else if (!hadCompleteInitData && gotInit) {
     MOZ_ASSERT(mCurrentDecoder);
     // Queue pending decoder for initialization now that we have a full
     // init segment.
     decoders.AppendElement(mCurrentDecoder);
   }
 
   if (gotMedia) {
-    if (mParser->IsMediaSegmentPresent(aData) && mLastEndTimestamp &&
+    if (mParser->IsMediaSegmentPresent(mInputBuffer) && mLastEndTimestamp &&
         (!mParser->TimestampsFuzzyEqual(start, mLastEndTimestamp.value()) ||
-         mLastTimestampOffset != aTimestampOffset ||
+         mLastTimestampOffset != mTimestampOffset ||
          mDecoderPerSegment ||
          (mCurrentDecoder && mCurrentDecoder->WasTrimmed()))) {
       MSE_DEBUG("Data last=[%lld, %lld] overlaps [%lld, %lld]",
                 mLastStartTimestamp, mLastEndTimestamp.value(), start, end);
 
       if (!newInitData) {
         // This data is earlier in the timeline than data we have already
         // processed or not continuous, so we must create a new decoder
         // to handle the decoding.
         if (!hadCompleteInitData ||
-            !decoders.NewDecoder(aTimestampOffset)) {
+            !decoders.NewDecoder(mTimestampOffset)) {
           mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
           return p;
         }
         MSE_DEBUG("Decoder marked as initialized.");
         AppendDataToCurrentResource(oldInit, 0);
       }
       mLastStartTimestamp = start;
     } else {
@@ -223,17 +237,17 @@ TrackBuffer::AppendData(MediaLargeByteBu
 
   if (gotMedia && starttu != mAdjustedTimestamp &&
       ((start < 0 && -start < FUZZ_TIMESTAMP_OFFSET && starttu < mAdjustedTimestamp) ||
        (start > 0 && (start < FUZZ_TIMESTAMP_OFFSET || starttu < mAdjustedTimestamp)))) {
     AdjustDecodersTimestampOffset(mAdjustedTimestamp - starttu);
     mAdjustedTimestamp = starttu;
   }
 
-  if (!AppendDataToCurrentResource(aData, end - start)) {
+  if (!AppendDataToCurrentResource(mInputBuffer, end - start)) {
     mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
     return p;
   }
 
   if (decoders.Length()) {
     // We're going to have to wait for the decoder to initialize, the promise
     // will be resolved once initialization completes.
     return p;
@@ -952,16 +966,17 @@ TrackBuffer::ResetParserState()
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mParser->HasInitData() && !mParser->HasCompleteInitData()) {
     // We have an incomplete init segment pending. reset current parser and
     // discard the current decoder.
     mParser = ContainerParser::CreateForMIMEType(mType);
     DiscardCurrentDecoder();
   }
+  mInputBuffer = nullptr;
 }
 
 void
 TrackBuffer::AbortAppendData()
 {
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
 
   nsRefPtr<SourceBufferDecoder> current = mCurrentDecoder;
--- a/dom/media/mediasource/TrackBuffer.h
+++ b/dom/media/mediasource/TrackBuffer.h
@@ -25,21 +25,22 @@ class MediaSourceDecoder;
 class MediaLargeByteBuffer;
 
 class TrackBuffer final : public SourceBufferContentManager {
 public:
   TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType);
 
   nsRefPtr<ShutdownPromise> Shutdown();
 
+  bool AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset) override;
+
   // Append data to the current decoder.  Also responsible for calling
   // NotifyDataArrived on the decoder to keep buffered range computation up
-  // to date.  Returns false if the append failed.
-  nsRefPtr<AppendPromise> AppendData(MediaLargeByteBuffer* aData,
-                                     TimeUnit aTimestampOffset /* microseconds */) override;
+  // to date.
+  nsRefPtr<AppendPromise> BufferAppend() override;
 
   // Evicts data held in the current decoders SourceBufferResource from the
   // start of the buffer through to aPlaybackTime. aThreshold is used to
   // bound the data being evicted. It will not evict more than aThreshold
   // bytes. aBufferStartTime contains the new start time of the current
   // decoders buffered data after the eviction.
   EvictDataResult EvictData(TimeUnit aPlaybackTime, uint32_t aThreshold, TimeUnit* aBufferStartTime) override;
 
@@ -157,16 +158,17 @@ private:
   void OnMetadataRead(MetadataHolder* aMetadata,
                       SourceBufferDecoder* aDecoder,
                       bool aWasEnded);
 
   void OnMetadataNotRead(ReadMetadataFailureReason aReason,
                          SourceBufferDecoder* aDecoder);
 
   nsAutoPtr<ContainerParser> mParser;
+  nsRefPtr<MediaLargeByteBuffer> mInputBuffer;
 
   // A task queue using the shared media thread pool.  Used exclusively to
   // initialize (i.e. call ReadMetadata on) decoders as they are created via
   // NewDecoder.
   RefPtr<MediaTaskQueue> mTaskQueue;
 
   // All of the decoders managed by this TrackBuffer.  Access protected by
   // mParentDecoder's monitor.
@@ -191,16 +193,17 @@ private:
   // The last start and end timestamps added to the TrackBuffer via
   // AppendData.  Accessed on the main thread only.
   int64_t mLastStartTimestamp;
   Maybe<int64_t> mLastEndTimestamp;
   void AdjustDecodersTimestampOffset(TimeUnit aOffset);
 
   // The timestamp offset used by our current decoder.
   TimeUnit mLastTimestampOffset;
+  TimeUnit mTimestampOffset;
   TimeUnit mAdjustedTimestamp;
 
   // True if at least one of our decoders has encrypted content.
   bool mIsWaitingOnCDM;
 
   // Set when the first decoder used by this TrackBuffer is initialized.
   // Protected by mParentDecoder's monitor.
   MediaInfo mInfo;