Bug 1316211. P14 - move members from MDR to MFR. draft
authorJW Wang <jwwang@mozilla.com>
Wed, 19 Jul 2017 17:34:05 +0800
changeset 611848 96610ae32c7153b26995588641f036e080651ec2
parent 611847 ddcebaa6cdc043909ee9c6e334e366019243f23d
child 611849 66dcbd7e4ffb91cab6605cc27434d3a6f25de28b
push id69302
push userjwwang@mozilla.com
push dateThu, 20 Jul 2017 02:52:36 +0000
bugs1316211
milestone56.0a1
Bug 1316211. P14 - move members from MDR to MFR. MozReview-Commit-ID: EwdteoEY1uS
dom/media/MediaDecoderReader.cpp
dom/media/MediaDecoderReader.h
dom/media/MediaDecoderReaderWrapper.cpp
dom/media/MediaDecoderReaderWrapper.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
--- a/dom/media/MediaDecoderReader.cpp
+++ b/dom/media/MediaDecoderReader.cpp
@@ -33,54 +33,19 @@ extern LazyLogModule gMediaDecoderLog;
 #undef DECODER_LOG
 #undef DECODER_WARN
 
 #define FMT(x, ...) "Decoder=%p " x, mDecoder, ##__VA_ARGS__
 #define DECODER_LOG(...) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug,   (FMT(__VA_ARGS__)))
 #define DECODER_WARN(...) NS_WARNING(nsPrintfCString(FMT(__VA_ARGS__)).get())
 
 MediaDecoderReader::MediaDecoderReader(MediaDecoderReaderInit& aInit)
-  : mDecoder(aInit.mDecoder)
-  , mTaskQueue(new TaskQueue(
-      GetMediaThreadPool(MediaThreadType::PLAYBACK),
-      "MediaDecoderReader::mTaskQueue",
-      /* aSupportsTailDispatch = */ true))
-  , mBuffered(mTaskQueue, TimeIntervals(), "MediaDecoderReader::mBuffered (Canonical)")
-  , mShutdown(false)
 {
   MOZ_COUNT_CTOR(MediaDecoderReader);
   MOZ_ASSERT(NS_IsMainThread());
 }
 
-nsresult
-MediaDecoderReader::Init()
-{
-  return InitInternal();
-}
-
 MediaDecoderReader::~MediaDecoderReader()
 {
-  MOZ_ASSERT(mShutdown);
   MOZ_COUNT_DTOR(MediaDecoderReader);
 }
 
-void
-MediaDecoderReader::UpdateDuration(const media::TimeUnit& aDuration)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  UpdateBuffered();
-}
-
-RefPtr<ShutdownPromise>
-MediaDecoderReader::Shutdown()
-{
-  MOZ_ASSERT(OnTaskQueue());
-  mShutdown = true;
-
-  ReleaseResources();
-  mBuffered.DisconnectAll();
-
-  mDecoder = nullptr;
-
-  return mTaskQueue->BeginShutdown();
-}
-
 } // namespace mozilla
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -24,50 +24,16 @@
 namespace mozilla {
 
 class CDMProxy;
 class GMPCrashHelper;
 class MediaDecoderReader;
 class TaskQueue;
 class VideoFrameContainer;
 
-struct WaitForDataRejectValue
-{
-  enum Reason
-  {
-    SHUTDOWN,
-    CANCELED
-  };
-
-  WaitForDataRejectValue(MediaData::Type aType, Reason aReason)
-    :mType(aType), mReason(aReason)
-  {
-  }
-  MediaData::Type mType;
-  Reason mReason;
-};
-
-struct SeekRejectValue
-{
-  MOZ_IMPLICIT SeekRejectValue(const MediaResult& aError)
-    : mType(MediaData::NULL_DATA), mError(aError) { }
-  MOZ_IMPLICIT SeekRejectValue(nsresult aResult)
-    : mType(MediaData::NULL_DATA), mError(aResult) { }
-  SeekRejectValue(MediaData::Type aType, const MediaResult& aError)
-    : mType(aType), mError(aError) { }
-  MediaData::Type mType;
-  MediaResult mError;
-};
-
-struct MetadataHolder
-{
-  UniquePtr<MediaInfo> mInfo;
-  UniquePtr<MetadataTags> mTags;
-};
-
 struct MOZ_STACK_CLASS MediaDecoderReaderInit
 {
   AbstractMediaDecoder* const mDecoder;
   MediaResource* mResource = nullptr;
   VideoFrameContainer* mVideoFrameContainer = nullptr;
   already_AddRefed<layers::KnowsCompositor> mKnowsCompositor;
   already_AddRefed<GMPCrashHelper> mCrashHelper;
 
@@ -80,221 +46,22 @@ struct MOZ_STACK_CLASS MediaDecoderReade
 // Encapsulates the decoding and reading of media data. Reading can either
 // synchronous and done on the calling "decode" thread, or asynchronous and
 // performed on a background thread, with the result being returned by
 // callback.
 // Unless otherwise specified, methods and fields of this class can only
 // be accessed on the decode task queue.
 class MediaDecoderReader
 {
-  static const bool IsExclusive = true;
-
 public:
-  using TrackSet = EnumSet<TrackInfo::TrackType>;
-
-  using MetadataPromise = MozPromise<MetadataHolder, MediaResult, IsExclusive>;
-
-  template <typename Type>
-  using DataPromise = MozPromise<RefPtr<Type>, MediaResult, IsExclusive>;
-  using AudioDataPromise = DataPromise<AudioData>;
-  using VideoDataPromise = DataPromise<VideoData>;
-
-  using SeekPromise = MozPromise<media::TimeUnit, SeekRejectValue, IsExclusive>;
-
-  // Note that, conceptually, WaitForData makes sense in a non-exclusive sense.
-  // But in the current architecture it's only ever used exclusively (by MDSM),
-  // so we mark it that way to verify our assumptions. If you have a use-case
-  // for multiple WaitForData consumers, feel free to flip the exclusivity here.
-  using WaitForDataPromise =
-    MozPromise<MediaData::Type, WaitForDataRejectValue, IsExclusive>;
-
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReader)
 
   // The caller must ensure that Shutdown() is called before aDecoder is
   // destroyed.
   explicit MediaDecoderReader(MediaDecoderReaderInit& aInit);
 
-  // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE
-  // on failure.
-  nsresult Init();
-
-  // Called by MDSM in dormant state to release resources allocated by this
-  // reader. The reader can resume decoding by calling Seek() to a specific
-  // position.
-  virtual void ReleaseResources() = 0;
-
-  // Destroys the decoding state. The reader cannot be made usable again.
-  // This is different from ReleaseMediaResources() as it is irreversable,
-  // whereas ReleaseMediaResources() is.  Must be called on the decode
-  // thread.
-  virtual RefPtr<ShutdownPromise> Shutdown();
-
-  virtual bool OnTaskQueue() const
-  {
-    return OwnerThread()->IsCurrentThreadIn();
-  }
-
-  void UpdateDuration(const media::TimeUnit& aDuration);
-
-  virtual void UpdateCompositor(already_AddRefed<layers::KnowsCompositor>) = 0;
-
-  // Resets all state related to decoding, emptying all buffers etc.
-  // Cancels all pending Request*Data() request callbacks, rejects any
-  // outstanding seek promises, and flushes the decode pipeline. The
-  // decoder must not call any of the callbacks for outstanding
-  // Request*Data() calls after this is called. Calls to Request*Data()
-  // made after this should be processed as usual.
-  //
-  // Normally this call preceedes a Seek() call, or shutdown.
-  //
-  // aParam is a set of TrackInfo::TrackType enums specifying which
-  // queues need to be reset, defaulting to both audio and video tracks.
-  virtual nsresult ResetDecode(
-    TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack,
-                                TrackInfo::kVideoTrack)) = 0;
-
-  // Requests one audio sample from the reader.
-  //
-  // The decode should be performed asynchronously, and the promise should
-  // be resolved when it is complete.
-  virtual RefPtr<AudioDataPromise> RequestAudioData() = 0;
-
-  // Requests one video sample from the reader.
-  virtual RefPtr<VideoDataPromise>
-  RequestVideoData(const media::TimeUnit& aTimeThreshold) = 0;
-
-  // By default, the state machine polls the reader once per second when it's
-  // in buffering mode. Some readers support a promise-based mechanism by which
-  // they notify the state machine when the data arrives.
-  virtual bool IsWaitForDataSupported() const = 0;
-
-  virtual RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) = 0;
-
-  // The default implementation of AsyncReadMetadata is implemented in terms of
-  // synchronous ReadMetadata() calls. Implementations may also
-  // override AsyncReadMetadata to create a more proper async implementation.
-  virtual RefPtr<MetadataPromise> AsyncReadMetadata() = 0;
-
-  // Fills aInfo with the latest cached data required to present the media,
-  // ReadUpdatedMetadata will always be called once ReadMetadata has succeeded.
-  virtual void ReadUpdatedMetadata(MediaInfo* aInfo) = 0;
-
-  // Moves the decode head to aTime microseconds.
-  virtual RefPtr<SeekPromise> Seek(const SeekTarget& aTarget) = 0;
-
-  virtual void SetCDMProxy(CDMProxy* aProxy) = 0;
-
-  // The MediaDecoderStateMachine uses various heuristics that assume that
-  // raw media data is arriving sequentially from a network channel. This
-  // makes sense in the <video src="foo"> case, but not for more advanced use
-  // cases like MSE.
-  virtual bool UseBufferingHeuristics() const = 0;
-
-  virtual size_t SizeOfVideoQueueInFrames() = 0;
-  virtual size_t SizeOfAudioQueueInFrames() = 0;
-
-  // Called once new data has been cached by the MediaResource.
-  // mBuffered should be recalculated and updated accordingly.
-  virtual void NotifyDataArrived() = 0;
-
-  AbstractCanonical<media::TimeIntervals>* CanonicalBuffered()
-  {
-    return &mBuffered;
-  }
-
-  TaskQueue* OwnerThread() const
-  {
-    return mTaskQueue;
-  }
-
-  // Returns true if this decoder reader uses hardware accelerated video
-  // decoding.
-  virtual bool VideoIsHardwareAccelerated() const = 0;
-
-  TimedMetadataEventSource& TimedMetadataEvent()
-  {
-    return mTimedMetadataEvent;
-  }
-
-  // Notified by the OggDemuxer during playback when chained ogg is detected.
-  MediaEventSource<void>& OnMediaNotSeekable() { return mOnMediaNotSeekable; }
-
-  TimedMetadataEventProducer& TimedMetadataProducer()
-  {
-    return mTimedMetadataEvent;
-  }
-
-  MediaEventProducer<void>& MediaNotSeekableProducer()
-  {
-    return mOnMediaNotSeekable;
-  }
-
-  // Notified if the reader can't decode a sample due to a missing decryption
-  // key.
-  MediaEventSource<TrackInfo::TrackType>& OnTrackWaitingForKey()
-  {
-    return mOnTrackWaitingForKey;
-  }
-
-  MediaEventProducer<TrackInfo::TrackType>& OnTrackWaitingForKeyProducer()
-  {
-    return mOnTrackWaitingForKey;
-  }
-
-  MediaEventSource<nsTArray<uint8_t>, nsString>& OnEncrypted()
-  {
-    return mOnEncrypted;
-  }
-
-  MediaEventSource<void>& OnWaitingForKey()
-  {
-    return mOnWaitingForKey;
-  }
-
-  MediaEventSource<MediaResult>& OnDecodeWarning()
-  {
-    return mOnDecodeWarning;
-  }
-
-  // Switch the video decoder to NullDecoderModule. It might takes effective
-  // since a few samples later depends on how much demuxed samples are already
-  // queued in the original video decoder.
-  virtual void SetVideoNullDecode(bool aIsNullDecode) = 0;
-
 protected:
   virtual ~MediaDecoderReader();
-
-  // Recomputes mBuffered.
-  virtual void UpdateBuffered() = 0;
-
-  // Reference to the owning decoder object.
-  AbstractMediaDecoder* mDecoder;
-
-  // Decode task queue.
-  RefPtr<TaskQueue> mTaskQueue;
-
-  // Buffered range.
-  Canonical<media::TimeIntervals> mBuffered;
-
-  bool mShutdown;
-
-  // Used to send TimedMetadata to the listener.
-  TimedMetadataEventProducer mTimedMetadataEvent;
-
-  // Notify if this media is not seekable.
-  MediaEventProducer<void> mOnMediaNotSeekable;
-
-  // Notify if we are waiting for a decryption key.
-  MediaEventProducer<TrackInfo::TrackType> mOnTrackWaitingForKey;
-
-  MediaEventProducer<nsTArray<uint8_t>, nsString> mOnEncrypted;
-
-  MediaEventProducer<void> mOnWaitingForKey;
-
-  MediaEventProducer<MediaResult> mOnDecodeWarning;
-
-private:
-  virtual nsresult InitInternal() = 0;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/MediaDecoderReaderWrapper.cpp
+++ b/dom/media/MediaDecoderReaderWrapper.cpp
@@ -97,17 +97,17 @@ MediaDecoderReaderWrapper::RequestVideoD
              return VideoDataPromise::CreateAndResolve(aVideo.forget(),
                                                        __func__);
            },
            [](const MediaResult& aError) {
              return VideoDataPromise::CreateAndReject(aError, __func__);
            });
 }
 
-RefPtr<MediaDecoderReader::SeekPromise>
+RefPtr<MediaDecoderReaderWrapper::SeekPromise>
 MediaDecoderReaderWrapper::Seek(const SeekTarget& aTarget)
 {
   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   SeekTarget adjustedTarget = aTarget;
   adjustedTarget.SetTime(adjustedTarget.GetTime() + StartTime());
   return InvokeAsync(mReader->OwnerThread(),
                      mReader.get(),
                      __func__,
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -7,34 +7,34 @@
 #ifndef MediaDecoderReaderWrapper_h_
 #define MediaDecoderReaderWrapper_h_
 
 #include "mozilla/AbstractThread.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Variant.h"
 #include "nsISupportsImpl.h"
 
-#include "MediaDecoderReader.h"
 #include "MediaEventSource.h"
+#include "MediaFormatReader.h"
 
 namespace mozilla {
 
 /**
  * A wrapper around MediaFormatReader to offset the timestamps of Audio/Video
  * samples by the start time to ensure MDSM can always assume zero start time.
  * 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::TrackSet TrackSet;
+  using MetadataPromise = MediaFormatReader::MetadataPromise;
+  using AudioDataPromise = MediaFormatReader::AudioDataPromise;
+  using VideoDataPromise = MediaFormatReader::VideoDataPromise;
+  using SeekPromise = MediaFormatReader::SeekPromise;
+  using WaitForDataPromise = MediaFormatReader::WaitForDataPromise;
+  using TrackSet = MediaFormatReader::TrackSet;
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReaderWrapper);
 
 public:
   MediaDecoderReaderWrapper(AbstractThread* aOwnerThread,
                             MediaFormatReader* aReader);
 
   media::TimeUnit StartTime() const;
   RefPtr<MetadataPromise> ReadMetadata();
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -385,17 +385,17 @@ private:
 
   void OnMetadataNotRead(const MediaResult& aError)
   {
     mMetadataRequest.Complete();
     SLOGW("Decode metadata failed, shutting down decoder");
     mMaster->DecodeError(aError);
   }
 
-  MozPromiseRequestHolder<MediaDecoderReader::MetadataPromise> mMetadataRequest;
+  MozPromiseRequestHolder<MediaFormatReader::MetadataPromise> mMetadataRequest;
 };
 
 /**
  * Purpose: wait for the CDM to start decoding.
  *
  * Transition to other states when CDM is ready:
  *   SEEKING if any pending seek request.
  *   DECODING_FIRSTFRAME otherwise.
@@ -1390,17 +1390,17 @@ protected:
     if (mDoneAudioSeeking && mDoneVideoSeeking) {
       SeekCompleted();
     }
   }
 
   /*
    * Track the current seek promise made by the reader.
    */
-  MozPromiseRequestHolder<MediaDecoderReader::SeekPromise> mSeekRequest;
+  MozPromiseRequestHolder<MediaFormatReader::SeekPromise> mSeekRequest;
 
   /*
    * Internal state.
    */
   media::TimeUnit mCurrentTimeBeforeSeek;
   bool mDoneAudioSeeking = false;
   bool mDoneVideoSeeking = false;
   MozPromiseRequestHolder<WaitForDataPromise> mWaitRequest;
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -84,19 +84,19 @@ hardware (via AudioStream).
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/StateMirroring.h"
 
 #include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
 #include "MediaDecoder.h"
-#include "MediaDecoderReader.h"
 #include "MediaDecoderOwner.h"
 #include "MediaEventSource.h"
+#include "MediaFormatReader.h"
 #include "MediaMetadataManager.h"
 #include "MediaStatistics.h"
 #include "MediaTimer.h"
 #include "ImageContainer.h"
 #include "SeekJob.h"
 
 namespace mozilla {
 
@@ -144,17 +144,17 @@ enum class VideoDecodeMode : uint8_t
   shared state machine thread.
 
   See MediaDecoder.h for more details.
 */
 class MediaDecoderStateMachine
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachine)
 
-  using TrackSet = MediaDecoderReader::TrackSet;
+  using TrackSet = MediaFormatReader::TrackSet;
 
 public:
   typedef MediaDecoderOwner::NextFrameStatus NextFrameStatus;
   typedef mozilla::layers::ImageContainer::FrameID FrameID;
   MediaDecoderStateMachine(MediaDecoder* aDecoder, MediaFormatReader* aReader);
 
   nsresult Init(MediaDecoder* aDecoder);
 
@@ -576,19 +576,19 @@ private:
   uint32_t GetAmpleVideoFrames() const;
 
   // Our "ample" audio threshold. Once we've this much audio decoded, we
   // pause decoding.
   media::TimeUnit mAmpleAudioThreshold;
 
   // Only one of a given pair of ({Audio,Video}DataPromise, WaitForDataPromise)
   // should exist at any given moment.
-  using AudioDataPromise = MediaDecoderReader::AudioDataPromise;
-  using VideoDataPromise = MediaDecoderReader::VideoDataPromise;
-  using WaitForDataPromise = MediaDecoderReader::WaitForDataPromise;
+  using AudioDataPromise = MediaFormatReader::AudioDataPromise;
+  using VideoDataPromise = MediaFormatReader::VideoDataPromise;
+  using WaitForDataPromise = MediaFormatReader::WaitForDataPromise;
   MozPromiseRequestHolder<AudioDataPromise> mAudioDataRequest;
   MozPromiseRequestHolder<VideoDataPromise> mVideoDataRequest;
   MozPromiseRequestHolder<WaitForDataPromise> mAudioWaitRequest;
   MozPromiseRequestHolder<WaitForDataPromise> mVideoWaitRequest;
 
   const char* AudioRequestStatus() const;
   const char* VideoRequestStatus() const;
 
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -1091,43 +1091,49 @@ MediaFormatReader::DemuxerProxy::NotifyD
     }
     return NotifyDataArrivedPromise::CreateAndResolve(true, __func__);
   });
 }
 
 MediaFormatReader::MediaFormatReader(MediaDecoderReaderInit& aInit,
                                      MediaDataDemuxer* aDemuxer)
   : MediaDecoderReader(aInit)
-  , mAudio(this, MediaData::AUDIO_DATA,
-           MediaPrefs::MaxAudioDecodeError())
-  , mVideo(this, MediaData::VIDEO_DATA,
-           MediaPrefs::MaxVideoDecodeError())
+  , mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
+                             "MediaFormatReader::mTaskQueue",
+                             /* aSupportsTailDispatch = */ true))
+  , mAudio(this, MediaData::AUDIO_DATA, MediaPrefs::MaxAudioDecodeError())
+  , mVideo(this, MediaData::VIDEO_DATA, MediaPrefs::MaxVideoDecodeError())
   , mDemuxer(new DemuxerProxy(aDemuxer))
   , mDemuxerInitDone(false)
   , mPendingNotifyDataArrived(false)
   , mLastReportedNumDecodedFrames(0)
   , mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe)
   , mKnowsCompositor(aInit.mKnowsCompositor)
   , mInitDone(false)
   , mTrackDemuxersMayBlock(false)
   , mSeekScheduled(false)
   , mVideoFrameContainer(aInit.mVideoFrameContainer)
   , mCrashHelper(aInit.mCrashHelper)
   , mDecoderFactory(new DecoderFactory(this))
   , mShutdownPromisePool(new ShutdownPromisePool())
+  , mDecoder(aInit.mDecoder)
+  , mBuffered(mTaskQueue,
+              TimeIntervals(),
+              "MediaFormatReader::mBuffered (Canonical)")
 {
   MOZ_ASSERT(aDemuxer);
   MOZ_COUNT_CTOR(MediaFormatReader);
   mOnTrackWaitingForKeyListener = OnTrackWaitingForKey().Connect(
     mTaskQueue, this, &MediaFormatReader::NotifyWaitingForKey);
 }
 
 MediaFormatReader::~MediaFormatReader()
 {
   MOZ_COUNT_DTOR(MediaFormatReader);
+  MOZ_ASSERT(mShutdown);
 }
 
 RefPtr<ShutdownPromise>
 MediaFormatReader::Shutdown()
 {
   MOZ_ASSERT(OnTaskQueue());
   LOG("");
 
@@ -1200,21 +1206,24 @@ MediaFormatReader::TearDownDecoders()
     mVideo.mTaskQueue->AwaitShutdownAndIdle();
     mVideo.mTaskQueue = nullptr;
   }
 
   mDecoderFactory = nullptr;
   mPlatform = nullptr;
   mVideoFrameContainer = nullptr;
 
-  return MediaDecoderReader::Shutdown();
+  ReleaseResources();
+  mBuffered.DisconnectAll();
+  mDecoder = nullptr;
+  return mTaskQueue->BeginShutdown();
 }
 
 nsresult
-MediaFormatReader::InitInternal()
+MediaFormatReader::Init()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
 
   mAudio.mTaskQueue = new TaskQueue(
     GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
     "MFR::mAudio::mTaskQueue");
 
   mVideo.mTaskQueue = new TaskQueue(
@@ -1239,17 +1248,17 @@ MediaFormatReader::SetCDMProxy(CDMProxy*
 
 bool
 MediaFormatReader::IsWaitingOnCDMResource()
 {
   MOZ_ASSERT(OnTaskQueue());
   return IsEncrypted() && !mCDMProxy;
 }
 
-RefPtr<MediaDecoderReader::MetadataPromise>
+RefPtr<MediaFormatReader::MetadataPromise>
 MediaFormatReader::AsyncReadMetadata()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   MOZ_DIAGNOSTIC_ASSERT(mMetadataPromise.IsEmpty());
 
   if (mInitDone) {
     // We are returning from dormant.
@@ -1483,17 +1492,17 @@ MediaFormatReader::ShouldSkip(TimeUnit a
   }
   return (nextKeyframe <= aTimeThreshold
           || (mVideo.mTimeThreshold
               && mVideo.mTimeThreshold.ref().EndTime() < aTimeThreshold))
          && nextKeyframe.ToMicroseconds() >= 0
          && !nextKeyframe.IsInfinite();
 }
 
-RefPtr<MediaDecoderReader::VideoDataPromise>
+RefPtr<MediaFormatReader::VideoDataPromise>
 MediaFormatReader::RequestVideoData(const TimeUnit& aTimeThreshold)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(),
                         "No sample requests allowed while seeking");
   MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests");
   MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists()
                         || mVideo.mTimeThreshold.isSome());
@@ -1600,17 +1609,17 @@ MediaFormatReader::OnVideoDemuxCompleted
        aSamples->mSamples[0]->mTrackInfo
        ? aSamples->mSamples[0]->mTrackInfo->GetID()
        : 0);
   mVideo.mDemuxRequest.Complete();
   mVideo.mQueuedSamples.AppendElements(aSamples->mSamples);
   ScheduleUpdate(TrackInfo::kVideoTrack);
 }
 
-RefPtr<MediaDecoderReader::AudioDataPromise>
+RefPtr<MediaFormatReader::AudioDataPromise>
 MediaFormatReader::RequestAudioData()
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise(), "No duplicate sample requests");
   MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || mSeekPromise.IsEmpty(),
                         "No sample requests allowed while seeking");
   MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking()
                         || !mAudio.mSeekRequest.Exists()
@@ -2416,17 +2425,17 @@ MediaFormatReader::SizeOfAudioQueueInFra
 
 size_t
 MediaFormatReader::SizeOfQueue(TrackType aTrack)
 {
   auto& decoder = GetDecoderData(aTrack);
   return decoder.mSizeOfQueue;
 }
 
-RefPtr<MediaDecoderReader::WaitForDataPromise>
+RefPtr<MediaFormatReader::WaitForDataPromise>
 MediaFormatReader::WaitForData(MediaData::Type aType)
 {
   MOZ_ASSERT(OnTaskQueue());
   TrackType trackType = aType == MediaData::VIDEO_DATA ?
     TrackType::kVideoTrack : TrackType::kAudioTrack;
   auto& decoder = GetDecoderData(trackType);
   if (!decoder.IsWaiting()) {
     // We aren't waiting for anything.
@@ -2596,17 +2605,17 @@ MediaFormatReader::OnVideoSkipFailed(
       }
       break;
     default:
       NotifyError(TrackType::kVideoTrack, aFailure.mFailure);
       break;
   }
 }
 
-RefPtr<MediaDecoderReader::SeekPromise>
+RefPtr<MediaFormatReader::SeekPromise>
 MediaFormatReader::Seek(const SeekTarget& aTarget)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   LOG("aTarget=(%" PRId64 ")", aTarget.GetTime().ToMicroseconds());
 
   MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty());
   MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise());
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -18,76 +18,231 @@
 #include "MediaPrefs.h"
 #include "nsAutoPtr.h"
 #include "PDMFactory.h"
 
 namespace mozilla {
 
 class CDMProxy;
 
+struct WaitForDataRejectValue
+{
+  enum Reason
+  {
+    SHUTDOWN,
+    CANCELED
+  };
+
+  WaitForDataRejectValue(MediaData::Type aType, Reason aReason)
+    : mType(aType)
+    , mReason(aReason)
+  {
+  }
+  MediaData::Type mType;
+  Reason mReason;
+};
+
+struct SeekRejectValue
+{
+  MOZ_IMPLICIT SeekRejectValue(const MediaResult& aError)
+    : mType(MediaData::NULL_DATA)
+    , mError(aError)
+  {
+  }
+  MOZ_IMPLICIT SeekRejectValue(nsresult aResult)
+    : mType(MediaData::NULL_DATA)
+    , mError(aResult)
+  {
+  }
+  SeekRejectValue(MediaData::Type aType, const MediaResult& aError)
+    : mType(aType)
+    , mError(aError)
+  {
+  }
+  MediaData::Type mType;
+  MediaResult mError;
+};
+
+struct MetadataHolder
+{
+  UniquePtr<MediaInfo> mInfo;
+  UniquePtr<MetadataTags> mTags;
+};
+
 class MediaFormatReader final : public MediaDecoderReader
 {
+  static const bool IsExclusive = true;
   typedef TrackInfo::TrackType TrackType;
-  typedef MozPromise<bool, MediaResult, /* IsExclusive = */ true> NotifyDataArrivedPromise;
+  typedef MozPromise<bool, MediaResult, IsExclusive> NotifyDataArrivedPromise;
 
 public:
+  using TrackSet = EnumSet<TrackInfo::TrackType>;
+  using MetadataPromise = MozPromise<MetadataHolder, MediaResult, IsExclusive>;
+
+  template<typename Type>
+  using DataPromise = MozPromise<RefPtr<Type>, MediaResult, IsExclusive>;
+  using AudioDataPromise = DataPromise<AudioData>;
+  using VideoDataPromise = DataPromise<VideoData>;
+
+  using SeekPromise = MozPromise<media::TimeUnit, SeekRejectValue, IsExclusive>;
+
+  // Note that, conceptually, WaitForData makes sense in a non-exclusive sense.
+  // But in the current architecture it's only ever used exclusively (by MDSM),
+  // so we mark it that way to verify our assumptions. If you have a use-case
+  // for multiple WaitForData consumers, feel free to flip the exclusivity here.
+  using WaitForDataPromise =
+    MozPromise<MediaData::Type, WaitForDataRejectValue, IsExclusive>;
+
   MediaFormatReader(MediaDecoderReaderInit& aInit, MediaDataDemuxer* aDemuxer);
 
   virtual ~MediaFormatReader();
 
-  size_t SizeOfVideoQueueInFrames() override;
-  size_t SizeOfAudioQueueInFrames() override;
+  // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE
+  // on failure.
+  nsresult Init();
 
-  RefPtr<VideoDataPromise>
-  RequestVideoData(const media::TimeUnit& aTimeThreshold) override;
+  size_t SizeOfVideoQueueInFrames();
+  size_t SizeOfAudioQueueInFrames();
 
-  RefPtr<AudioDataPromise> RequestAudioData() override;
+  // Requests one video sample from the reader.
+  RefPtr<VideoDataPromise> RequestVideoData(
+    const media::TimeUnit& aTimeThreshold);
 
-  RefPtr<MetadataPromise> AsyncReadMetadata() override;
-
-  void ReadUpdatedMetadata(MediaInfo* aInfo) override;
+  // Requests one audio sample from the reader.
+  //
+  // The decode should be performed asynchronously, and the promise should
+  // be resolved when it is complete.
+  RefPtr<AudioDataPromise> RequestAudioData();
 
-  RefPtr<SeekPromise> Seek(const SeekTarget& aTarget) override;
+  // The default implementation of AsyncReadMetadata is implemented in terms of
+  // synchronous ReadMetadata() calls. Implementations may also
+  // override AsyncReadMetadata to create a more proper async implementation.
+  RefPtr<MetadataPromise> AsyncReadMetadata();
 
-  void NotifyDataArrived() override;
+  // Fills aInfo with the latest cached data required to present the media,
+  // ReadUpdatedMetadata will always be called once ReadMetadata has succeeded.
+  void ReadUpdatedMetadata(MediaInfo* aInfo);
+
+  RefPtr<SeekPromise> Seek(const SeekTarget& aTarget);
+
+  // Called once new data has been cached by the MediaResource.
+  // mBuffered should be recalculated and updated accordingly.
+  void NotifyDataArrived();
 
 protected:
-  void UpdateBuffered() override;
+  // Recomputes mBuffered.
+  void UpdateBuffered();
 
 public:
-  // For Media Resource Management
-  void ReleaseResources() override;
+  // Called by MDSM in dormant state to release resources allocated by this
+  // reader. The reader can resume decoding by calling Seek() to a specific
+  // position.
+  void ReleaseResources();
+
+  bool OnTaskQueue() const { return OwnerThread()->IsCurrentThreadIn(); }
 
-  nsresult ResetDecode(TrackSet aTracks) override;
-
-  RefPtr<ShutdownPromise> Shutdown() override;
-
-  bool VideoIsHardwareAccelerated() const override;
+  // Resets all state related to decoding, emptying all buffers etc.
+  // Cancels all pending Request*Data() request callbacks, rejects any
+  // outstanding seek promises, and flushes the decode pipeline. The
+  // decoder must not call any of the callbacks for outstanding
+  // Request*Data() calls after this is called. Calls to Request*Data()
+  // made after this should be processed as usual.
+  //
+  // Normally this call preceedes a Seek() call, or shutdown.
+  //
+  // aParam is a set of TrackInfo::TrackType enums specifying which
+  // queues need to be reset, defaulting to both audio and video tracks.
+  nsresult ResetDecode(TrackSet aTracks);
 
-  bool IsWaitForDataSupported() const override { return true; }
-  RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) override;
+  // Destroys the decoding state. The reader cannot be made usable again.
+  // This is different from ReleaseMediaResources() as it is irreversable,
+  // whereas ReleaseMediaResources() is.  Must be called on the decode
+  // thread.
+  RefPtr<ShutdownPromise> Shutdown();
+
+  // Returns true if this decoder reader uses hardware accelerated video
+  // decoding.
+  bool VideoIsHardwareAccelerated() const;
 
-  bool UseBufferingHeuristics() const override
-  {
-    return mTrackDemuxersMayBlock;
-  }
+  // By default, the state machine polls the reader once per second when it's
+  // in buffering mode. Some readers support a promise-based mechanism by which
+  // they notify the state machine when the data arrives.
+  bool IsWaitForDataSupported() const { return true; }
+
+  RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType);
 
-  void SetCDMProxy(CDMProxy* aProxy) override;
+  // The MediaDecoderStateMachine uses various heuristics that assume that
+  // raw media data is arriving sequentially from a network channel. This
+  // makes sense in the <video src="foo"> case, but not for more advanced use
+  // cases like MSE.
+  bool UseBufferingHeuristics() const { return mTrackDemuxersMayBlock; }
+
+  void SetCDMProxy(CDMProxy* aProxy);
 
   // Returns a string describing the state of the decoder data.
   // Used for debugging purposes.
   void GetMozDebugReaderData(nsACString& aString);
 
-  void SetVideoNullDecode(bool aIsNullDecode) override;
+  // Switch the video decoder to NullDecoderModule. It might takes effective
+  // since a few samples later depends on how much demuxed samples are already
+  // queued in the original video decoder.
+  void SetVideoNullDecode(bool aIsNullDecode);
+
+  void UpdateCompositor(already_AddRefed<layers::KnowsCompositor>);
+
+  void UpdateDuration(const media::TimeUnit& aDuration)
+  {
+    MOZ_ASSERT(OnTaskQueue());
+    UpdateBuffered();
+  }
+
+  AbstractCanonical<media::TimeIntervals>* CanonicalBuffered()
+  {
+    return &mBuffered;
+  }
+
+  TaskQueue* OwnerThread() const { return mTaskQueue; }
+
+  TimedMetadataEventSource& TimedMetadataEvent() { return mTimedMetadataEvent; }
+
+  // Notified by the OggDemuxer during playback when chained ogg is detected.
+  MediaEventSource<void>& OnMediaNotSeekable() { return mOnMediaNotSeekable; }
 
-  void UpdateCompositor(already_AddRefed<layers::KnowsCompositor>) override;
+  TimedMetadataEventProducer& TimedMetadataProducer()
+  {
+    return mTimedMetadataEvent;
+  }
+
+  MediaEventProducer<void>& MediaNotSeekableProducer()
+  {
+    return mOnMediaNotSeekable;
+  }
+
+  // Notified if the reader can't decode a sample due to a missing decryption
+  // key.
+  MediaEventSource<TrackInfo::TrackType>& OnTrackWaitingForKey()
+  {
+    return mOnTrackWaitingForKey;
+  }
+
+  MediaEventProducer<TrackInfo::TrackType>& OnTrackWaitingForKeyProducer()
+  {
+    return mOnTrackWaitingForKey;
+  }
+
+  MediaEventSource<nsTArray<uint8_t>, nsString>& OnEncrypted()
+  {
+    return mOnEncrypted;
+  }
+
+  MediaEventSource<void>& OnWaitingForKey() { return mOnWaitingForKey; }
+
+  MediaEventSource<MediaResult>& OnDecodeWarning() { return mOnDecodeWarning; }
 
 private:
-  nsresult InitInternal() override;
-
   bool HasVideo() const { return mVideo.mTrackDemuxer; }
   bool HasAudio() const { return mAudio.mTrackDemuxer; }
 
   bool IsWaitingOnCDMResource();
 
   bool InitDemuxer();
   // Notify the track demuxers that new data has been received.
   void NotifyTrackDemuxers();
@@ -440,16 +595,19 @@ private:
       mHasPromise = false;
     }
 
   private:
     MozPromiseHolder<DataPromise<Type>> mPromise;
     Atomic<bool> mHasPromise;
   };
 
+  // Decode task queue.
+  RefPtr<TaskQueue> mTaskQueue;
+
   DecoderDataWithPromise<AudioData> mAudio;
   DecoderDataWithPromise<VideoData> mVideo;
 
   // Returns true when the decoder for this track needs input.
   bool NeedInput(DecoderData& aDecoder);
 
   DecoderData& GetDecoderData(TrackType aTrack);
 
@@ -560,13 +718,36 @@ private:
 
   UniquePtr<MetadataTags> mTags;
 
   // A flag indicating if the start time is known or not.
   bool mHasStartTime = false;
 
   void ShutdownDecoder(TrackType aTrack);
   RefPtr<ShutdownPromise> TearDownDecoders();
+
+  // Reference to the owning decoder object.
+  AbstractMediaDecoder* mDecoder;
+
+  bool mShutdown = false;
+
+  // Buffered range.
+  Canonical<media::TimeIntervals> mBuffered;
+
+  // Used to send TimedMetadata to the listener.
+  TimedMetadataEventProducer mTimedMetadataEvent;
+
+  // Notify if this media is not seekable.
+  MediaEventProducer<void> mOnMediaNotSeekable;
+
+  // Notify if we are waiting for a decryption key.
+  MediaEventProducer<TrackInfo::TrackType> mOnTrackWaitingForKey;
+
+  MediaEventProducer<nsTArray<uint8_t>, nsString> mOnEncrypted;
+
+  MediaEventProducer<void> mOnWaitingForKey;
+
+  MediaEventProducer<MediaResult> mOnDecodeWarning;
 };
 
 } // namespace mozilla
 
 #endif