Bug 1265311. Part 1 - Add more proxy functions to MediaDecoderReaderWrapper. r=jya.
authorJW Wang <jwwang@mozilla.com>
Tue, 19 Apr 2016 16:14:30 +0800
changeset 293837 0220fd37d605291b2db7061e86d47252ed28aa7a
parent 293836 348413c98656addb864011b0dd3914f3710f4f06
child 293838 d5d46a4ad2be4af1b0d32886f3d492c1292a21ce
push id30194
push usercbook@mozilla.com
push dateWed, 20 Apr 2016 09:50:56 +0000
treeherdermozilla-central@f05a1242fb29 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya
bugs1265311
milestone48.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 1265311. Part 1 - Add more proxy functions to MediaDecoderReaderWrapper. r=jya.
dom/media/MediaDecoderReaderWrapper.cpp
dom/media/MediaDecoderReaderWrapper.h
dom/media/MediaDecoderStateMachine.cpp
--- a/dom/media/MediaDecoderReaderWrapper.cpp
+++ b/dom/media/MediaDecoderReaderWrapper.cpp
@@ -241,25 +241,70 @@ MediaDecoderReaderWrapper::Seek(SeekTarg
 {
   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   aTarget.SetTime(aTarget.GetTime() + StartTime());
   return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
                      &MediaDecoderReader::Seek, aTarget,
                      aEndTime.ToMicroseconds());
 }
 
+RefPtr<MediaDecoderReaderWrapper::WaitForDataPromise>
+MediaDecoderReaderWrapper::WaitForData(MediaData::Type aType)
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
+                     &MediaDecoderReader::WaitForData, aType);
+}
+
+RefPtr<MediaDecoderReaderWrapper::BufferedUpdatePromise>
+MediaDecoderReaderWrapper::UpdateBufferedWithPromise()
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
+                     &MediaDecoderReader::UpdateBufferedWithPromise);
+}
+
 void
+MediaDecoderReaderWrapper::ReleaseMediaResources()
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources);
+  mReader->OwnerThread()->Dispatch(r.forget());
+}
+
+void
+MediaDecoderReaderWrapper::SetIdle()
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableMethod(mReader, &MediaDecoderReader::SetIdle);
+  mReader->OwnerThread()->Dispatch(r.forget());
+}
+
+void
+MediaDecoderReaderWrapper::ResetDecode()
+{
+  MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode);
+  mReader->OwnerThread()->Dispatch(r.forget());
+}
+
+RefPtr<ShutdownPromise>
 MediaDecoderReaderWrapper::Shutdown()
 {
   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   mShutdown = true;
   if (mStartTimeRendezvous) {
     mStartTimeRendezvous->Destroy();
     mStartTimeRendezvous = nullptr;
   }
+  return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
+                     &MediaDecoderReader::Shutdown);
 }
 
 void
 MediaDecoderReaderWrapper::OnMetadataRead(MetadataHolder* aMetadata)
 {
   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   if (mShutdown) {
     return;
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -25,31 +25,68 @@ typedef MozPromise<bool, bool, /* isExcl
  * It also adjusts the seek target passed to Seek() to ensure correct seek time
  * is passed to the underlying reader.
  */
 class MediaDecoderReaderWrapper {
   typedef MediaDecoderReader::MetadataPromise MetadataPromise;
   typedef MediaDecoderReader::AudioDataPromise AudioDataPromise;
   typedef MediaDecoderReader::VideoDataPromise VideoDataPromise;
   typedef MediaDecoderReader::SeekPromise SeekPromise;
+  typedef MediaDecoderReader::WaitForDataPromise WaitForDataPromise;
+  typedef MediaDecoderReader::BufferedUpdatePromise BufferedUpdatePromise;
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReaderWrapper);
 
 public:
   MediaDecoderReaderWrapper(bool aIsRealTime,
                             AbstractThread* aOwnerThread,
                             MediaDecoderReader* aReader);
 
   media::TimeUnit StartTime() const;
   RefPtr<MetadataPromise> ReadMetadata();
   RefPtr<HaveStartTimePromise> AwaitStartTime();
   RefPtr<AudioDataPromise> RequestAudioData();
   RefPtr<VideoDataPromise> RequestVideoData(bool aSkipToNextKeyframe,
                                             media::TimeUnit aTimeThreshold);
   RefPtr<SeekPromise> Seek(SeekTarget aTarget, media::TimeUnit aEndTime);
-  void Shutdown();
+  RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType);
+  RefPtr<BufferedUpdatePromise> UpdateBufferedWithPromise();
+  RefPtr<ShutdownPromise> Shutdown();
+
+  void ReleaseMediaResources();
+  void SetIdle();
+  void ResetDecode();
+
+  nsresult Init() { return mReader->Init(); }
+  bool IsWaitForDataSupported() { return mReader->IsWaitForDataSupported(); }
+  bool IsAsync() const { return mReader->IsAsync(); }
+  bool UseBufferingHeuristics() { return mReader->UseBufferingHeuristics(); }
+  bool ForceZeroStartTime() const { return mReader->ForceZeroStartTime(); }
+
+  bool VideoIsHardwareAccelerated() const {
+    return mReader->VideoIsHardwareAccelerated();
+  }
+  TimedMetadataEventSource& TimedMetadataEvent() {
+    return mReader->TimedMetadataEvent();
+  }
+  size_t SizeOfAudioQueueInFrames() const {
+    return mReader->SizeOfAudioQueueInFrames();
+  }
+  size_t SizeOfVideoQueueInFrames() const {
+    return mReader->SizeOfVideoQueueInFrames();
+  }
+  void ReadUpdatedMetadata(MediaInfo* aInfo) {
+    mReader->ReadUpdatedMetadata(aInfo);
+  }
+  AbstractCanonical<media::TimeIntervals>* CanonicalBuffered() {
+    return mReader->CanonicalBuffered();
+  }
+
+#ifdef MOZ_EME
+  void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); }
+#endif
 
 private:
   ~MediaDecoderReaderWrapper();
 
   void OnMetadataRead(MetadataHolder* aMetadata);
   void OnMetadataNotRead() {}
   void OnSampleDecoded(MediaData* aSample);
   void OnNotDecoded() {}
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -318,17 +318,17 @@ MediaDecoderStateMachine::~MediaDecoderS
 }
 
 void
 MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // Connect mirrors.
-  mBuffered.Connect(mReader->CanonicalBuffered());
+  mBuffered.Connect(mReaderWrapper->CanonicalBuffered());
   mEstimatedDuration.Connect(aDecoder->CanonicalEstimatedDuration());
   mExplicitDuration.Connect(aDecoder->CanonicalExplicitDuration());
   mPlayState.Connect(aDecoder->CanonicalPlayState());
   mNextPlayState.Connect(aDecoder->CanonicalNextPlayState());
   mLogicallySeeking.Connect(aDecoder->CanonicalLogicallySeeking());
   mVolume.Connect(aDecoder->CanonicalVolume());
   mLogicalPlaybackRate.Connect(aDecoder->CanonicalPlaybackRate());
   mPreservesPitch.Connect(aDecoder->CanonicalPreservesPitch());
@@ -517,28 +517,28 @@ MediaDecoderStateMachine::NeedToSkipToNe
   // We'll skip the video decode to the next keyframe if we're low on
   // audio, or if we're low on video, provided we're not running low on
   // data to decode. If we're running low on downloaded data to decode,
   // we won't start keyframe skipping, as we'll be pausing playback to buffer
   // soon anyway and we'll want to be able to display frames immediately
   // after buffering finishes. We ignore the low audio calculations for
   // readers that are async, as since their audio decode runs on a different
   // task queue it should never run low and skipping won't help their decode.
-  bool isLowOnDecodedAudio = !mReader->IsAsync() &&
+  bool isLowOnDecodedAudio = !mReaderWrapper->IsAsync() &&
                              !mIsAudioPrerolling && IsAudioDecoding() &&
                              (GetDecodedAudioDuration() <
                               mLowAudioThresholdUsecs * mPlaybackRate);
   bool isLowOnDecodedVideo = !mIsVideoPrerolling &&
                              ((GetClock() - mDecodedVideoEndTime) * mPlaybackRate >
                               LOW_VIDEO_THRESHOLD_USECS);
   bool lowUndecoded = HasLowUndecodedData();
 
   if ((isLowOnDecodedAudio || isLowOnDecodedVideo) && !lowUndecoded) {
     DECODER_LOG("Skipping video decode to the next keyframe lowAudio=%d lowVideo=%d lowUndecoded=%d async=%d",
-                isLowOnDecodedAudio, isLowOnDecodedVideo, lowUndecoded, mReader->IsAsync());
+                isLowOnDecodedAudio, isLowOnDecodedVideo, lowUndecoded, mReaderWrapper->IsAsync());
     return true;
   }
 
   return false;
 }
 
 bool
 MediaDecoderStateMachine::NeedToDecodeAudio()
@@ -689,21 +689,21 @@ MediaDecoderStateMachine::OnNotDecoded(M
   if (aReason == MediaDecoderReader::DECODE_ERROR) {
     DecodeError();
     return;
   }
 
   // If the decoder is waiting for data, we tell it to call us back when the
   // data arrives.
   if (aReason == MediaDecoderReader::WAITING_FOR_DATA) {
-    MOZ_ASSERT(mReader->IsWaitForDataSupported(),
+    MOZ_ASSERT(mReaderWrapper->IsWaitForDataSupported(),
                "Readers that send WAITING_FOR_DATA need to implement WaitForData");
     RefPtr<MediaDecoderStateMachine> self = this;
-    WaitRequestRef(aType).Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
-                                            &MediaDecoderReader::WaitForData, aType)
+    WaitRequestRef(aType).Begin(
+      mReaderWrapper->WaitForData(aType)
       ->Then(OwnerThread(), __func__,
              [self] (MediaData::Type aType) -> void {
                self->WaitRequestRef(aType).Complete();
                if (aType == MediaData::AUDIO_DATA) {
                  self->EnsureAudioDecodeTaskQueued();
                } else {
                  self->EnsureVideoDecodeTaskQueued();
                }
@@ -822,17 +822,17 @@ MediaDecoderStateMachine::OnVideoDecoded
         StopPrerollingVideo();
       }
 
       // For non async readers, if the requested video sample was slow to
       // arrive, increase the amount of audio we buffer to ensure that we
       // don't run out of audio. This is unnecessary for async readers,
       // since they decode audio and video on different threads so they
       // are unlikely to run out of decoded audio.
-      if (mReader->IsAsync()) {
+      if (mReaderWrapper->IsAsync()) {
         return;
       }
       TimeDuration decodeTime = TimeStamp::Now() - aDecodeStartTime;
       if (!IsDecodingFirstFrame() &&
           THRESHOLD_FACTOR * DurationToUsecs(decodeTime) > mLowAudioThresholdUsecs &&
           !HasLowUndecodedData())
       {
         mLowAudioThresholdUsecs =
@@ -903,28 +903,28 @@ nsresult MediaDecoderStateMachine::Init(
     this, &MediaDecoderStateMachine::InitializationTask, aDecoder);
   mTaskQueue->Dispatch(r.forget());
 
   mAudioQueueListener = AudioQueue().PopEvent().Connect(
     mTaskQueue, this, &MediaDecoderStateMachine::OnAudioPopped);
   mVideoQueueListener = VideoQueue().PopEvent().Connect(
     mTaskQueue, this, &MediaDecoderStateMachine::OnVideoPopped);
 
-  mMetadataManager.Connect(mReader->TimedMetadataEvent(), OwnerThread());
+  mMetadataManager.Connect(mReaderWrapper->TimedMetadataEvent(), OwnerThread());
 
   mMediaSink = CreateMediaSink(mAudioCaptured);
 
 #ifdef MOZ_EME
   mCDMProxyPromise.Begin(aDecoder->RequestCDMProxy()->Then(
     OwnerThread(), __func__, this,
     &MediaDecoderStateMachine::OnCDMProxyReady,
     &MediaDecoderStateMachine::OnCDMProxyNotReady));
 #endif
 
-  nsresult rv = mReader->Init();
+  nsresult rv = mReaderWrapper->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   r = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::ReadMetadata);
   OwnerThread()->Dispatch(r.forget());
 
   return NS_OK;
 }
 
@@ -981,21 +981,21 @@ void
 MediaDecoderStateMachine::MaybeStartBuffering()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   if (mState == DECODER_STATE_DECODING &&
       mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
       mResource->IsExpectingMoreData()) {
     bool shouldBuffer;
-    if (mReader->UseBufferingHeuristics()) {
+    if (mReaderWrapper->UseBufferingHeuristics()) {
       shouldBuffer = HasLowDecodedData(EXHAUSTED_DATA_MARGIN_USECS) &&
                      (JustExitedQuickBuffering() || HasLowUndecodedData());
     } else {
-      MOZ_ASSERT(mReader->IsWaitForDataSupported());
+      MOZ_ASSERT(mReaderWrapper->IsWaitForDataSupported());
       shouldBuffer = (OutOfDecodedAudio() && mAudioWaitRequest.Exists()) ||
                      (OutOfDecodedVideo() && mVideoWaitRequest.Exists());
     }
     if (shouldBuffer) {
       StartBuffering();
       // Don't go straight back to the state machine loop since that might
       // cause us to start decoding again and we could flip-flop between
       // decoding and quick-buffering.
@@ -1163,18 +1163,17 @@ MediaDecoderStateMachine::SetDormant(boo
     Reset();
 
     // Note that we do not wait for the decode task queue to go idle before
     // queuing the ReleaseMediaResources task - instead, we disconnect promises,
     // reset state, and put a ResetDecode in the decode task queue. Any tasks
     // that run after ResetDecode are supposed to run with a clean slate. We rely
     // on that in other places (i.e. seeking), so it seems reasonable to rely on
     // it here as well.
-    nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources);
-    DecodeTaskQueue()->Dispatch(r.forget());
+    mReaderWrapper->ReleaseMediaResources();
   } else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
     mDecodingFirstFrame = true;
     SetState(DECODER_STATE_DECODING_METADATA);
     ReadMetadata();
   }
 }
 
 RefPtr<ShutdownPromise>
@@ -1202,24 +1201,22 @@ MediaDecoderStateMachine::Shutdown()
 
   if (IsPlaying()) {
     StopPlayback();
   }
 
   Reset();
 
   mMediaSink->Shutdown();
-  mReaderWrapper->Shutdown();
 
   DECODER_LOG("Shutdown started");
 
   // Put a task in the decode queue to shutdown the reader.
   // the queue to spin down.
-  return InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
-                     &MediaDecoderReader::Shutdown)
+  return mReaderWrapper->Shutdown()
     ->Then(OwnerThread(), __func__, this,
            &MediaDecoderStateMachine::FinishShutdown,
            &MediaDecoderStateMachine::FinishShutdown)
     ->CompletionPromise();
 }
 
 void MediaDecoderStateMachine::StartDecoding()
 {
@@ -1364,17 +1361,17 @@ MediaDecoderStateMachine::Seek(SeekTarge
     DECODER_WARN("Seek() function should not be called on a non-seekable state machine");
     return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true, __func__);
   }
 
   MOZ_ASSERT(mState > DECODER_STATE_DECODING_METADATA,
                "We should have got duration already");
 
   if (mState < DECODER_STATE_DECODING ||
-      (IsDecodingFirstFrame() && !mReader->ForceZeroStartTime())) {
+      (IsDecodingFirstFrame() && !mReaderWrapper->ForceZeroStartTime())) {
     DECODER_LOG("Seek() Not Enough Data to continue at this stage, queuing seek");
     mQueuedSeek.RejectIfExists(__func__);
     mQueuedSeek.mTarget = aTarget;
     return mQueuedSeek.mPromise.Ensure(__func__);
   }
   mQueuedSeek.RejectIfExists(__func__);
 
   DECODER_LOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
@@ -1452,18 +1449,17 @@ MediaDecoderStateMachine::DispatchDecode
   if (needToDecodeVideo) {
     EnsureVideoDecodeTaskQueued();
   }
 
   if (needIdle) {
     DECODER_LOG("Dispatching SetIdle() audioQueue=%lld videoQueue=%lld",
                 GetDecodedAudioDuration(),
                 VideoQueue().Duration());
-    nsCOMPtr<nsIRunnable> task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::SetIdle);
-    DecodeTaskQueue()->Dispatch(task.forget());
+    mReaderWrapper->SetIdle();
   }
 }
 
 void
 MediaDecoderStateMachine::InitiateSeek(SeekJob aSeekJob)
 {
   MOZ_ASSERT(OnTaskQueue());
 
@@ -1614,17 +1610,17 @@ MediaDecoderStateMachine::EnsureAudioDec
 
 void
 MediaDecoderStateMachine::RequestAudioData()
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(mState != DECODER_STATE_SEEKING);
 
   SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o",
-             AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames());
+             AudioQueue().GetSize(), mReaderWrapper->SizeOfAudioQueueInFrames());
 
   mAudioDataRequest.Begin(
     mReaderWrapper->RequestAudioData()
     ->Then(OwnerThread(), __func__, this,
            &MediaDecoderStateMachine::OnAudioDecoded,
            &MediaDecoderStateMachine::OnAudioNotDecoded));
 }
 
@@ -1679,17 +1675,17 @@ MediaDecoderStateMachine::RequestVideoDa
   TimeStamp videoDecodeStartTime = TimeStamp::Now();
 
   bool skipToNextKeyFrame = mSentFirstFrameLoadedEvent &&
     NeedToSkipToNextKeyframe();
 
   media::TimeUnit currentTime = media::TimeUnit::FromMicroseconds(GetMediaTime());
 
   SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
-             VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
+             VideoQueue().GetSize(), mReaderWrapper->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
              currentTime.ToMicroseconds());
 
   RefPtr<MediaDecoderStateMachine> self = this;
   mVideoDataRequest.Begin(
     mReaderWrapper->RequestVideoData(skipToNextKeyFrame, currentTime)
     ->Then(OwnerThread(), __func__,
            [self, videoDecodeStartTime] (MediaData* aVideoSample) {
              self->OnVideoDecoded(aVideoSample, videoDecodeStartTime);
@@ -1723,17 +1719,17 @@ MediaDecoderStateMachine::StartMediaSink
         &MediaDecoderStateMachine::OnMediaSinkVideoError));
     }
   }
 }
 
 bool MediaDecoderStateMachine::HasLowDecodedData(int64_t aAudioUsecs)
 {
   MOZ_ASSERT(OnTaskQueue());
-  MOZ_ASSERT(mReader->UseBufferingHeuristics());
+  MOZ_ASSERT(mReaderWrapper->UseBufferingHeuristics());
   // We consider ourselves low on decoded data if we're low on audio,
   // provided we've not decoded to the end of the audio stream, or
   // if we're low on video frames, provided
   // we've not decoded to the end of the video stream.
   return ((IsAudioDecoding() && GetDecodedAudioDuration() < aAudioUsecs) ||
          (IsVideoDecoding() &&
           static_cast<uint32_t>(VideoQueue().GetSize()) < LOW_VIDEO_FRAMES));
 }
@@ -1840,18 +1836,18 @@ MediaDecoderStateMachine::OnMetadataRead
         self->mInfo.mMetadataDuration.emplace(unadjusted - adjustment);
         self->RecomputeDuration();
       }, [] () -> void { NS_WARNING("Adjusting metadata end time failed"); }
     );
   }
 
   if (HasVideo()) {
     DECODER_LOG("Video decode isAsync=%d HWAccel=%d videoQueueSize=%d",
-                mReader->IsAsync(),
-                mReader->VideoIsHardwareAccelerated(),
+                mReaderWrapper->IsAsync(),
+                mReaderWrapper->VideoIsHardwareAccelerated(),
                 GetAmpleVideoFrames());
   }
 
   // In general, we wait until we know the duration before notifying the decoder.
   // However, we notify  unconditionally in this case without waiting for the start
   // time, since the caller might be waiting on metadataloaded to be fired before
   // feeding in the CDM, which we need to decode the first frame (and
   // thus get the metadata). We could fix this if we could compute the start
@@ -1905,18 +1901,18 @@ MediaDecoderStateMachine::EnqueueLoadedM
 void
 MediaDecoderStateMachine::EnqueueFirstFrameLoadedEvent()
 {
   MOZ_ASSERT(OnTaskQueue());
   // Track value of mSentFirstFrameLoadedEvent from before updating it
   bool firstFrameBeenLoaded = mSentFirstFrameLoadedEvent;
   mSentFirstFrameLoadedEvent = true;
   RefPtr<MediaDecoderStateMachine> self = this;
-  mBufferedUpdateRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
-    &MediaDecoderReader::UpdateBufferedWithPromise)
+  mBufferedUpdateRequest.Begin(
+    mReaderWrapper->UpdateBufferedWithPromise()
     ->Then(OwnerThread(),
     __func__,
     // Resolve
     [self, firstFrameBeenLoaded]() {
       self->mBufferedUpdateRequest.Complete();
       MediaDecoderEventVisibility visibility =
         firstFrameBeenLoaded ? MediaDecoderEventVisibility::Suppressed
                              : MediaDecoderEventVisibility::Observable;
@@ -1948,17 +1944,17 @@ MediaDecoderStateMachine::FinishDecodeFi
     mDuration = Some(TimeUnit::FromInfinity());
   }
 
   DECODER_LOG("Media duration %lld, "
               "transportSeekable=%d, mediaSeekable=%d",
               Duration().ToMicroseconds(), mResource->IsTransportSeekable(), mMediaSeekable.Ref());
 
   // Get potentially updated metadata
-  mReader->ReadUpdatedMetadata(&mInfo);
+  mReaderWrapper->ReadUpdatedMetadata(&mInfo);
 
   if (!mNotifyMetadataBeforeFirstFrame) {
     // If we didn't have duration and/or start time before, we should now.
     EnqueueLoadedMetadataEvent();
   }
   EnqueueFirstFrameLoadedEvent();
 
   mDecodingFirstFrame = false;
@@ -2147,33 +2143,33 @@ nsresult MediaDecoderStateMachine::RunSt
 
     case DECODER_STATE_BUFFERING: {
       TimeStamp now = TimeStamp::Now();
       NS_ASSERTION(!mBufferingStart.IsNull(), "Must know buffering start time.");
 
       // With buffering heuristics we will remain in the buffering state if
       // we've not decoded enough data to begin playback, or if we've not
       // downloaded a reasonable amount of data inside our buffering time.
-      if (mReader->UseBufferingHeuristics()) {
+      if (mReaderWrapper->UseBufferingHeuristics()) {
         TimeDuration elapsed = now - mBufferingStart;
         bool isLiveStream = resource->IsLiveStream();
         if ((isLiveStream || !CanPlayThrough()) &&
               elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) &&
               (mQuickBuffering ? HasLowDecodedData(mQuickBufferingLowDataThresholdUsecs)
                                : HasLowUndecodedData(mBufferingWait * USECS_PER_S)) &&
               mResource->IsExpectingMoreData())
         {
           DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s",
                       mBufferingWait, mBufferingWait - elapsed.ToSeconds(),
                       (mQuickBuffering ? "(quick exit)" : ""));
           ScheduleStateMachineIn(USECS_PER_S);
           return NS_OK;
         }
       } else if (OutOfDecodedAudio() || OutOfDecodedVideo()) {
-        MOZ_ASSERT(mReader->IsWaitForDataSupported(),
+        MOZ_ASSERT(mReaderWrapper->IsWaitForDataSupported(),
                    "Don't yet have a strategy for non-heuristic + non-WaitForData");
         DispatchDecodeTasksIfNeeded();
         MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mAudioDataRequest.Exists() || mAudioWaitRequest.Exists());
         MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mVideoDataRequest.Exists() || mVideoWaitRequest.Exists());
         DECODER_LOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
                     "mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
                     OutOfDecodedAudio(), AudioRequestStatus(),
                     OutOfDecodedVideo(), VideoRequestStatus());
@@ -2270,19 +2266,17 @@ MediaDecoderStateMachine::Reset()
   mAudioDataRequest.DisconnectIfExists();
   mAudioWaitRequest.DisconnectIfExists();
   mVideoDataRequest.DisconnectIfExists();
   mVideoWaitRequest.DisconnectIfExists();
   mSeekTaskRequest.DisconnectIfExists();
 
   mPlaybackOffset = 0;
 
-  nsCOMPtr<nsIRunnable> resetTask =
-    NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode);
-  DecodeTaskQueue()->Dispatch(resetTask.forget());
+  mReaderWrapper->ResetDecode();
 }
 
 int64_t
 MediaDecoderStateMachine::GetClock(TimeStamp* aTimeStamp) const
 {
   MOZ_ASSERT(OnTaskQueue());
   int64_t clockTime = mMediaSink->GetPosition(aTimeStamp);
   NS_ASSERTION(GetMediaTime() <= clockTime, "Clock should go forwards.");
@@ -2599,17 +2593,17 @@ void MediaDecoderStateMachine::OnMediaSi
 
 #ifdef MOZ_EME
 void
 MediaDecoderStateMachine::OnCDMProxyReady(RefPtr<CDMProxy> aProxy)
 {
   MOZ_ASSERT(OnTaskQueue());
   mCDMProxyPromise.Complete();
   mCDMProxy = aProxy;
-  mReader->SetCDMProxy(aProxy);
+  mReaderWrapper->SetCDMProxy(aProxy);
   if (mState == DECODER_STATE_WAIT_FOR_CDM) {
     StartDecoding();
   }
 }
 
 void
 MediaDecoderStateMachine::OnCDMProxyNotReady()
 {
@@ -2661,17 +2655,17 @@ MediaDecoderStateMachine::SetAudioCaptur
   if (mIsAudioPrerolling && DonePrerollingAudio()) {
     StopPrerollingAudio();
   }
 }
 
 uint32_t MediaDecoderStateMachine::GetAmpleVideoFrames() const
 {
   MOZ_ASSERT(OnTaskQueue());
-  return (mReader->IsAsync() && mReader->VideoIsHardwareAccelerated())
+  return (mReaderWrapper->IsAsync() && mReaderWrapper->VideoIsHardwareAccelerated())
     ? std::max<uint32_t>(sVideoQueueHWAccelSize, MIN_VIDEO_QUEUE_SIZE)
     : std::max<uint32_t>(sVideoQueueDefaultSize, MIN_VIDEO_QUEUE_SIZE);
 }
 
 void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream,
                                                bool aFinishWhenEnded)
 {
   MOZ_ASSERT(NS_IsMainThread());