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_