Bug 1685822 [wpt PR 27117] - [Import Maps] Add tests for rejecting multiple import...
[gecko.git] / dom / media / MediaDecoderStateMachine.h
blob8cca026e9024c87ec484597ba35116fb409f7064
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /*
8 Each media element for a media file has one thread called the "audio thread".
10 The audio thread writes the decoded audio data to the audio
11 hardware. This is done in a separate thread to ensure that the
12 audio hardware gets a constant stream of data without
13 interruption due to decoding or display. At some point
14 AudioStream will be refactored to have a callback interface
15 where it asks for data and this thread will no longer be
16 needed.
18 The element/state machine also has a TaskQueue which runs in a
19 SharedThreadPool that is shared with all other elements/decoders. The state
20 machine dispatches tasks to this to call into the MediaDecoderReader to
21 request decoded audio or video data. The Reader will callback with decoded
22 sampled when it has them available, and the state machine places the decoded
23 samples into its queues for the consuming threads to pull from.
25 The MediaDecoderReader can choose to decode asynchronously, or synchronously
26 and return requested samples synchronously inside it's Request*Data()
27 functions via callback. Asynchronous decoding is preferred, and should be
28 used for any new readers.
30 Synchronisation of state between the thread is done via a monitor owned
31 by MediaDecoder.
33 The lifetime of the audio thread is controlled by the state machine when
34 it runs on the shared state machine thread. When playback needs to occur
35 the audio thread is created and an event dispatched to run it. The audio
36 thread exits when audio playback is completed or no longer required.
38 A/V synchronisation is handled by the state machine. It examines the audio
39 playback time and compares this to the next frame in the queue of video
40 frames. If it is time to play the video frame it is then displayed, otherwise
41 it schedules the state machine to run again at the time of the next frame.
43 Frame skipping is done in the following ways:
45 1) The state machine will skip all frames in the video queue whose
46 display time is less than the current audio time. This ensures
47 the correct frame for the current time is always displayed.
49 2) The decode tasks will stop decoding interframes and read to the
50 next keyframe if it determines that decoding the remaining
51 interframes will cause playback issues. It detects this by:
52 a) If the amount of audio data in the audio queue drops
53 below a threshold whereby audio may start to skip.
54 b) If the video queue drops below a threshold where it
55 will be decoding video data that won't be displayed due
56 to the decode thread dropping the frame immediately.
57 TODO: In future we should only do this when the Reader is decoding
58 synchronously.
60 When hardware accelerated graphics is not available, YCbCr conversion
61 is done on the decode task queue when video frames are decoded.
63 The decode task queue pushes decoded audio and videos frames into two
64 separate queues - one for audio and one for video. These are kept
65 separate to make it easy to constantly feed audio data to the audio
66 hardware while allowing frame skipping of video data. These queues are
67 threadsafe, and neither the decode, audio, or state machine should
68 be able to monopolize them, and cause starvation of the other threads.
70 Both queues are bounded by a maximum size. When this size is reached
71 the decode tasks will no longer request video or audio depending on the
72 queue that has reached the threshold. If both queues are full, no more
73 decode tasks will be dispatched to the decode task queue, so other
74 decoders will have an opportunity to run.
76 During playback the audio thread will be idle (via a Wait() on the
77 monitor) if the audio queue is empty. Otherwise it constantly pops
78 audio data off the queue and plays it with a blocking write to the audio
79 hardware (via AudioStream).
82 #if !defined(MediaDecoderStateMachine_h__)
83 # define MediaDecoderStateMachine_h__
85 # include "AudioDeviceInfo.h"
86 # include "ImageContainer.h"
87 # include "MediaDecoder.h"
88 # include "MediaDecoderOwner.h"
89 # include "MediaEventSource.h"
90 # include "MediaFormatReader.h"
91 # include "MediaMetadataManager.h"
92 # include "MediaQueue.h"
93 # include "MediaSink.h"
94 # include "MediaStatistics.h"
95 # include "MediaTimer.h"
96 # include "SeekJob.h"
97 # include "mozilla/Attributes.h"
98 # include "mozilla/ReentrantMonitor.h"
99 # include "mozilla/StateMirroring.h"
100 # include "mozilla/dom/MediaDebugInfoBinding.h"
101 # include "nsThreadUtils.h"
103 namespace mozilla {
105 class AbstractThread;
106 class AudioSegment;
107 class DecodedStream;
108 class DOMMediaStream;
109 class ReaderProxy;
110 class TaskQueue;
112 extern LazyLogModule gMediaDecoderLog;
114 struct MediaPlaybackEvent {
115 enum EventType {
116 PlaybackStarted,
117 PlaybackStopped,
118 PlaybackProgressed,
119 PlaybackEnded,
120 SeekStarted,
121 Invalidate,
122 EnterVideoSuspend,
123 ExitVideoSuspend,
124 StartVideoSuspendTimer,
125 CancelVideoSuspendTimer,
126 VideoOnlySeekBegin,
127 VideoOnlySeekCompleted,
128 } mType;
130 using DataType = Variant<Nothing, int64_t>;
131 DataType mData;
133 MOZ_IMPLICIT MediaPlaybackEvent(EventType aType)
134 : mType(aType), mData(Nothing{}) {}
136 template <typename T>
137 MediaPlaybackEvent(EventType aType, T&& aArg)
138 : mType(aType), mData(std::forward<T>(aArg)) {}
141 enum class VideoDecodeMode : uint8_t { Normal, Suspend };
143 DDLoggedTypeDeclName(MediaDecoderStateMachine);
146 The state machine class. This manages the decoding and seeking in the
147 MediaDecoderReader on the decode task queue, and A/V sync on the shared
148 state machine thread, and controls the audio "push" thread.
150 All internal state is synchronised via the decoder monitor. State changes
151 are propagated by scheduling the state machine to run another cycle on the
152 shared state machine thread.
154 See MediaDecoder.h for more details.
156 class MediaDecoderStateMachine
157 : public DecoderDoctorLifeLogger<MediaDecoderStateMachine> {
158 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachine)
160 using TrackSet = MediaFormatReader::TrackSet;
162 public:
163 typedef MediaDecoderOwner::NextFrameStatus NextFrameStatus;
164 typedef mozilla::layers::ImageContainer::FrameID FrameID;
165 MediaDecoderStateMachine(MediaDecoder* aDecoder, MediaFormatReader* aReader);
167 nsresult Init(MediaDecoder* aDecoder);
169 // Enumeration for the valid decoding states
170 enum State {
171 DECODER_STATE_DECODING_METADATA,
172 DECODER_STATE_DORMANT,
173 DECODER_STATE_DECODING_FIRSTFRAME,
174 DECODER_STATE_DECODING,
175 DECODER_STATE_LOOPING_DECODING,
176 DECODER_STATE_SEEKING_ACCURATE,
177 DECODER_STATE_SEEKING_FROMDORMANT,
178 DECODER_STATE_SEEKING_NEXTFRAMESEEKING,
179 DECODER_STATE_SEEKING_VIDEOONLY,
180 DECODER_STATE_BUFFERING,
181 DECODER_STATE_COMPLETED,
182 DECODER_STATE_SHUTDOWN
185 // Returns the state machine task queue.
186 TaskQueue* OwnerThread() const { return mTaskQueue; }
188 RefPtr<GenericPromise> RequestDebugInfo(
189 dom::MediaDecoderStateMachineDebugInfo& aInfo);
191 // Seeks to the decoder to aTarget asynchronously.
192 RefPtr<MediaDecoder::SeekPromise> InvokeSeek(const SeekTarget& aTarget);
194 void DispatchSetPlaybackRate(double aPlaybackRate) {
195 OwnerThread()->DispatchStateChange(NewRunnableMethod<double>(
196 "MediaDecoderStateMachine::SetPlaybackRate", this,
197 &MediaDecoderStateMachine::SetPlaybackRate, aPlaybackRate));
200 RefPtr<ShutdownPromise> BeginShutdown();
202 // Set the media fragment end time.
203 void DispatchSetFragmentEndTime(const media::TimeUnit& aEndTime) {
204 RefPtr<MediaDecoderStateMachine> self = this;
205 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
206 "MediaDecoderStateMachine::DispatchSetFragmentEndTime",
207 [self, aEndTime]() {
208 // A negative number means we don't have a fragment end time at all.
209 self->mFragmentEndTime = aEndTime >= media::TimeUnit::Zero()
210 ? aEndTime
211 : media::TimeUnit::Invalid();
213 nsresult rv = OwnerThread()->Dispatch(r.forget());
214 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
215 Unused << rv;
218 void DispatchCanPlayThrough(bool aCanPlayThrough) {
219 RefPtr<MediaDecoderStateMachine> self = this;
220 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
221 "MediaDecoderStateMachine::DispatchCanPlayThrough",
222 [self, aCanPlayThrough]() { self->mCanPlayThrough = aCanPlayThrough; });
223 OwnerThread()->DispatchStateChange(r.forget());
226 void DispatchIsLiveStream(bool aIsLiveStream) {
227 RefPtr<MediaDecoderStateMachine> self = this;
228 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
229 "MediaDecoderStateMachine::DispatchIsLiveStream",
230 [self, aIsLiveStream]() { self->mIsLiveStream = aIsLiveStream; });
231 OwnerThread()->DispatchStateChange(r.forget());
234 TimedMetadataEventSource& TimedMetadataEvent() {
235 return mMetadataManager.TimedMetadataEvent();
238 MediaEventSource<void>& OnMediaNotSeekable() const;
240 MediaEventSourceExc<UniquePtr<MediaInfo>, UniquePtr<MetadataTags>,
241 MediaDecoderEventVisibility>&
242 MetadataLoadedEvent() {
243 return mMetadataLoadedEvent;
246 MediaEventSourceExc<UniquePtr<MediaInfo>, MediaDecoderEventVisibility>&
247 FirstFrameLoadedEvent() {
248 return mFirstFrameLoadedEvent;
251 MediaEventSource<MediaPlaybackEvent>& OnPlaybackEvent() {
252 return mOnPlaybackEvent;
254 MediaEventSource<MediaResult>& OnPlaybackErrorEvent() {
255 return mOnPlaybackErrorEvent;
258 MediaEventSource<DecoderDoctorEvent>& OnDecoderDoctorEvent() {
259 return mOnDecoderDoctorEvent;
262 MediaEventSource<NextFrameStatus>& OnNextFrameStatus() {
263 return mOnNextFrameStatus;
266 MediaEventSourceExc<RefPtr<VideoFrameContainer>>&
267 OnSecondaryVideoContainerInstalled() {
268 return mOnSecondaryVideoContainerInstalled;
271 size_t SizeOfVideoQueue() const;
273 size_t SizeOfAudioQueue() const;
275 // Sets the video decode mode. Used by the suspend-video-decoder feature.
276 void SetVideoDecodeMode(VideoDecodeMode aMode);
278 RefPtr<GenericPromise> InvokeSetSink(RefPtr<AudioDeviceInfo> aSink);
280 void InvokeSuspendMediaSink();
281 void InvokeResumeMediaSink();
283 private:
284 class StateObject;
285 class DecodeMetadataState;
286 class DormantState;
287 class DecodingFirstFrameState;
288 class DecodingState;
289 class LoopingDecodingState;
290 class SeekingState;
291 class AccurateSeekingState;
292 class NextFrameSeekingState;
293 class NextFrameSeekingFromDormantState;
294 class VideoOnlySeekingState;
295 class BufferingState;
296 class CompletedState;
297 class ShutdownState;
299 static const char* ToStateStr(State aState);
300 const char* ToStateStr();
302 void GetDebugInfo(dom::MediaDecoderStateMachineDebugInfo& aInfo);
304 // Functions used by assertions to ensure we're calling things
305 // on the appropriate threads.
306 bool OnTaskQueue() const;
308 // Initialization that needs to happen on the task queue. This is the first
309 // task that gets run on the task queue, and is dispatched from the MDSM
310 // constructor immediately after the task queue is created.
311 void InitializationTask(MediaDecoder* aDecoder);
313 RefPtr<MediaDecoder::SeekPromise> Seek(const SeekTarget& aTarget);
315 RefPtr<ShutdownPromise> Shutdown();
317 RefPtr<ShutdownPromise> FinishShutdown();
319 // Update the playback position. This can result in a timeupdate event
320 // and an invalidate of the frame being dispatched asynchronously if
321 // there is no such event currently queued.
322 // Only called on the decoder thread. Must be called with
323 // the decode monitor held.
324 void UpdatePlaybackPosition(const media::TimeUnit& aTime);
326 bool HasAudio() const { return mInfo.ref().HasAudio(); }
327 bool HasVideo() const { return mInfo.ref().HasVideo(); }
328 const MediaInfo& Info() const { return mInfo.ref(); }
330 // Schedules the shared state machine thread to run the state machine.
331 void ScheduleStateMachine();
333 // Invokes ScheduleStateMachine to run in |aTime|,
334 // unless it's already scheduled to run earlier, in which case the
335 // request is discarded.
336 void ScheduleStateMachineIn(const media::TimeUnit& aTime);
338 bool HaveEnoughDecodedAudio();
339 bool HaveEnoughDecodedVideo();
341 // Returns true if we're currently playing. The decoder monitor must
342 // be held.
343 bool IsPlaying() const;
345 // Sets mMediaSeekable to false.
346 void SetMediaNotSeekable();
348 // Resets all states related to decoding and aborts all pending requests
349 // to the decoders.
350 void ResetDecode(TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack,
351 TrackInfo::kVideoTrack));
353 void SetVideoDecodeModeInternal(VideoDecodeMode aMode);
355 // Set new sink device and restart MediaSink if playback is started.
356 // Returned promise will be resolved with true if the playback is
357 // started and false if playback is stopped after setting the new sink.
358 // Returned promise will be rejected with value NS_ERROR_ABORT
359 // if the action fails or it is not supported.
360 // If there are multiple pending requests only the last one will be
361 // executed, for all previous requests the promise will be resolved
362 // with true or false similar to above.
363 RefPtr<GenericPromise> SetSink(RefPtr<AudioDeviceInfo> aSink);
365 // Shutdown MediaSink on suspend to clean up resources.
366 void SuspendMediaSink();
367 // Create a new MediaSink, it must have been stopped first.
368 void ResumeMediaSink();
370 protected:
371 virtual ~MediaDecoderStateMachine();
373 void BufferedRangeUpdated();
375 void ReaderSuspendedChanged();
377 // Inserts a sample into the Audio/Video queue.
378 // aSample must not be null.
379 void PushAudio(AudioData* aSample);
380 void PushVideo(VideoData* aSample);
382 void OnAudioPopped(const RefPtr<AudioData>& aSample);
383 void OnVideoPopped(const RefPtr<VideoData>& aSample);
385 void AudioAudibleChanged(bool aAudible);
387 void VolumeChanged();
388 void SetPlaybackRate(double aPlaybackRate);
389 void PreservesPitchChanged();
390 void LoopingChanged();
391 void UpdateSecondaryVideoContainer();
392 void UpdateOutputCaptured();
393 void OutputTracksChanged();
394 void OutputPrincipalChanged();
396 MediaQueue<AudioData>& AudioQueue() { return mAudioQueue; }
397 MediaQueue<VideoData>& VideoQueue() { return mVideoQueue; }
399 // True if we are low in decoded audio/video data.
400 // May not be invoked when mReader->UseBufferingHeuristics() is false.
401 bool HasLowDecodedData();
403 bool HasLowDecodedAudio();
405 bool HasLowDecodedVideo();
407 bool OutOfDecodedAudio();
409 bool OutOfDecodedVideo() {
410 MOZ_ASSERT(OnTaskQueue());
411 return IsVideoDecoding() && VideoQueue().GetSize() <= 1;
414 // Returns true if we're running low on buffered data.
415 bool HasLowBufferedData();
417 // Returns true if we have less than aThreshold of buffered data available.
418 bool HasLowBufferedData(const media::TimeUnit& aThreshold);
420 // Return the current time, either the audio clock if available (if the media
421 // has audio, and the playback is possible), or a clock for the video.
422 // Called on the state machine thread.
423 // If aTimeStamp is non-null, set *aTimeStamp to the TimeStamp corresponding
424 // to the returned stream time.
425 media::TimeUnit GetClock(TimeStamp* aTimeStamp = nullptr) const;
427 // Update only the state machine's current playback position (and duration,
428 // if unknown). Does not update the playback position on the decoder or
429 // media element -- use UpdatePlaybackPosition for that. Called on the state
430 // machine thread, caller must hold the decoder lock.
431 void UpdatePlaybackPositionInternal(const media::TimeUnit& aTime);
433 // Update playback position and trigger next update by default time period.
434 // Called on the state machine thread.
435 void UpdatePlaybackPositionPeriodically();
437 MediaSink* CreateAudioSink();
439 // Always create mediasink which contains an AudioSink or DecodedStream
440 // inside.
441 already_AddRefed<MediaSink> CreateMediaSink();
443 // Stops the media sink and shut it down.
444 // The decoder monitor must be held with exactly one lock count.
445 // Called on the state machine thread.
446 void StopMediaSink();
448 // Create and start the media sink.
449 // The decoder monitor must be held with exactly one lock count.
450 // Called on the state machine thread.
451 // If start fails an NS_ERROR_FAILURE is returned.
452 nsresult StartMediaSink();
454 // Notification method invoked when mPlayState changes.
455 void PlayStateChanged();
457 // Notification method invoked when mIsVisible changes.
458 void VisibilityChanged();
460 // Sets internal state which causes playback of media to pause.
461 // The decoder monitor must be held.
462 void StopPlayback();
464 // If the conditions are right, sets internal state which causes playback
465 // of media to begin or resume.
466 // Must be called with the decode monitor held.
467 void MaybeStartPlayback();
469 // Moves the decoder into the shutdown state, and dispatches an error
470 // event to the media element. This begins shutting down the decoder.
471 // The decoder monitor must be held. This is only called on the
472 // decode thread.
473 void DecodeError(const MediaResult& aError);
475 void EnqueueFirstFrameLoadedEvent();
477 // Start a task to decode audio.
478 void RequestAudioData();
480 // Start a task to decode video.
481 void RequestVideoData(const media::TimeUnit& aCurrentTime);
483 void WaitForData(MediaData::Type aType);
485 bool IsRequestingAudioData() const { return mAudioDataRequest.Exists(); }
486 bool IsRequestingVideoData() const { return mVideoDataRequest.Exists(); }
487 bool IsWaitingAudioData() const { return mAudioWaitRequest.Exists(); }
488 bool IsWaitingVideoData() const { return mVideoWaitRequest.Exists(); }
490 // Returns the "media time". This is the absolute time which the media
491 // playback has reached. i.e. this returns values in the range
492 // [mStartTime, mEndTime], and mStartTime will not be 0 if the media does
493 // not start at 0. Note this is different than the "current playback
494 // position", which is in the range [0,duration].
495 media::TimeUnit GetMediaTime() const {
496 MOZ_ASSERT(OnTaskQueue());
497 return mCurrentPosition;
500 // Returns an upper bound on the number of microseconds of audio that is
501 // decoded and playable. This is the sum of the number of usecs of audio which
502 // is decoded and in the reader's audio queue, and the usecs of unplayed audio
503 // which has been pushed to the audio hardware for playback. Note that after
504 // calling this, the audio hardware may play some of the audio pushed to
505 // hardware, so this can only be used as a upper bound. The decoder monitor
506 // must be held when calling this. Called on the decode thread.
507 media::TimeUnit GetDecodedAudioDuration();
509 void FinishDecodeFirstFrame();
511 // Performs one "cycle" of the state machine.
512 void RunStateMachine();
514 bool IsStateMachineScheduled() const;
516 // These return true if the respective stream's decode has not yet reached
517 // the end of stream.
518 bool IsAudioDecoding();
519 bool IsVideoDecoding();
521 private:
522 // Resolved by the MediaSink to signal that all audio/video outstanding
523 // work is complete and identify which part(a/v) of the sink is shutting down.
524 void OnMediaSinkAudioComplete();
525 void OnMediaSinkVideoComplete();
527 // Rejected by the MediaSink to signal errors for audio/video.
528 void OnMediaSinkAudioError(nsresult aResult);
529 void OnMediaSinkVideoError();
531 void* const mDecoderID;
532 const RefPtr<AbstractThread> mAbstractMainThread;
533 const RefPtr<FrameStatistics> mFrameStats;
534 const RefPtr<VideoFrameContainer> mVideoFrameContainer;
536 // Task queue for running the state machine.
537 RefPtr<TaskQueue> mTaskQueue;
539 // State-watching manager.
540 WatchManager<MediaDecoderStateMachine> mWatchManager;
542 // True if we've dispatched a task to run the state machine but the task has
543 // yet to run.
544 bool mDispatchedStateMachine;
546 // Used to dispatch another round schedule with specific target time.
547 DelayedScheduler mDelayedScheduler;
549 // Queue of audio frames. This queue is threadsafe, and is accessed from
550 // the audio, decoder, state machine, and main threads.
551 MediaQueue<AudioData> mAudioQueue;
552 // Queue of video frames. This queue is threadsafe, and is accessed from
553 // the decoder, state machine, and main threads.
554 MediaQueue<VideoData> mVideoQueue;
556 UniquePtr<StateObject> mStateObj;
558 media::TimeUnit Duration() const {
559 MOZ_ASSERT(OnTaskQueue());
560 return mDuration.Ref().ref();
563 // FrameID which increments every time a frame is pushed to our queue.
564 FrameID mCurrentFrameID;
566 // Media Fragment end time.
567 media::TimeUnit mFragmentEndTime = media::TimeUnit::Invalid();
569 // The media sink resource. Used on the state machine thread.
570 RefPtr<MediaSink> mMediaSink;
572 const RefPtr<ReaderProxy> mReader;
574 // The end time of the last audio frame that's been pushed onto the media sink
575 // in microseconds. This will approximately be the end time
576 // of the audio stream, unless another frame is pushed to the hardware.
577 media::TimeUnit AudioEndTime() const;
579 // The end time of the last rendered video frame that's been sent to
580 // compositor.
581 media::TimeUnit VideoEndTime() const;
583 // The end time of the last decoded audio frame. This signifies the end of
584 // decoded audio data. Used to check if we are low in decoded data.
585 media::TimeUnit mDecodedAudioEndTime;
587 // The end time of the last decoded video frame. Used to check if we are low
588 // on decoded video data.
589 media::TimeUnit mDecodedVideoEndTime;
591 // Playback rate. 1.0 : normal speed, 0.5 : two times slower.
592 double mPlaybackRate;
594 // If we've got more than this number of decoded video frames waiting in
595 // the video queue, we will not decode any more video frames until some have
596 // been consumed by the play state machine thread.
597 // Must hold monitor.
598 uint32_t GetAmpleVideoFrames() const;
600 // Our "ample" audio threshold. Once we've this much audio decoded, we
601 // pause decoding.
602 media::TimeUnit mAmpleAudioThreshold;
604 // Only one of a given pair of ({Audio,Video}DataPromise, WaitForDataPromise)
605 // should exist at any given moment.
606 using AudioDataPromise = MediaFormatReader::AudioDataPromise;
607 using VideoDataPromise = MediaFormatReader::VideoDataPromise;
608 using WaitForDataPromise = MediaFormatReader::WaitForDataPromise;
609 MozPromiseRequestHolder<AudioDataPromise> mAudioDataRequest;
610 MozPromiseRequestHolder<VideoDataPromise> mVideoDataRequest;
611 MozPromiseRequestHolder<WaitForDataPromise> mAudioWaitRequest;
612 MozPromiseRequestHolder<WaitForDataPromise> mVideoWaitRequest;
614 const char* AudioRequestStatus() const;
615 const char* VideoRequestStatus() const;
617 void OnSuspendTimerResolved();
618 void CancelSuspendTimer();
620 bool IsInSeamlessLooping() const;
622 bool mCanPlayThrough = false;
624 bool mIsLiveStream = false;
626 // True if all audio frames are already rendered.
627 bool mAudioCompleted = false;
629 // True if all video frames are already rendered.
630 bool mVideoCompleted = false;
632 // True if we should not decode/preroll unnecessary samples, unless we're
633 // played. "Prerolling" in this context refers to when we decode and
634 // buffer decoded samples in advance of when they're needed for playback.
635 // This flag is set for preload=metadata media, and means we won't
636 // decode more than the first video frame and first block of audio samples
637 // for that media when we startup, or after a seek. When Play() is called,
638 // we reset this flag, as we assume the user is playing the media, so
639 // prerolling is appropriate then. This flag is used to reduce the overhead
640 // of prerolling samples for media elements that may not play, both
641 // memory and CPU overhead.
642 bool mMinimizePreroll;
644 // Stores presentation info required for playback.
645 Maybe<MediaInfo> mInfo;
647 mozilla::MediaMetadataManager mMetadataManager;
649 // True if we've decoded first frames (thus having the start time) and
650 // notified the FirstFrameLoaded event. Note we can't initiate seek until the
651 // start time is known which happens when the first frames are decoded or we
652 // are playing an MSE stream (the start time is always assumed 0).
653 bool mSentFirstFrameLoadedEvent;
655 // True if video decoding is suspended.
656 bool mVideoDecodeSuspended;
658 // True if the media is seekable (i.e. supports random access).
659 bool mMediaSeekable = true;
661 // True if the media is seekable only in buffered ranges.
662 bool mMediaSeekableOnlyInBufferedRanges = false;
664 // Track enabling video decode suspension via timer
665 DelayedScheduler mVideoDecodeSuspendTimer;
667 // Track the current video decode mode.
668 VideoDecodeMode mVideoDecodeMode;
670 // Track the complete & error for audio/video separately
671 MozPromiseRequestHolder<MediaSink::EndedPromise> mMediaSinkAudioEndedPromise;
672 MozPromiseRequestHolder<MediaSink::EndedPromise> mMediaSinkVideoEndedPromise;
674 MediaEventListener mAudioQueueListener;
675 MediaEventListener mVideoQueueListener;
676 MediaEventListener mAudibleListener;
677 MediaEventListener mOnMediaNotSeekable;
679 MediaEventProducerExc<UniquePtr<MediaInfo>, UniquePtr<MetadataTags>,
680 MediaDecoderEventVisibility>
681 mMetadataLoadedEvent;
682 MediaEventProducerExc<UniquePtr<MediaInfo>, MediaDecoderEventVisibility>
683 mFirstFrameLoadedEvent;
685 MediaEventProducer<MediaPlaybackEvent> mOnPlaybackEvent;
686 MediaEventProducer<MediaResult> mOnPlaybackErrorEvent;
688 MediaEventProducer<DecoderDoctorEvent> mOnDecoderDoctorEvent;
690 MediaEventProducer<NextFrameStatus> mOnNextFrameStatus;
692 MediaEventProducerExc<RefPtr<VideoFrameContainer>>
693 mOnSecondaryVideoContainerInstalled;
695 const bool mIsMSE;
697 bool mSeamlessLoopingAllowed;
699 // If media was in looping and had reached to the end before, then we need
700 // to adjust sample time from clock time to media time.
701 void AdjustByLooping(media::TimeUnit& aTime) const;
702 Maybe<media::TimeUnit> mAudioDecodedDuration;
704 // Current playback position in the stream in bytes.
705 int64_t mPlaybackOffset = 0;
707 private:
708 // The buffered range. Mirrored from the decoder thread.
709 Mirror<media::TimeIntervals> mBuffered;
711 // The current play state, mirrored from the main thread.
712 Mirror<MediaDecoder::PlayState> mPlayState;
714 // Volume of playback. 0.0 = muted. 1.0 = full volume.
715 Mirror<double> mVolume;
717 // Pitch preservation for the playback rate.
718 Mirror<bool> mPreservesPitch;
720 // Whether to seek back to the start of the media resource
721 // upon reaching the end.
722 Mirror<bool> mLooping;
724 // The device used with SetSink, or nullptr if no explicit device has been
725 // set.
726 Mirror<RefPtr<AudioDeviceInfo>> mSinkDevice;
728 // Set if the decoder is sending video to a secondary container. While set we
729 // should not suspend the decoder.
730 Mirror<RefPtr<VideoFrameContainer>> mSecondaryVideoContainer;
732 // Whether all output should be captured into mOutputTracks, halted, or not
733 // captured.
734 Mirror<MediaDecoder::OutputCaptureState> mOutputCaptureState;
736 // A dummy track used to access the right MediaTrackGraph instance. Needed
737 // since there's no guarantee that output tracks are present.
738 Mirror<nsMainThreadPtrHandle<SharedDummyTrack>> mOutputDummyTrack;
740 // Tracks to capture data into.
741 Mirror<CopyableTArray<RefPtr<ProcessedMediaTrack>>> mOutputTracks;
743 // PrincipalHandle to feed with data captured into mOutputTracks.
744 Mirror<PrincipalHandle> mOutputPrincipal;
746 Canonical<CopyableTArray<RefPtr<ProcessedMediaTrack>>> mCanonicalOutputTracks;
747 Canonical<PrincipalHandle> mCanonicalOutputPrincipal;
749 // Duration of the media. This is guaranteed to be non-null after we finish
750 // decoding the first frame.
751 Canonical<media::NullableTimeUnit> mDuration;
753 // The time of the current frame, corresponding to the "current
754 // playback position" in HTML5. This is referenced from 0, which is the
755 // initial playback position.
756 Canonical<media::TimeUnit> mCurrentPosition;
758 // Used to distinguish whether the audio is producing sound.
759 Canonical<bool> mIsAudioDataAudible;
761 // Track when MediaSink is supsended. When that happens some actions are
762 // restricted like starting the sink or changing sink id. The flag is valid
763 // after Initialization. TaskQueue thread only.
764 bool mIsMediaSinkSuspended = false;
766 public:
767 AbstractCanonical<media::TimeIntervals>* CanonicalBuffered() const;
769 AbstractCanonical<CopyableTArray<RefPtr<ProcessedMediaTrack>>>*
770 CanonicalOutputTracks() {
771 return &mCanonicalOutputTracks;
773 AbstractCanonical<PrincipalHandle>* CanonicalOutputPrincipal() {
774 return &mCanonicalOutputPrincipal;
776 AbstractCanonical<media::NullableTimeUnit>* CanonicalDuration() {
777 return &mDuration;
779 AbstractCanonical<media::TimeUnit>* CanonicalCurrentPosition() {
780 return &mCurrentPosition;
782 AbstractCanonical<bool>* CanonicalIsAudioDataAudible() {
783 return &mIsAudioDataAudible;
787 } // namespace mozilla
789 #endif