tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MediaDecoderStateMachineBase.h (11923B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #ifndef DOM_MEDIA_MEDIADECODERSTATEMACHINEBASE_H_
      6 #define DOM_MEDIA_MEDIADECODERSTATEMACHINEBASE_H_
      7 
      8 #include "DecoderDoctorDiagnostics.h"
      9 #include "MediaDecoder.h"
     10 #include "MediaDecoderOwner.h"
     11 #include "MediaEventSource.h"
     12 #include "MediaInfo.h"
     13 #include "MediaMetadataManager.h"
     14 #include "MediaPromiseDefs.h"
     15 #include "ReaderProxy.h"
     16 #include "VideoFrameContainer.h"
     17 #include "mozilla/Variant.h"
     18 #include "mozilla/dom/MediaDebugInfoBinding.h"
     19 #include "nsISupportsImpl.h"
     20 
     21 class AudioDeviceInfo;
     22 
     23 namespace mozilla {
     24 
     25 class AbstractThread;
     26 class CDMProxy;
     27 class FrameStatistics;
     28 class MediaFormatReader;
     29 class TaskQueue;
     30 
     31 struct MediaPlaybackEvent {
     32  enum EventType {
     33    PlaybackStarted,
     34    PlaybackStopped,
     35    PlaybackProgressed,
     36    PlaybackEnded,
     37    SeekStarted,
     38    Invalidate,
     39    EnterVideoSuspend,
     40    ExitVideoSuspend,
     41    StartVideoSuspendTimer,
     42    CancelVideoSuspendTimer,
     43    VideoOnlySeekBegin,
     44    VideoOnlySeekCompleted,
     45  } mType;
     46 
     47  using DataType = Variant<Nothing, int64_t>;
     48  DataType mData;
     49 
     50  MOZ_IMPLICIT MediaPlaybackEvent(EventType aType)
     51      : mType(aType), mData(Nothing{}) {}
     52 
     53  template <typename T>
     54  MediaPlaybackEvent(EventType aType, T&& aArg)
     55      : mType(aType), mData(std::forward<T>(aArg)) {}
     56 };
     57 
     58 enum class VideoDecodeMode : uint8_t { Normal, Suspend };
     59 
     60 /**
     61 * The state machine class. This manages the decoding and seeking in the
     62 * MediaDecoderReader on the decode task queue, and A/V sync on the shared
     63 * state machine thread, and controls the audio "push" thread.
     64 *
     65 * All internal state is synchronised via the decoder monitor. State changes
     66 * are propagated by scheduling the state machine to run another cycle on the
     67 * shared state machine thread.
     68 */
     69 class MediaDecoderStateMachineBase {
     70 public:
     71  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
     72 
     73  using FirstFrameEventSourceExc =
     74      MediaEventSourceExc<UniquePtr<MediaInfo>, MediaDecoderEventVisibility>;
     75  using MetadataEventSourceExc =
     76      MediaEventSourceExc<UniquePtr<MediaInfo>, UniquePtr<MetadataTags>,
     77                          MediaDecoderEventVisibility>;
     78  using NextFrameStatus = MediaDecoderOwner::NextFrameStatus;
     79 
     80  MediaDecoderStateMachineBase(MediaDecoder* aDecoder,
     81                               MediaFormatReader* aReader);
     82 
     83  virtual nsresult Init(MediaDecoder* aDecoder);
     84 
     85  RefPtr<ShutdownPromise> BeginShutdown();
     86 
     87  // Seeks to the decoder to aTarget asynchronously.
     88  virtual RefPtr<MediaDecoder::SeekPromise> InvokeSeek(
     89      const SeekTarget& aTarget);
     90 
     91  virtual size_t SizeOfVideoQueue() const = 0;
     92  virtual size_t SizeOfAudioQueue() const = 0;
     93 
     94  // Sets the video decode mode. Used by the suspend-video-decoder feature.
     95  virtual void SetVideoDecodeMode(VideoDecodeMode aMode) = 0;
     96 
     97  // Set new sink device.  ExternalEngineStateMachine will reject the returned
     98  // promise with NS_ERROR_ABORT to indicate that the action is not supported.
     99  // MediaDecoderStateMachine will resolve the promise when the previous
    100  // device is no longer in use and an attempt to open the new device
    101  // completes (successfully or not) or is deemed unnecessary because the
    102  // device is not required for output at this time.  MediaDecoderStateMachine
    103  // will always consider the switch in underlying output device successful
    104  // and continue attempting to open the new device even if opening initially
    105  // fails.
    106  virtual RefPtr<GenericPromise> InvokeSetSink(
    107      const RefPtr<AudioDeviceInfo>& aSink) = 0;
    108  virtual void InvokeSuspendMediaSink() = 0;
    109  virtual void InvokeResumeMediaSink() = 0;
    110 
    111  virtual RefPtr<GenericPromise> RequestDebugInfo(
    112      dom::MediaDecoderStateMachineDebugInfo& aInfo) = 0;
    113 
    114  // Returns the state machine task queue.
    115  TaskQueue* OwnerThread() const { return mTaskQueue; }
    116 
    117  MetadataEventSourceExc& MetadataLoadedEvent() { return mMetadataLoadedEvent; }
    118 
    119  FirstFrameEventSourceExc& FirstFrameLoadedEvent() {
    120    return mFirstFrameLoadedEvent;
    121  }
    122 
    123  MediaEventSourceExc<RefPtr<VideoFrameContainer>>&
    124  OnSecondaryVideoContainerInstalled() {
    125    return mOnSecondaryVideoContainerInstalled;
    126  }
    127 
    128  TimedMetadataEventSource& TimedMetadataEvent() {
    129    return mMetadataManager.TimedMetadataEvent();
    130  }
    131 
    132  MediaEventSource<MediaPlaybackEvent>& OnPlaybackEvent() {
    133    return mOnPlaybackEvent;
    134  }
    135  MediaEventSource<MediaResult>& OnPlaybackErrorEvent() {
    136    return mOnPlaybackErrorEvent;
    137  }
    138 
    139  MediaEventSource<DecoderDoctorEvent>& OnDecoderDoctorEvent() {
    140    return mOnDecoderDoctorEvent;
    141  }
    142 
    143  MediaEventSource<NextFrameStatus>& OnNextFrameStatus() {
    144    return mOnNextFrameStatus;
    145  }
    146 
    147  MediaEventProducer<VideoInfo, AudioInfo>& OnTrackInfoUpdatedEvent() {
    148    return mReader->OnTrackInfoUpdatedEvent();
    149  }
    150 
    151  MediaEventSource<void>& OnMediaNotSeekable() const;
    152 
    153  AbstractCanonical<media::NullableTimeUnit>* CanonicalDuration() {
    154    return &mDuration;
    155  }
    156  AbstractCanonical<media::TimeUnit>* CanonicalCurrentPosition() {
    157    return &mCurrentPosition;
    158  }
    159  AbstractCanonical<bool>* CanonicalIsAudioDataAudible() {
    160    return &mIsAudioDataAudible;
    161  }
    162  AbstractCanonical<media::TimeIntervals>* CanonicalBuffered() const;
    163 
    164  void DispatchSetFragmentEndTime(const media::TimeUnit& aEndTime);
    165  void DispatchCanPlayThrough(bool aCanPlayThrough);
    166  void DispatchIsLiveStream(bool aIsLiveStream);
    167  void DispatchSetPlaybackRate(double aPlaybackRate);
    168 
    169  virtual RefPtr<SetCDMPromise> SetCDMProxy(CDMProxy* aProxy);
    170 
    171  virtual nsresult IsCDMProxySupported(CDMProxy* aProxy) = 0;
    172 
    173  virtual bool IsExternalEngineStateMachine() const { return false; }
    174 
    175  bool IsLiveStream() const;
    176 
    177 #ifdef DEBUG
    178  bool HasNotifiedPlaybackError() const { return mHasNotifiedPlaybackError; }
    179 #endif
    180 
    181 protected:
    182  virtual ~MediaDecoderStateMachineBase() = default;
    183 
    184  bool HasAudio() const { return mInfo.ref().HasAudio(); }
    185  bool HasVideo() const { return mInfo.ref().HasVideo(); }
    186  const MediaInfo& Info() const { return mInfo.ref(); }
    187 
    188  virtual void SetPlaybackRate(double aPlaybackRate) = 0;
    189  virtual void SetCanPlayThrough(bool aCanPlayThrough) = 0;
    190  virtual void SetFragmentEndTime(const media::TimeUnit& aFragmentEndTime) = 0;
    191 
    192  virtual void BufferedRangeUpdated() = 0;
    193  virtual void VolumeChanged() = 0;
    194  virtual void PreservesPitchChanged() = 0;
    195  virtual void PlayStateChanged() = 0;
    196  virtual void LoopingChanged() = 0;
    197  virtual void UpdateSecondaryVideoContainer() = 0;
    198 
    199  // Init tasks which should be done on the task queue.
    200  virtual void InitializationTask(MediaDecoder* aDecoder);
    201 
    202  virtual RefPtr<ShutdownPromise> Shutdown() = 0;
    203 
    204  virtual RefPtr<MediaDecoder::SeekPromise> Seek(const SeekTarget& aTarget) = 0;
    205 
    206  virtual void DecodeError(const MediaResult& aError);
    207 
    208  void SetIsLiveStream(bool aIsLiveStream);
    209 
    210  // Functions used by assertions to ensure we're calling things
    211  // on the appropriate threads.
    212  bool OnTaskQueue() const;
    213 
    214  bool IsRequestingAudioData() const { return mAudioDataRequest.Exists(); }
    215  bool IsRequestingVideoData() const { return mVideoDataRequest.Exists(); }
    216  bool IsWaitingAudioData() const { return mAudioWaitRequest.Exists(); }
    217  bool IsWaitingVideoData() const { return mVideoWaitRequest.Exists(); }
    218  bool IsTrackingAudioData() const {
    219    return mAudioDataRequest.Exists() || mAudioWaitRequest.Exists();
    220  }
    221  bool IsTrackingVideoData() const {
    222    return mVideoDataRequest.Exists() || mVideoWaitRequest.Exists();
    223  }
    224 
    225  void* const mDecoderID;
    226  const RefPtr<AbstractThread> mAbstractMainThread;
    227  const RefPtr<FrameStatistics> mFrameStats;
    228  const RefPtr<VideoFrameContainer> mVideoFrameContainer;
    229  const RefPtr<TaskQueue> mTaskQueue;
    230  const RefPtr<ReaderProxy> mReader;
    231  mozilla::MediaMetadataManager mMetadataManager;
    232 
    233  // Playback rate. 1.0 : normal speed, 0.5 : two times slower.
    234  double mPlaybackRate;
    235 
    236  // Event producers
    237  MediaEventProducerExc<UniquePtr<MediaInfo>, UniquePtr<MetadataTags>,
    238                        MediaDecoderEventVisibility>
    239      mMetadataLoadedEvent;
    240  MediaEventProducerExc<UniquePtr<MediaInfo>, MediaDecoderEventVisibility>
    241      mFirstFrameLoadedEvent;
    242  MediaEventProducerExc<RefPtr<VideoFrameContainer>>
    243      mOnSecondaryVideoContainerInstalled;
    244  MediaEventProducer<MediaPlaybackEvent> mOnPlaybackEvent;
    245  MediaEventProducer<MediaResult> mOnPlaybackErrorEvent;
    246  MediaEventProducer<DecoderDoctorEvent> mOnDecoderDoctorEvent;
    247  MediaEventProducer<NextFrameStatus> mOnNextFrameStatus;
    248 
    249  // The buffered range. Mirrored from the decoder thread.
    250  Mirror<media::TimeIntervals> mBuffered;
    251 
    252  // The current play state, mirrored from the main thread.
    253  Mirror<MediaDecoder::PlayState> mPlayState;
    254 
    255  // Volume of playback. 0.0 = muted. 1.0 = full volume.
    256  Mirror<double> mVolume;
    257 
    258  // Pitch preservation for the playback rate.
    259  Mirror<bool> mPreservesPitch;
    260 
    261  // Whether to seek back to the start of the media resource
    262  // upon reaching the end.
    263  Mirror<bool> mLooping;
    264 
    265  // Set if the decoder is sending video to a secondary container. While set we
    266  // should not suspend the decoder.
    267  Mirror<RefPtr<VideoFrameContainer>> mSecondaryVideoContainer;
    268 
    269  // Duration of the media. This is guaranteed to be non-null after we finish
    270  // decoding the first frame.
    271  Canonical<media::NullableTimeUnit> mDuration;
    272 
    273  // The time of the current frame, corresponding to the "current
    274  // playback position" in HTML5. This is referenced from 0, which is the
    275  // initial playback position.
    276  Canonical<media::TimeUnit> mCurrentPosition;
    277 
    278  // Used to distinguish whether the audio is producing sound.
    279  Canonical<bool> mIsAudioDataAudible;
    280 
    281  // Stores presentation info required for playback.
    282  Maybe<MediaInfo> mInfo;
    283 
    284  // True if the media is seekable (i.e. supports random access).
    285  bool mMediaSeekable = true;
    286 
    287  // True if the media is seekable only in buffered ranges.
    288  bool mMediaSeekableOnlyInBufferedRanges = false;
    289 
    290  // True if we've decoded first frames (thus having the start time) and
    291  // notified the FirstFrameLoaded event. Note we can't initiate seek until the
    292  // start time is known which happens when the first frames are decoded or we
    293  // are playing an MSE stream (the start time is always assumed 0).
    294  bool mSentFirstFrameLoadedEvent = false;
    295 
    296  // True if we should not decode/preroll unnecessary samples, unless we're
    297  // played. "Prerolling" in this context refers to when we decode and
    298  // buffer decoded samples in advance of when they're needed for playback.
    299  // This flag is set for preload=metadata media, and means we won't
    300  // decode more than the first video frame and first block of audio samples
    301  // for that media when we startup, or after a seek. When Play() is called,
    302  // we reset this flag, as we assume the user is playing the media, so
    303  // prerolling is appropriate then. This flag is used to reduce the overhead
    304  // of prerolling samples for media elements that may not play, both
    305  // memory and CPU overhead.
    306  bool mMinimizePreroll;
    307 
    308  // Only one of a given pair of ({Audio,Video}DataPromise, WaitForDataPromise)
    309  // should exist at any given moment.
    310  using AudioDataPromise = MediaFormatReader::AudioDataPromise;
    311  using VideoDataPromise = MediaFormatReader::VideoDataPromise;
    312  using WaitForDataPromise = MediaFormatReader::WaitForDataPromise;
    313  MozPromiseRequestHolder<AudioDataPromise> mAudioDataRequest;
    314  MozPromiseRequestHolder<VideoDataPromise> mVideoDataRequest;
    315  MozPromiseRequestHolder<WaitForDataPromise> mAudioWaitRequest;
    316  MozPromiseRequestHolder<WaitForDataPromise> mVideoWaitRequest;
    317 
    318  // True if playback is live stream.
    319  Atomic<bool> mIsLiveStream;
    320 
    321 private:
    322  WatchManager<MediaDecoderStateMachineBase> mWatchManager;
    323 
    324 #ifdef DEBUG
    325  bool mHasNotifiedPlaybackError = false;
    326 #endif
    327 };
    328 
    329 }  // namespace mozilla
    330 
    331 #endif  // DOM_MEDIA_MEDIADECODERSTATEMACHINEBASE_H_