Bug 1190019: [MSE] P1. Remove cycle between SourceBuffer and TrackBuffersManager. r=cpearce
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 04 Aug 2015 13:25:47 +1000
changeset 287722 a736fc66131dc2eea727c887c606ea3bb8ad24ed
parent 287721 b4a3696bed55dd325cdd13e22d1e8ed705dc1ecf
child 287723 bd2d8b78d1fc6c2e9114d6aa300f8c16180fe77b
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1190019
milestone42.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 1190019: [MSE] P1. Remove cycle between SourceBuffer and TrackBuffersManager. r=cpearce Instead we use a a ref-counted attribute holder to store those arguments.
dom/media/mediasource/SourceBuffer.cpp
dom/media/mediasource/SourceBuffer.h
dom/media/mediasource/SourceBufferContentManager.cpp
dom/media/mediasource/SourceBufferContentManager.h
dom/media/mediasource/TrackBuffersManager.cpp
dom/media/mediasource/TrackBuffersManager.h
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -71,17 +71,17 @@ SourceBuffer::SetMode(SourceBufferAppend
   if (!IsAttached() || mUpdating) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
   if (!mIsUsingFormatReader && aMode == SourceBufferAppendMode::Sequence) {
     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return;
   }
-  if (mIsUsingFormatReader && mGenerateTimestamps &&
+  if (mIsUsingFormatReader && mAttributes->mGenerateTimestamps &&
       aMode == SourceBufferAppendMode::Segments) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return;
   }
   MOZ_ASSERT(mMediaSource->ReadyState() != MediaSourceReadyState::Closed);
   if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
     mMediaSource->SetReadyState(MediaSourceReadyState::Open);
   }
@@ -91,17 +91,17 @@ SourceBuffer::SetMode(SourceBufferAppend
     return;
   }
 
   if (mIsUsingFormatReader && aMode == SourceBufferAppendMode::Sequence) {
     // Will set GroupStartTimestamp to GroupEndTimestamp.
     mContentManager->RestartGroupStartTimestamp();
   }
 
-  mAppendMode = aMode;
+  mAttributes->SetAppendMode(aMode);
 }
 
 void
 SourceBuffer::SetTimestampOffset(double aTimestampOffset, ErrorResult& aRv)
 {
   typedef mozilla::SourceBufferContentManager::AppendState AppendState;
 
   MOZ_ASSERT(NS_IsMainThread());
@@ -114,32 +114,23 @@ SourceBuffer::SetTimestampOffset(double 
   if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
     mMediaSource->SetReadyState(MediaSourceReadyState::Open);
   }
   if (mIsUsingFormatReader &&
       mContentManager->GetAppendState() == AppendState::PARSING_MEDIA_SEGMENT){
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
-  mApparentTimestampOffset = aTimestampOffset;
-  mTimestampOffset = TimeUnit::FromSeconds(aTimestampOffset);
-  if (mIsUsingFormatReader && mAppendMode == SourceBufferAppendMode::Sequence) {
-    mContentManager->SetGroupStartTimestamp(mTimestampOffset);
+  mAttributes->SetApparentTimestampOffset(aTimestampOffset);
+  if (mIsUsingFormatReader &&
+      mAttributes->GetAppendMode() == SourceBufferAppendMode::Sequence) {
+    mContentManager->SetGroupStartTimestamp(mAttributes->GetTimestampOffset());
   }
 }
 
-void
-SourceBuffer::SetTimestampOffset(const TimeUnit& aTimestampOffset)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  mTimestampOffset = aTimestampOffset;
-  mApparentTimestampOffset = aTimestampOffset.ToSeconds();
-}
-
 already_AddRefed<TimeRanges>
 SourceBuffer::GetBuffered(ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!IsAttached()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
@@ -160,37 +151,39 @@ void
 SourceBuffer::SetAppendWindowStart(double aAppendWindowStart, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_API("SetAppendWindowStart(aAppendWindowStart=%f)", aAppendWindowStart);
   if (!IsAttached() || mUpdating) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
-  if (aAppendWindowStart < 0 || aAppendWindowStart >= mAppendWindowEnd) {
+  if (aAppendWindowStart < 0 ||
+      aAppendWindowStart >= mAttributes->GetAppendWindowEnd()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return;
   }
-  mAppendWindowStart = aAppendWindowStart;
+  mAttributes->SetAppendWindowStart(aAppendWindowStart);
 }
 
 void
 SourceBuffer::SetAppendWindowEnd(double aAppendWindowEnd, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_API("SetAppendWindowEnd(aAppendWindowEnd=%f)", aAppendWindowEnd);
   if (!IsAttached() || mUpdating) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
-  if (IsNaN(aAppendWindowEnd) || aAppendWindowEnd <= mAppendWindowStart) {
+  if (IsNaN(aAppendWindowEnd) ||
+      aAppendWindowEnd <= mAttributes->GetAppendWindowStart()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return;
   }
-  mAppendWindowEnd = aAppendWindowEnd;
+  mAttributes->SetAppendWindowEnd(aAppendWindowEnd);
 }
 
 void
 SourceBuffer::AppendBuffer(const ArrayBuffer& aData, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_API("AppendBuffer(ArrayBuffer)");
   aData.ComputeLengthAndData();
@@ -216,18 +209,18 @@ SourceBuffer::Abort(ErrorResult& aRv)
     return;
   }
   if (mMediaSource->ReadyState() != MediaSourceReadyState::Open) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
   AbortBufferAppend();
   mContentManager->ResetParserState();
-  mAppendWindowStart = 0;
-  mAppendWindowEnd = PositiveInfinity<double>();
+  mAttributes->SetAppendWindowStart(0);
+  mAttributes->SetAppendWindowEnd(PositiveInfinity<double>());
 }
 
 void
 SourceBuffer::AbortBufferAppend()
 {
   if (mUpdating) {
     mPendingAppend.DisconnectIfExists();
     // TODO: Abort stream append loop algorithms.
@@ -307,46 +300,44 @@ SourceBuffer::Ended()
   // We want the MediaSourceReader to refresh its buffered range as it may
   // have been modified (end lined up).
   mMediaSource->GetDecoder()->NotifyDataArrived(1, mReportedOffset++, /* aThrottleUpdates = */ false);
 }
 
 SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
   : DOMEventTargetHelper(aMediaSource->GetParentObject())
   , mMediaSource(aMediaSource)
-  , mAppendWindowStart(0)
-  , mAppendWindowEnd(PositiveInfinity<double>())
-  , mApparentTimestampOffset(0)
-  , mAppendMode(SourceBufferAppendMode::Segments)
   , mUpdating(false)
   , mActive(false)
   , mUpdateID(0)
   , mReportedOffset(0)
   , mType(aType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aMediaSource);
   mEvictionThreshold = Preferences::GetUint("media.mediasource.eviction_threshold",
                                             100 * (1 << 20));
+  bool generateTimestamps = false;
+  if (aType.LowerCaseEqualsLiteral("audio/mpeg") ||
+      aType.LowerCaseEqualsLiteral("audio/aac")) {
+    generateTimestamps = true;
+  }
+  mAttributes = new SourceBufferAttributes(generateTimestamps);
+
   mContentManager =
-    SourceBufferContentManager::CreateManager(this,
+    SourceBufferContentManager::CreateManager(mAttributes,
                                               aMediaSource->GetDecoder(),
                                               aType);
   MSE_DEBUG("Create mContentManager=%p",
             mContentManager.get());
-  if (aType.LowerCaseEqualsLiteral("audio/mpeg") ||
-      aType.LowerCaseEqualsLiteral("audio/aac")) {
-    mGenerateTimestamps = true;
-  } else {
-    mGenerateTimestamps = false;
-  }
+
   mIsUsingFormatReader =
     Preferences::GetBool("media.mediasource.format-reader", false);
   ErrorResult dummy;
-  if (mGenerateTimestamps) {
+  if (mAttributes->mGenerateTimestamps) {
     SetMode(SourceBufferAppendMode::Sequence, dummy);
   } else {
     SetMode(SourceBufferAppendMode::Segments, dummy);
   }
   if (mIsUsingFormatReader) {
     mMediaSource->GetDecoder()->GetDemuxer()->AttachSourceBuffer(
       static_cast<mozilla::TrackBuffersManager*>(mContentManager.get()));
   }
@@ -441,21 +432,22 @@ void
 SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
 {
   MSE_DEBUG("AppendData(aLength=%u)", aLength);
 
   nsRefPtr<MediaByteBuffer> data = PrepareAppend(aData, aLength, aRv);
   if (!data) {
     return;
   }
-  mContentManager->AppendData(data, mTimestampOffset);
+  mContentManager->AppendData(data, mAttributes->GetTimestampOffset());
 
   StartUpdating();
 
-  MOZ_ASSERT(mIsUsingFormatReader || mAppendMode == SourceBufferAppendMode::Segments,
+  MOZ_ASSERT(mIsUsingFormatReader ||
+             mAttributes->GetAppendMode() == SourceBufferAppendMode::Segments,
              "We don't handle timestampOffset for sequence mode yet");
   nsCOMPtr<nsIRunnable> task = new BufferAppendRunnable(this, mUpdateID);
   NS_DispatchToMainThread(task);
 }
 
 void
 SourceBuffer::BufferAppend(uint32_t aUpdateID)
 {
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -20,67 +20,158 @@
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionNoteChild.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsISupports.h"
 #include "nsString.h"
 #include "nscore.h"
 #include "SourceBufferContentManager.h"
+#include "mozilla/Monitor.h"
 
 class JSObject;
 struct JSContext;
 
 namespace mozilla {
 
 class ErrorResult;
 class MediaByteBuffer;
 template <typename T> class AsyncEventRunner;
 class TrackBuffersManager;
 
 namespace dom {
 
 class TimeRanges;
 
+class SourceBufferAttributes {
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SourceBufferAttributes);
+  explicit SourceBufferAttributes(bool aGenerateTimestamp)
+    : mGenerateTimestamps(aGenerateTimestamp)
+    , mMonitor("SourceBufferAttributes")
+    , mAppendWindowStart(0)
+    , mAppendWindowEnd(PositiveInfinity<double>())
+    , mAppendMode(SourceBufferAppendMode::Segments)
+    , mApparentTimestampOffset(0)
+  {}
+
+  double GetAppendWindowStart()
+  {
+    MonitorAutoLock mon(mMonitor);
+    return mAppendWindowStart;
+  }
+
+  double GetAppendWindowEnd()
+  {
+    MonitorAutoLock mon(mMonitor);
+    return mAppendWindowEnd;
+  }
+
+  void SetAppendWindowStart(double aWindowStart)
+  {
+    MonitorAutoLock mon(mMonitor);
+    mAppendWindowStart = aWindowStart;
+  }
+
+  void SetAppendWindowEnd(double aWindowEnd)
+  {
+    MonitorAutoLock mon(mMonitor);
+    mAppendWindowEnd = aWindowEnd;
+  }
+
+  double GetApparentTimestampOffset()
+  {
+    MonitorAutoLock mon(mMonitor);
+    return mApparentTimestampOffset;
+  }
+
+  void SetApparentTimestampOffset(double aTimestampOffset)
+  {
+    MonitorAutoLock mon(mMonitor);
+    mApparentTimestampOffset = aTimestampOffset;
+    mTimestampOffset = media::TimeUnit::FromSeconds(aTimestampOffset);
+  }
+
+  media::TimeUnit GetTimestampOffset()
+  {
+    MonitorAutoLock mon(mMonitor);
+    return mTimestampOffset;
+  }
+
+  void SetTimestampOffset(media::TimeUnit& aTimestampOffset)
+  {
+    MonitorAutoLock mon(mMonitor);
+    mTimestampOffset = aTimestampOffset;
+    mApparentTimestampOffset = aTimestampOffset.ToSeconds();
+  }
+
+  SourceBufferAppendMode GetAppendMode()
+  {
+    MonitorAutoLock mon(mMonitor);
+    return mAppendMode;
+  }
+
+  void SetAppendMode(SourceBufferAppendMode aAppendMode)
+  {
+    MonitorAutoLock mon(mMonitor);
+    mAppendMode = aAppendMode;
+  }
+
+  // mGenerateTimestamp isn't mutable once the source buffer has been constructed
+  // We don't need a monitor to protect it across threads.
+  const bool mGenerateTimestamps;
+
+private:
+  ~SourceBufferAttributes() {};
+
+  // Monitor protecting all members below.
+  Monitor mMonitor;
+  double mAppendWindowStart;
+  double mAppendWindowEnd;
+  SourceBufferAppendMode mAppendMode;
+  double mApparentTimestampOffset;
+  media::TimeUnit mTimestampOffset;
+};
+
 class SourceBuffer final : public DOMEventTargetHelper
 {
 public:
   /** WebIDL Methods. */
   SourceBufferAppendMode Mode() const
   {
-    return mAppendMode;
+    return mAttributes->GetAppendMode();
   }
 
   void SetMode(SourceBufferAppendMode aMode, ErrorResult& aRv);
 
   bool Updating() const
   {
     return mUpdating;
   }
 
   already_AddRefed<TimeRanges> GetBuffered(ErrorResult& aRv);
   media::TimeIntervals GetTimeIntervals();
 
   double TimestampOffset() const
   {
-    return mApparentTimestampOffset;
+    return mAttributes->GetApparentTimestampOffset();
   }
 
   void SetTimestampOffset(double aTimestampOffset, ErrorResult& aRv);
 
   double AppendWindowStart() const
   {
-    return mAppendWindowStart;
+    return mAttributes->GetAppendWindowStart();
   }
 
   void SetAppendWindowStart(double aAppendWindowStart, ErrorResult& aRv);
 
   double AppendWindowEnd() const
   {
-    return mAppendWindowEnd;
+    return mAttributes->GetAppendWindowEnd();
   }
 
   void SetAppendWindowEnd(double aAppendWindowEnd, ErrorResult& aRv);
 
   void AppendBuffer(const ArrayBuffer& aData, ErrorResult& aRv);
   void AppendBuffer(const ArrayBufferView& aData, ErrorResult& aRv);
 
   void Abort(ErrorResult& aRv);
@@ -159,34 +250,24 @@ private:
   // on success or nullptr (with aRv set) on error.
   already_AddRefed<MediaByteBuffer> PrepareAppend(const uint8_t* aData,
                                                   uint32_t aLength,
                                                   ErrorResult& aRv);
 
   void AppendDataCompletedWithSuccess(bool aHasActiveTracks);
   void AppendDataErrored(nsresult aError);
 
-  // Set timestampOffset, must be called on the main thread.
-  void SetTimestampOffset(const media::TimeUnit& aTimestampOffset);
-
   nsRefPtr<MediaSource> mMediaSource;
 
   uint32_t mEvictionThreshold;
 
   nsRefPtr<SourceBufferContentManager> mContentManager;
-
-  double mAppendWindowStart;
-  double mAppendWindowEnd;
+  nsRefPtr<SourceBufferAttributes> mAttributes;
 
-  double mApparentTimestampOffset;
-  media::TimeUnit mTimestampOffset;
-
-  SourceBufferAppendMode mAppendMode;
   bool mUpdating;
-  bool mGenerateTimestamps;
   bool mIsUsingFormatReader;
 
   mozilla::Atomic<bool> mActive;
 
   // Each time mUpdating is set to true, mUpdateID will be incremented.
   // This allows for a queued AppendData task to identify if it was earlier
   // aborted and another AppendData queued.
   uint32_t mUpdateID;
--- a/dom/media/mediasource/SourceBufferContentManager.cpp
+++ b/dom/media/mediasource/SourceBufferContentManager.cpp
@@ -13,25 +13,25 @@ namespace mozilla {
 
 #if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) || defined(MOZ_APPLEMEDIA) || defined(MOZ_FFMPEG)
 #define MP4_READER_DORMANT_HEURISTIC
 #else
 #undef MP4_READER_DORMANT_HEURISTIC
 #endif
 
 already_AddRefed<SourceBufferContentManager>
-SourceBufferContentManager::CreateManager(dom::SourceBuffer* aParent,
+SourceBufferContentManager::CreateManager(dom::SourceBufferAttributes* aAttributes,
                                           MediaSourceDecoder* aParentDecoder,
                                           const nsACString &aType)
 {
   nsRefPtr<SourceBufferContentManager> manager;
   bool useFormatReader =
     Preferences::GetBool("media.mediasource.format-reader", false);
   if (useFormatReader) {
-    manager = new TrackBuffersManager(aParent, aParentDecoder, aType);
+    manager = new TrackBuffersManager(aAttributes, aParentDecoder, aType);
   } else {
     manager = new TrackBuffer(aParentDecoder, aType);
   }
 
   // Now that we know what type we're dealing with, enable dormant as needed.
 #if defined(MP4_READER_DORMANT_HEURISTIC)
   if (aType.LowerCaseEqualsLiteral("video/mp4") ||
       aType.LowerCaseEqualsLiteral("audio/mp4") ||
--- a/dom/media/mediasource/SourceBufferContentManager.h
+++ b/dom/media/mediasource/SourceBufferContentManager.h
@@ -13,27 +13,29 @@
 #include "MediaSourceDecoder.h"
 #include "TimeUnits.h"
 #include "nsString.h"
 
 namespace mozilla {
 
 namespace dom {
 class SourceBuffer;
+class SourceBufferAttributes;
 }
 
 class SourceBufferContentManager {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SourceBufferContentManager);
 
   typedef MozPromise<bool, nsresult, /* IsExclusive = */ true> AppendPromise;
   typedef AppendPromise RangeRemovalPromise;
 
   static already_AddRefed<SourceBufferContentManager>
-  CreateManager(dom::SourceBuffer* aParent, MediaSourceDecoder* aParentDecoder,
+  CreateManager(dom::SourceBufferAttributes* aAttributes,
+                MediaSourceDecoder* aParentDecoder,
                 const nsACString& aType);
 
   // Add data to the end of the input buffer.
   // Returns false if the append failed.
   virtual bool
   AppendData(MediaByteBuffer* aData, media::TimeUnit aTimestampOffset) = 0;
 
   // Run MSE Buffer Append Algorithm
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -85,28 +85,30 @@ public:
   }
 private:
   nsRefPtr<AbstractMediaDecoder> mDecoder;
   nsTArray<uint8_t> mInitData;
   nsString mInitDataType;
 };
 #endif // MOZ_EME
 
-TrackBuffersManager::TrackBuffersManager(dom::SourceBuffer* aParent, MediaSourceDecoder* aParentDecoder, const nsACString& aType)
+TrackBuffersManager::TrackBuffersManager(dom::SourceBufferAttributes* aAttributes,
+                                         MediaSourceDecoder* aParentDecoder,
+                                         const nsACString& aType)
   : mInputBuffer(new MediaByteBuffer)
   , mAppendState(AppendState::WAITING_FOR_SEGMENT)
   , mBufferFull(false)
   , mFirstInitializationSegmentReceived(false)
   , mActiveTrack(false)
   , mType(aType)
   , mParser(ContainerParser::CreateForMIMEType(aType))
   , mProcessedInput(0)
   , mAppendRunning(false)
   , mTaskQueue(aParentDecoder->GetDemuxer()->GetTaskQueue())
-  , mParent(new nsMainThreadPtrHolder<dom::SourceBuffer>(aParent, false /* strict */))
+  , mSourceBufferAttributes(aAttributes)
   , mParentDecoder(new nsMainThreadPtrHolder<MediaSourceDecoder>(aParentDecoder, false /* strict */))
   , mMediaSourceDemuxer(mParentDecoder->GetDemuxer())
   , mMediaSourceDuration(mTaskQueue, Maybe<double>(), "TrackBuffersManager::mMediaSourceDuration (Mirror)")
   , mAbort(false)
   , mEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold",
                                             100 * (1 << 20)))
   , mEvictionOccurred(false)
   , mMonitor("TrackBuffersManager")
@@ -615,18 +617,18 @@ TrackBuffersManager::AppendIncomingBuffe
       RejectAppend(NS_ERROR_OUT_OF_MEMORY, __func__);
     }
     mTimestampOffset = incomingBuffer.second();
     mLastTimestampOffset = mTimestampOffset;
   }
   mIncomingBuffers.Clear();
 
   mAppendWindow =
-    TimeInterval(TimeUnit::FromSeconds(mParent->AppendWindowStart()),
-                 TimeUnit::FromSeconds(mParent->AppendWindowEnd()));
+    TimeInterval(TimeUnit::FromSeconds(mSourceBufferAttributes->GetAppendWindowStart()),
+                 TimeUnit::FromSeconds(mSourceBufferAttributes->GetAppendWindowEnd()));
 }
 
 void
 TrackBuffersManager::SegmentParserLoop()
 {
   MOZ_ASSERT(OnTaskQueue());
   while (true) {
     // 1. If the input buffer is empty, then jump to the need more data step below.
@@ -1234,17 +1236,17 @@ TrackBuffersManager::ResolveProcessing(b
     mAppendRunning = false;
   }
   mProcessingPromise.ResolveIfExists(aResolveValue, __func__);
 }
 
 void
 TrackBuffersManager::CheckSequenceDiscontinuity()
 {
-  if (mParent->mAppendMode == SourceBufferAppendMode::Sequence &&
+  if (mSourceBufferAttributes->GetAppendMode() == SourceBufferAppendMode::Sequence &&
       mGroupStartTimestamp.isSome()) {
     mTimestampOffset = mGroupStartTimestamp.ref();
     mGroupEndTimestamp = mGroupStartTimestamp.ref();
     mVideoTracks.mNeedRandomAccessPoint = true;
     mAudioTracks.mNeedRandomAccessPoint = true;
     mGroupStartTimestamp.reset();
   }
 }
@@ -1309,41 +1311,43 @@ TrackBuffersManager::ProcessFrames(Track
     //   Let presentation timestamp be a double precision floating point representation of the coded frame's presentation timestamp in seconds.
     //   Let decode timestamp be a double precision floating point representation of the coded frame's decode timestamp in seconds.
 
     // 2. Let frame duration be a double precision floating point representation of the coded frame's duration in seconds.
     // Step 3 is performed earlier or when a discontinuity has been detected.
     // 4. If timestampOffset is not 0, then run the following steps:
 
     TimeInterval sampleInterval =
-      mParent->mGenerateTimestamps
+      mSourceBufferAttributes->mGenerateTimestamps
         ? TimeInterval(mTimestampOffset,
                        mTimestampOffset + TimeUnit::FromMicroseconds(sample->mDuration))
         : TimeInterval(TimeUnit::FromMicroseconds(sample->mTime) + mTimestampOffset,
                        TimeUnit::FromMicroseconds(sample->GetEndTime()) + mTimestampOffset);
     TimeUnit decodeTimestamp =
-      mParent->mGenerateTimestamps
+      mSourceBufferAttributes->mGenerateTimestamps
         ? mTimestampOffset
         : TimeUnit::FromMicroseconds(sample->mTimecode) + mTimestampOffset;
 
     // 6. If last decode timestamp for track buffer is set and decode timestamp is less than last decode timestamp:
     // OR
     // If last decode timestamp for track buffer is set and the difference between decode timestamp and last decode timestamp is greater than 2 times last frame duration:
 
     if (needDiscontinuityCheck && trackBuffer.mLastDecodeTimestamp.isSome() &&
         (decodeTimestamp < trackBuffer.mLastDecodeTimestamp.ref() ||
          decodeTimestamp - trackBuffer.mLastDecodeTimestamp.ref() > 2*trackBuffer.mLongestFrameDuration.ref())) {
       MSE_DEBUG("Discontinuity detected.");
+      SourceBufferAppendMode appendMode = mSourceBufferAttributes->GetAppendMode();
+
       // 1a. If mode equals "segments":
-      if (mParent->mAppendMode == SourceBufferAppendMode::Segments) {
+      if (appendMode == SourceBufferAppendMode::Segments) {
         // Set group end timestamp to presentation timestamp.
         mGroupEndTimestamp = sampleInterval.mStart;
       }
       // 1b. If mode equals "sequence":
-      if (mParent->mAppendMode == SourceBufferAppendMode::Sequence) {
+      if (appendMode == SourceBufferAppendMode::Sequence) {
         // Set group start timestamp equal to the group end timestamp.
         mGroupStartTimestamp = Some(mGroupEndTimestamp);
       }
       for (auto& track : GetTracksList()) {
         // 2. Unset the last decode timestamp on all track buffers.
         // 3. Unset the last frame duration on all track buffers.
         // 4. Unset the highest end timestamp on all track buffers.
         // 5. Set the need random access point flag on all track buffers to true.
@@ -1353,27 +1357,27 @@ TrackBuffersManager::ProcessFrames(Track
       // Rather that restarting the process for the frame, we run the first
       // steps again instead.
       // 3. If mode equals "sequence" and group start timestamp is set, then run the following steps:
       CheckSequenceDiscontinuity();
 
       if (!sample->mKeyframe) {
         continue;
       }
-      if (mParent->mAppendMode == SourceBufferAppendMode::Sequence) {
+      if (appendMode == SourceBufferAppendMode::Sequence) {
         // mTimestampOffset was modified during CheckSequenceDiscontinuity.
         // We need to update our variables.
         sampleInterval =
-          mParent->mGenerateTimestamps
+          mSourceBufferAttributes->mGenerateTimestamps
             ? TimeInterval(mTimestampOffset,
                            mTimestampOffset + TimeUnit::FromMicroseconds(sample->mDuration))
             : TimeInterval(TimeUnit::FromMicroseconds(sample->mTime) + mTimestampOffset,
                            TimeUnit::FromMicroseconds(sample->GetEndTime()) + mTimestampOffset);
         decodeTimestamp =
-          mParent->mGenerateTimestamps
+          mSourceBufferAttributes->mGenerateTimestamps
             ? mTimestampOffset
             : TimeUnit::FromMicroseconds(sample->mTimecode) + mTimestampOffset;
       }
       trackBuffer.mNeedRandomAccessPoint = false;
       needDiscontinuityCheck = false;
     }
 
     // 7. Let frame end timestamp equal the sum of presentation timestamp and frame duration.
@@ -1423,17 +1427,17 @@ TrackBuffersManager::ProcessFrames(Track
         sampleInterval.mEnd > trackBuffer.mHighestEndTimestamp.ref()) {
       trackBuffer.mHighestEndTimestamp = Some(sampleInterval.mEnd);
     }
     // 20. If frame end timestamp is greater than group end timestamp, then set group end timestamp equal to frame end timestamp.
     if (sampleInterval.mEnd > mGroupEndTimestamp) {
       mGroupEndTimestamp = sampleInterval.mEnd;
     }
     // 21. If generate timestamps flag equals true, then set timestampOffset equal to frame end timestamp.
-    if (mParent->mGenerateTimestamps) {
+    if (mSourceBufferAttributes->mGenerateTimestamps) {
       mTimestampOffset = sampleInterval.mEnd;
     }
   }
 
   if (samples.Length()) {
     InsertFrames(samples, samplesRange, trackBuffer);
     trackBuffer.mSizeBuffer += sizeNewSamples;
   }
@@ -1674,22 +1678,17 @@ TrackBuffersManager::GetTracksList()
   return tracks;
 }
 
 void
 TrackBuffersManager::RestoreCachedVariables()
 {
   MOZ_ASSERT(OnTaskQueue());
   if (mTimestampOffset != mLastTimestampOffset) {
-    nsRefPtr<TrackBuffersManager> self = this;
-    nsCOMPtr<nsIRunnable> task =
-      NS_NewRunnableFunction([self] {
-        self->mParent->SetTimestampOffset(self->mTimestampOffset);
-      });
-    AbstractThread::MainThread()->Dispatch(task.forget());
+    mSourceBufferAttributes->SetTimestampOffset(mTimestampOffset);
   }
 }
 
 void
 TrackBuffersManager::SetAppendState(TrackBuffersManager::AppendState aAppendState)
 {
   MSE_DEBUG("AppendState changed from %s to %s",
             AppendStateToStr(mAppendState), AppendStateToStr(aAppendState));
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -20,27 +20,32 @@
 #include "nsTArray.h"
 
 namespace mozilla {
 
 class ContainerParser;
 class MediaByteBuffer;
 class MediaRawData;
 class MediaSourceDemuxer;
-class SourceBuffer;
 class SourceBufferResource;
 
+namespace dom {
+  class SourceBufferAttributes;
+}
+
 class TrackBuffersManager : public SourceBufferContentManager {
 public:
   typedef MozPromise<bool, nsresult, /* IsExclusive = */ true> CodedFrameProcessingPromise;
   typedef TrackInfo::TrackType TrackType;
   typedef MediaData::Type MediaType;
   typedef nsTArray<nsRefPtr<MediaRawData>> TrackBuffer;
 
-  TrackBuffersManager(dom::SourceBuffer* aParent, MediaSourceDecoder* aParentDecoder, const nsACString& aType);
+  TrackBuffersManager(dom::SourceBufferAttributes* aAttributes,
+                      MediaSourceDecoder* aParentDecoder,
+                      const nsACString& aType);
 
   bool AppendData(MediaByteBuffer* aData,
                   media::TimeUnit aTimestampOffset) override;
 
   nsRefPtr<AppendPromise> BufferAppend() override;
 
   void AbortAppendData() override;
 
@@ -310,17 +315,17 @@ private:
   RefPtr<TaskQueue> mTaskQueue;
 
   media::TimeInterval mAppendWindow;
   media::TimeUnit mTimestampOffset;
   media::TimeUnit mLastTimestampOffset;
   void RestoreCachedVariables();
 
   // Strong references to external objects.
-  nsMainThreadPtrHandle<dom::SourceBuffer> mParent;
+  nsRefPtr<dom::SourceBufferAttributes> mSourceBufferAttributes;
   nsMainThreadPtrHandle<MediaSourceDecoder> mParentDecoder;
   nsRefPtr<MediaSourceDemuxer> mMediaSourceDemuxer;
 
   // MediaSource duration mirrored from MediaDecoder on the main thread..
   Mirror<Maybe<double>> mMediaSourceDuration;
 
   // Set to true if abort was called.
   Atomic<bool> mAbort;