Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
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 /*
7 Each video element based on MediaDecoder has a state machine to manage
8 its play state and keep the current frame up to date. All state machines
9 share time in a single shared thread. Each decoder also has one thread
10 dedicated to decoding audio and video data. This thread is shutdown when
11 playback is paused. Each decoder also has a thread to push decoded audio
12 to the hardware. This thread is not created until playback starts, but
13 currently is not destroyed when paused, only when playback ends.
15 The decoder owns the resources for downloading the media file, and the
16 high level state. It holds an owning reference to the state machine that
17 owns all the resources related to decoding data, and manages the low level
18 decoding operations and A/V sync.
20 Each state machine runs on the shared state machine thread. Every time some
21 action is required for a state machine, it is scheduled to run on the shared
22 the state machine thread. The state machine runs one "cycle" on the state
23 machine thread, and then returns. If necessary, it will schedule itself to
24 run again in future. While running this cycle, it must not block the
25 thread, as other state machines' events may need to run. State shared
26 between a state machine's threads is synchronised via the monitor owned
27 by its MediaDecoder object.
29 The Main thread controls the decode state machine by setting the value
30 of a mPlayState variable and notifying on the monitor based on the
31 high level player actions required (Seek, Pause, Play, etc).
33 The player states are the states requested by the client through the
34 DOM API. They represent the desired state of the player, while the
35 decoder's state represents the actual state of the decoder.
37 The high level state of the player is maintained via a PlayState value.
38 It can have the following states:
40 START
41 The decoder has been initialized but has no resource loaded.
42 PAUSED
43 A request via the API has been received to pause playback.
44 LOADING
45 A request via the API has been received to load a resource.
46 PLAYING
47 A request via the API has been received to start playback.
48 SEEKING
49 A request via the API has been received to start seeking.
50 COMPLETED
51 Playback has completed.
52 SHUTDOWN
53 The decoder is about to be destroyed.
55 State transition occurs when the Media Element calls the Play, Seek,
56 etc methods on the MediaDecoder object. When the transition
57 occurs MediaDecoder then calls the methods on the decoder state
58 machine object to cause it to behave as required by the play state.
59 State transitions will likely schedule the state machine to run to
60 affect the change.
62 An implementation of the MediaDecoderStateMachine class is the event
63 that gets dispatched to the state machine thread. Each time the event is run,
64 the state machine must cycle the state machine once, and then return.
66 The state machine has the following states:
68 DECODING_METADATA
69 The media headers are being loaded, and things like framerate, etc are
70 being determined, and the first frame of audio/video data is being decoded.
71 DECODING
72 The decode has started. If the PlayState is PLAYING, the decode thread
73 should be alive and decoding video and audio frame, the audio thread
74 should be playing audio, and the state machine should run periodically
75 to update the video frames being displayed.
76 SEEKING
77 A seek operation is in progress. The decode thread should be seeking.
78 BUFFERING
79 Decoding is paused while data is buffered for smooth playback. If playback
80 is paused (PlayState transitions to PAUSED) we'll destory the decode thread.
81 COMPLETED
82 The resource has completed decoding, but possibly not finished playback.
83 The decode thread will be destroyed. Once playback finished, the audio
84 thread will also be destroyed.
85 SHUTDOWN
86 The decoder object and its state machine are about to be destroyed.
87 Once the last state machine has been destroyed, the shared state machine
88 thread will also be destroyed. It will be recreated later if needed.
90 The following result in state transitions.
92 Shutdown()
93 Clean up any resources the MediaDecoderStateMachine owns.
94 Play()
95 Start decoding and playback of media data.
96 Buffer
97 This is not user initiated. It occurs when the
98 available data in the stream drops below a certain point.
99 Complete
100 This is not user initiated. It occurs when the
101 stream is completely decoded.
102 Seek(double)
103 Seek to the time position given in the resource.
105 A state transition diagram:
107 DECODING_METADATA
108 | |
109 v | Shutdown()
110 | |
111 v -->-------------------->--------------------------|
112 |---------------->----->------------------------| v
113 DECODING | | | | |
114 ^ v Seek(t) | | | |
115 | Play() | v | | |
116 ^-----------<----SEEKING | v Complete v v
117 | | | | | |
118 | | | COMPLETED SHUTDOWN-<-|
119 ^ ^ | |Shutdown() |
120 | | | >-------->-----^
121 | Play() |Seek(t) |Buffer() |
122 -----------<--------<-------BUFFERING |
123 | ^
124 v Shutdown() |
125 | |
126 ------------>-----|
128 The following represents the states that the MediaDecoder object
129 can be in, and the valid states the MediaDecoderStateMachine can be in at that
130 time:
132 player LOADING decoder DECODING_METADATA
133 player PLAYING decoder DECODING, BUFFERING, SEEKING, COMPLETED
134 player PAUSED decoder DECODING, BUFFERING, SEEKING, COMPLETED
135 player SEEKING decoder SEEKING
136 player COMPLETED decoder SHUTDOWN
137 player SHUTDOWN decoder SHUTDOWN
139 The general sequence of events is:
141 1) The video element calls Load on MediaDecoder. This creates the
142 state machine and starts the channel for downloading the
143 file. It instantiates and schedules the MediaDecoderStateMachine. The
144 high level LOADING state is entered, which results in the decode
145 thread being created and starting to decode metadata. These are
146 the headers that give the video size, framerate, etc. Load() returns
147 immediately to the calling video element.
149 2) When the metadata has been loaded by the decode thread, the state machine
150 will call a method on the video element object to inform it that this
151 step is done, so it can do the things required by the video specification
152 at this stage. The decode thread then continues to decode the first frame
153 of data.
155 3) When the first frame of data has been successfully decoded the state
156 machine calls a method on the video element object to inform it that
157 this step has been done, once again so it can do the required things
158 by the video specification at this stage.
160 This results in the high level state changing to PLAYING or PAUSED
161 depending on any user action that may have occurred.
163 While the play state is PLAYING, the decode thread will decode
164 data, and the audio thread will push audio data to the hardware to
165 be played. The state machine will run periodically on the shared
166 state machine thread to ensure video frames are played at the
167 correct time; i.e. the state machine manages A/V sync.
169 The Shutdown method on MediaDecoder closes the download channel, and
170 signals to the state machine that it should shutdown. The state machine
171 shuts down asynchronously, and will release the owning reference to the
172 state machine once its threads are shutdown.
174 The owning object of a MediaDecoder object *MUST* call Shutdown when
175 destroying the MediaDecoder object.
177 */
178 #if !defined(MediaDecoder_h_)
179 #define MediaDecoder_h_
181 #include "nsISupports.h"
182 #include "nsCOMPtr.h"
183 #include "nsIObserver.h"
184 #include "nsAutoPtr.h"
185 #include "MediaResource.h"
186 #include "mozilla/dom/AudioChannelBinding.h"
187 #include "mozilla/gfx/Rect.h"
188 #include "mozilla/ReentrantMonitor.h"
189 #include "mozilla/TimeStamp.h"
190 #include "MediaStreamGraph.h"
191 #include "AbstractMediaDecoder.h"
192 #include "necko-config.h"
194 class nsIStreamListener;
195 class nsIPrincipal;
196 class nsITimer;
198 namespace mozilla {
199 namespace dom {
200 class TimeRanges;
201 }
202 }
204 namespace mozilla {
205 namespace layers {
206 class Image;
207 } //namespace layers
209 class VideoFrameContainer;
210 class MediaDecoderStateMachine;
211 class MediaDecoderOwner;
213 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
214 // GetTickCount() and conflicts with MediaDecoder::GetCurrentTime implementation.
215 #ifdef GetCurrentTime
216 #undef GetCurrentTime
217 #endif
219 // Stores the seek target; the time to seek to, and whether an Accurate,
220 // or "Fast" (nearest keyframe) seek was requested.
221 struct SeekTarget {
222 enum Type {
223 Invalid,
224 PrevSyncPoint,
225 Accurate
226 };
227 SeekTarget()
228 : mTime(-1.0)
229 , mType(SeekTarget::Invalid)
230 {
231 }
232 SeekTarget(int64_t aTimeUsecs, Type aType)
233 : mTime(aTimeUsecs)
234 , mType(aType)
235 {
236 }
237 bool IsValid() const {
238 return mType != SeekTarget::Invalid;
239 }
240 void Reset() {
241 mTime = -1;
242 mType = SeekTarget::Invalid;
243 }
244 // Seek target time in microseconds.
245 int64_t mTime;
246 // Whether we should seek "Fast", or "Accurate".
247 // "Fast" seeks to the seek point preceeding mTime, whereas
248 // "Accurate" seeks as close as possible to mTime.
249 Type mType;
250 };
252 class MediaDecoder : public nsIObserver,
253 public AbstractMediaDecoder
254 {
255 public:
256 class DecodedStreamGraphListener;
258 NS_DECL_THREADSAFE_ISUPPORTS
259 NS_DECL_NSIOBSERVER
261 // Enumeration for the valid play states (see mPlayState)
262 enum PlayState {
263 PLAY_STATE_START,
264 PLAY_STATE_LOADING,
265 PLAY_STATE_PAUSED,
266 PLAY_STATE_PLAYING,
267 PLAY_STATE_SEEKING,
268 PLAY_STATE_ENDED,
269 PLAY_STATE_SHUTDOWN
270 };
272 MediaDecoder();
273 virtual ~MediaDecoder();
275 // Reset the decoder and notify the media element that
276 // server connection is closed.
277 virtual void ResetConnectionState();
278 // Create a new decoder of the same type as this one.
279 // Subclasses must implement this.
280 virtual MediaDecoder* Clone() = 0;
281 // Create a new state machine to run this decoder.
282 // Subclasses must implement this.
283 virtual MediaDecoderStateMachine* CreateStateMachine() = 0;
285 // Call on the main thread only.
286 // Perform any initialization required for the decoder.
287 // Return true on successful initialisation, false
288 // on failure.
289 virtual bool Init(MediaDecoderOwner* aOwner);
291 // Cleanup internal data structures. Must be called on the main
292 // thread by the owning object before that object disposes of this object.
293 virtual void Shutdown();
295 // Start downloading the media. Decode the downloaded data up to the
296 // point of the first frame of data.
297 // This is called at most once per decoder, after Init().
298 virtual nsresult Load(nsIStreamListener** aListener,
299 MediaDecoder* aCloneDonor);
301 // Called in |Load| to open mResource.
302 nsresult OpenResource(nsIStreamListener** aStreamListener);
304 // Called when the video file has completed downloading.
305 virtual void ResourceLoaded();
307 // Called if the media file encounters a network error.
308 virtual void NetworkError();
310 // Get the current MediaResource being used. Its URI will be returned
311 // by currentSrc. Returns what was passed to Load(), if Load() has been called.
312 // Note: The MediaResource is refcounted, but it outlives the MediaDecoder,
313 // so it's OK to use the reference returned by this function without
314 // refcounting, *unless* you need to store and use the reference after the
315 // MediaDecoder has been destroyed. You might need to do this if you're
316 // wrapping the MediaResource in some kind of byte stream interface to be
317 // passed to a platform decoder.
318 MediaResource* GetResource() const MOZ_FINAL MOZ_OVERRIDE
319 {
320 return mResource;
321 }
322 void SetResource(MediaResource* aResource)
323 {
324 NS_ASSERTION(NS_IsMainThread(), "Should only be called on main thread");
325 mResource = aResource;
326 }
328 // Return the principal of the current URI being played or downloaded.
329 virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
331 // Return the time position in the video stream being
332 // played measured in seconds.
333 virtual double GetCurrentTime();
335 // Seek to the time position in (seconds) from the start of the video.
336 // If aDoFastSeek is true, we'll seek to the sync point/keyframe preceeding
337 // the seek target.
338 virtual nsresult Seek(double aTime, SeekTarget::Type aSeekType);
340 // Enables decoders to supply an enclosing byte range for a seek offset.
341 // E.g. used by ChannelMediaResource to download a whole cluster for
342 // DASH-WebM.
343 virtual nsresult GetByteRangeForSeek(int64_t const aOffset,
344 MediaByteRange &aByteRange) {
345 return NS_ERROR_NOT_AVAILABLE;
346 }
348 // Initialize state machine and schedule it.
349 nsresult InitializeStateMachine(MediaDecoder* aCloneDonor);
351 // Start playback of a video. 'Load' must have previously been
352 // called.
353 virtual nsresult Play();
355 // Set/Unset dormant state if necessary.
356 // Dormant state is a state to free all scarce media resources
357 // (like hw video codec), did not decoding and stay dormant.
358 // It is used to share scarece media resources in system.
359 virtual void SetDormantIfNecessary(bool aDormant);
361 // Pause video playback.
362 virtual void Pause();
363 // Adjust the speed of the playback, optionally with pitch correction,
364 virtual void SetVolume(double aVolume);
365 // Sets whether audio is being captured. If it is, we won't play any
366 // of our audio.
367 virtual void SetAudioCaptured(bool aCaptured);
369 virtual void NotifyWaitingForResourcesStatusChanged() MOZ_OVERRIDE;
371 virtual void SetPlaybackRate(double aPlaybackRate);
372 void SetPreservesPitch(bool aPreservesPitch);
374 // Directs the decoder to not preroll extra samples until the media is
375 // played. This reduces the memory overhead of media elements that may
376 // not be played. Note that seeking also doesn't cause us start prerolling.
377 void SetMinimizePrerollUntilPlaybackStarts();
379 // All MediaStream-related data is protected by mReentrantMonitor.
380 // We have at most one DecodedStreamData per MediaDecoder. Its stream
381 // is used as the input for each ProcessedMediaStream created by calls to
382 // captureStream(UntilEnded). Seeking creates a new source stream, as does
383 // replaying after the input as ended. In the latter case, the new source is
384 // not connected to streams created by captureStreamUntilEnded.
386 struct DecodedStreamData {
387 typedef gfx::IntSize IntSize;
389 DecodedStreamData(MediaDecoder* aDecoder,
390 int64_t aInitialTime, SourceMediaStream* aStream);
391 ~DecodedStreamData();
393 StreamTime GetLastOutputTime() { return mListener->GetLastOutputTime(); }
394 bool IsFinished() { return mListener->IsFinishedOnMainThread(); }
396 // The following group of fields are protected by the decoder's monitor
397 // and can be read or written on any thread.
398 int64_t mLastAudioPacketTime; // microseconds
399 int64_t mLastAudioPacketEndTime; // microseconds
400 // Count of audio frames written to the stream
401 int64_t mAudioFramesWritten;
402 // Saved value of aInitialTime. Timestamp of the first audio and/or
403 // video packet written.
404 int64_t mInitialTime; // microseconds
405 // mNextVideoTime is the end timestamp for the last packet sent to the stream.
406 // Therefore video packets starting at or after this time need to be copied
407 // to the output stream.
408 int64_t mNextVideoTime; // microseconds
409 MediaDecoder* mDecoder;
410 // The last video image sent to the stream. Useful if we need to replicate
411 // the image.
412 nsRefPtr<layers::Image> mLastVideoImage;
413 IntSize mLastVideoImageDisplaySize;
414 // This is set to true when the stream is initialized (audio and
415 // video tracks added).
416 bool mStreamInitialized;
417 bool mHaveSentFinish;
418 bool mHaveSentFinishAudio;
419 bool mHaveSentFinishVideo;
421 // The decoder is responsible for calling Destroy() on this stream.
422 // Can be read from any thread.
423 const nsRefPtr<SourceMediaStream> mStream;
424 // Can be read from any thread.
425 nsRefPtr<DecodedStreamGraphListener> mListener;
426 // True when we've explicitly blocked this stream because we're
427 // not in PLAY_STATE_PLAYING. Used on the main thread only.
428 bool mHaveBlockedForPlayState;
429 // We also have an explicit blocker on the stream when
430 // mDecoderStateMachine is non-null and MediaDecoderStateMachine is false.
431 bool mHaveBlockedForStateMachineNotPlaying;
432 };
434 class DecodedStreamGraphListener : public MediaStreamListener {
435 public:
436 DecodedStreamGraphListener(MediaStream* aStream, DecodedStreamData* aData);
437 virtual void NotifyOutput(MediaStreamGraph* aGraph, GraphTime aCurrentTime) MOZ_OVERRIDE;
438 virtual void NotifyFinished(MediaStreamGraph* aGraph) MOZ_OVERRIDE;
440 void DoNotifyFinished();
442 StreamTime GetLastOutputTime()
443 {
444 MutexAutoLock lock(mMutex);
445 return mLastOutputTime;
446 }
447 void Forget()
448 {
449 NS_ASSERTION(NS_IsMainThread(), "Main thread only");
450 mData = nullptr;
452 MutexAutoLock lock(mMutex);
453 mStream = nullptr;
454 }
455 bool SetFinishedOnMainThread(bool aFinished)
456 {
457 MutexAutoLock lock(mMutex);
458 bool result = !mStreamFinishedOnMainThread;
459 mStreamFinishedOnMainThread = aFinished;
460 return result;
461 }
462 bool IsFinishedOnMainThread()
463 {
464 MutexAutoLock lock(mMutex);
465 return mStreamFinishedOnMainThread;
466 }
467 private:
468 // Main thread only
469 DecodedStreamData* mData;
471 Mutex mMutex;
472 // Protected by mMutex
473 nsRefPtr<MediaStream> mStream;
474 // Protected by mMutex
475 StreamTime mLastOutputTime;
476 // Protected by mMutex
477 bool mStreamFinishedOnMainThread;
478 };
480 struct OutputStreamData {
481 void Init(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
482 {
483 mStream = aStream;
484 mFinishWhenEnded = aFinishWhenEnded;
485 }
486 nsRefPtr<ProcessedMediaStream> mStream;
487 // mPort connects mDecodedStream->mStream to our mStream.
488 nsRefPtr<MediaInputPort> mPort;
489 bool mFinishWhenEnded;
490 };
491 /**
492 * Connects mDecodedStream->mStream to aStream->mStream.
493 */
494 void ConnectDecodedStreamToOutputStream(OutputStreamData* aStream);
495 /**
496 * Disconnects mDecodedStream->mStream from all outputs and clears
497 * mDecodedStream.
498 */
499 void DestroyDecodedStream();
500 /**
501 * Recreates mDecodedStream. Call this to create mDecodedStream at first,
502 * and when seeking, to ensure a new stream is set up with fresh buffers.
503 * aStartTimeUSecs is relative to the state machine's mStartTime.
504 * Decoder monitor must be held.
505 */
506 void RecreateDecodedStream(int64_t aStartTimeUSecs);
507 /**
508 * Call this when mDecoderStateMachine or mDecoderStateMachine->IsPlaying() changes.
509 * Decoder monitor must be held.
510 */
511 void UpdateStreamBlockingForStateMachinePlaying();
512 nsTArray<OutputStreamData>& OutputStreams()
513 {
514 GetReentrantMonitor().AssertCurrentThreadIn();
515 return mOutputStreams;
516 }
517 DecodedStreamData* GetDecodedStream()
518 {
519 GetReentrantMonitor().AssertCurrentThreadIn();
520 return mDecodedStream;
521 }
523 // Add an output stream. All decoder output will be sent to the stream.
524 // The stream is initially blocked. The decoder is responsible for unblocking
525 // it while it is playing back.
526 virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
528 // Return the duration of the video in seconds.
529 virtual double GetDuration();
531 // Return the duration of the video in seconds.
532 int64_t GetMediaDuration() MOZ_FINAL MOZ_OVERRIDE;
534 // A media stream is assumed to be infinite if the metadata doesn't
535 // contain the duration, and range requests are not supported, and
536 // no headers give a hint of a possible duration (Content-Length,
537 // Content-Duration, and variants), and we cannot seek in the media
538 // stream to determine the duration.
539 //
540 // When the media stream ends, we can know the duration, thus the stream is
541 // no longer considered to be infinite.
542 virtual void SetInfinite(bool aInfinite);
544 // Return true if the stream is infinite (see SetInfinite).
545 virtual bool IsInfinite();
547 // Called by MediaResource when the "cache suspended" status changes.
548 // If MediaResource::IsSuspendedByCache returns true, then the decoder
549 // should stop buffering or otherwise waiting for download progress and
550 // start consuming data, if possible, because the cache is full.
551 virtual void NotifySuspendedStatusChanged();
553 // Called by MediaResource when some data has been received.
554 // Call on the main thread only.
555 virtual void NotifyBytesDownloaded();
557 // Called by nsChannelToPipeListener or MediaResource when the
558 // download has ended. Called on the main thread only. aStatus is
559 // the result from OnStopRequest.
560 virtual void NotifyDownloadEnded(nsresult aStatus);
562 // Called as data arrives on the stream and is read into the cache. Called
563 // on the main thread only.
564 virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
566 // Called by MediaResource when the principal of the resource has
567 // changed. Called on main thread only.
568 virtual void NotifyPrincipalChanged();
570 // Called by the MediaResource to keep track of the number of bytes read
571 // from the resource. Called on the main by an event runner dispatched
572 // by the MediaResource read functions.
573 void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) MOZ_FINAL MOZ_OVERRIDE;
575 int64_t GetEndMediaTime() const MOZ_FINAL MOZ_OVERRIDE;
577 // Return true if we are currently seeking in the media resource.
578 // Call on the main thread only.
579 virtual bool IsSeeking() const;
581 // Return true if the decoder has reached the end of playback.
582 // Call on the main thread only.
583 virtual bool IsEnded() const;
585 // Set the duration of the media resource in units of seconds.
586 // This is called via a channel listener if it can pick up the duration
587 // from a content header. Must be called from the main thread only.
588 virtual void SetDuration(double aDuration);
590 // Sets the initial duration of the media. Called while the media metadata
591 // is being read and the decode is being setup.
592 void SetMediaDuration(int64_t aDuration) MOZ_OVERRIDE;
593 // Updates the media duration. This is called while the media is being
594 // played, calls before the media has reached loaded metadata are ignored.
595 // The duration is assumed to be an estimate, and so a degree of
596 // instability is expected; if the incoming duration is not significantly
597 // different from the existing duration, the change request is ignored.
598 // If the incoming duration is significantly different, the duration is
599 // changed, this causes a durationchanged event to fire to the media
600 // element.
601 void UpdateEstimatedMediaDuration(int64_t aDuration) MOZ_OVERRIDE;
603 // Set a flag indicating whether seeking is supported
604 virtual void SetMediaSeekable(bool aMediaSeekable) MOZ_OVERRIDE;
605 virtual void SetTransportSeekable(bool aTransportSeekable) MOZ_FINAL MOZ_OVERRIDE;
606 // Returns true if this media supports seeking. False for example for WebM
607 // files without an index and chained ogg files.
608 virtual bool IsMediaSeekable() MOZ_FINAL MOZ_OVERRIDE;
609 // Returns true if seeking is supported on a transport level (e.g. the server
610 // supports range requests, we are playing a file, etc.).
611 virtual bool IsTransportSeekable();
613 // Return the time ranges that can be seeked into.
614 virtual nsresult GetSeekable(dom::TimeRanges* aSeekable);
616 // Set the end time of the media resource. When playback reaches
617 // this point the media pauses. aTime is in seconds.
618 virtual void SetFragmentEndTime(double aTime);
620 // Set the end time of the media. aTime is in microseconds.
621 void SetMediaEndTime(int64_t aTime) MOZ_FINAL MOZ_OVERRIDE;
623 // Invalidate the frame.
624 void Invalidate();
625 void InvalidateWithFlags(uint32_t aFlags);
627 // Suspend any media downloads that are in progress. Called by the
628 // media element when it is sent to the bfcache, or when we need
629 // to throttle the download. Call on the main thread only. This can
630 // be called multiple times, there's an internal "suspend count".
631 virtual void Suspend();
633 // Resume any media downloads that have been suspended. Called by the
634 // media element when it is restored from the bfcache, or when we need
635 // to stop throttling the download. Call on the main thread only.
636 // The download will only actually resume once as many Resume calls
637 // have been made as Suspend calls. When aForceBuffering is true,
638 // we force the decoder to go into buffering state before resuming
639 // playback.
640 virtual void Resume(bool aForceBuffering);
642 // Moves any existing channel loads into the background, so that they don't
643 // block the load event. This is called when we stop delaying the load
644 // event. Any new loads initiated (for example to seek) will also be in the
645 // background. Implementations of this must call MoveLoadsToBackground() on
646 // their MediaResource.
647 virtual void MoveLoadsToBackground();
649 // Returns a weak reference to the media decoder owner.
650 MediaDecoderOwner* GetMediaOwner() const;
652 // Called by the state machine to notify the decoder that the duration
653 // has changed.
654 void DurationChanged();
656 bool OnStateMachineThread() const MOZ_OVERRIDE;
658 bool OnDecodeThread() const MOZ_OVERRIDE;
660 // Returns the monitor for other threads to synchronise access to
661 // state.
662 ReentrantMonitor& GetReentrantMonitor() MOZ_OVERRIDE;
664 // Returns true if the decoder is shut down
665 bool IsShutdown() const MOZ_FINAL MOZ_OVERRIDE;
667 // Constructs the time ranges representing what segments of the media
668 // are buffered and playable.
669 virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
671 // Returns the size, in bytes, of the heap memory used by the currently
672 // queued decoded video and audio data.
673 size_t SizeOfVideoQueue();
674 size_t SizeOfAudioQueue();
676 VideoFrameContainer* GetVideoFrameContainer() MOZ_FINAL MOZ_OVERRIDE
677 {
678 return mVideoFrameContainer;
679 }
680 layers::ImageContainer* GetImageContainer() MOZ_OVERRIDE;
682 // Return the current state. Can be called on any thread. If called from
683 // a non-main thread, the decoder monitor must be held.
684 PlayState GetState() {
685 return mPlayState;
686 }
688 // Fire progress events if needed according to the time and byte
689 // constraints outlined in the specification. aTimer is true
690 // if the method is called as a result of the progress timer rather
691 // than the result of downloaded data.
692 void Progress(bool aTimer);
694 // Fire timeupdate events if needed according to the time constraints
695 // outlined in the specification.
696 void FireTimeUpdate();
698 // Stop updating the bytes downloaded for progress notifications. Called
699 // when seeking to prevent wild changes to the progress notification.
700 // Must be called with the decoder monitor held.
701 virtual void StopProgressUpdates();
703 // Allow updating the bytes downloaded for progress notifications. Must
704 // be called with the decoder monitor held.
705 virtual void StartProgressUpdates();
707 // Something has changed that could affect the computed playback rate,
708 // so recompute it. The monitor must be held.
709 virtual void UpdatePlaybackRate();
711 // Used to estimate rates of data passing through the decoder's channel.
712 // Records activity stopping on the channel. The monitor must be held.
713 virtual void NotifyPlaybackStarted() {
714 GetReentrantMonitor().AssertCurrentThreadIn();
715 mPlaybackStatistics.Start();
716 }
718 // Used to estimate rates of data passing through the decoder's channel.
719 // Records activity stopping on the channel. The monitor must be held.
720 virtual void NotifyPlaybackStopped() {
721 GetReentrantMonitor().AssertCurrentThreadIn();
722 mPlaybackStatistics.Stop();
723 }
725 // The actual playback rate computation. The monitor must be held.
726 virtual double ComputePlaybackRate(bool* aReliable);
728 // Return true when the media is same-origin with the element. The monitor
729 // must be held.
730 bool IsSameOriginMedia();
732 // Returns true if we can play the entire media through without stopping
733 // to buffer, given the current download and playback rates.
734 bool CanPlayThrough();
736 // Make the decoder state machine update the playback position. Called by
737 // the reader on the decoder thread (Assertions for this checked by
738 // mDecoderStateMachine). This must be called with the decode monitor
739 // held.
740 void UpdatePlaybackPosition(int64_t aTime) MOZ_FINAL MOZ_OVERRIDE;
742 void SetAudioChannel(dom::AudioChannel aChannel) { mAudioChannel = aChannel; }
743 dom::AudioChannel GetAudioChannel() { return mAudioChannel; }
745 // Send a new set of metadata to the state machine, to be dispatched to the
746 // main thread to be presented when the |currentTime| of the media is greater
747 // or equal to aPublishTime.
748 void QueueMetadata(int64_t aPublishTime,
749 int aChannels,
750 int aRate,
751 bool aHasAudio,
752 bool aHasVideo,
753 MetadataTags* aTags);
755 /******
756 * The following methods must only be called on the main
757 * thread.
758 ******/
760 // Change to a new play state. This updates the mState variable and
761 // notifies any thread blocking on this object's monitor of the
762 // change. Call on the main thread only.
763 virtual void ChangeState(PlayState aState);
765 // Called by |ChangeState|, to update the state machine.
766 // Call on the main thread only and the lock must be obtained.
767 virtual void ApplyStateToStateMachine(PlayState aState);
769 // May be called by the reader to notify this decoder that the metadata from
770 // the media file has been read. Call on the decode thread only.
771 void OnReadMetadataCompleted() MOZ_OVERRIDE { }
773 // Called when the metadata from the media file has been loaded by the
774 // state machine. Call on the main thread only.
775 virtual void MetadataLoaded(int aChannels,
776 int aRate,
777 bool aHasAudio,
778 bool aHasVideo,
779 MetadataTags* aTags);
781 // Called when the first frame has been loaded.
782 // Call on the main thread only.
783 void FirstFrameLoaded();
785 // Returns true if the resource has been loaded. Acquires the monitor.
786 // Call from any thread.
787 virtual bool IsDataCachedToEndOfResource();
789 // Called when the video has completed playing.
790 // Call on the main thread only.
791 void PlaybackEnded();
793 // Seeking has stopped. Inform the element on the main
794 // thread.
795 void SeekingStopped();
797 // Seeking has stopped at the end of the resource. Inform the element on the main
798 // thread.
799 void SeekingStoppedAtEnd();
801 // Seeking has started. Inform the element on the main
802 // thread.
803 void SeekingStarted();
805 // Called when the backend has changed the current playback
806 // position. It dispatches a timeupdate event and invalidates the frame.
807 // This must be called on the main thread only.
808 void PlaybackPositionChanged();
810 // Calls mElement->UpdateReadyStateForData, telling it whether we have
811 // data for the next frame and if we're buffering. Main thread only.
812 virtual void UpdateReadyStateForData();
814 // Find the end of the cached data starting at the current decoder
815 // position.
816 int64_t GetDownloadPosition();
818 // Updates the approximate byte offset which playback has reached. This is
819 // used to calculate the readyState transitions.
820 void UpdatePlaybackOffset(int64_t aOffset);
822 // Provide access to the state machine object
823 MediaDecoderStateMachine* GetStateMachine() const;
825 // Drop reference to state machine. Only called during shutdown dance.
826 virtual void ReleaseStateMachine();
828 // Notifies the element that decoding has failed.
829 virtual void DecodeError();
831 // Indicate whether the media is same-origin with the element.
832 void UpdateSameOriginStatus(bool aSameOrigin);
834 MediaDecoderOwner* GetOwner() MOZ_OVERRIDE;
836 // Returns true if we're logically playing, that is, if the Play() has
837 // been called and Pause() has not or we have not yet reached the end
838 // of media. This is irrespective of the seeking state; if the owner
839 // calls Play() and then Seek(), we still count as logically playing.
840 // The decoder monitor must be held.
841 bool IsLogicallyPlaying();
843 #ifdef MOZ_RAW
844 static bool IsRawEnabled();
845 #endif
847 static bool IsOggEnabled();
848 static bool IsOpusEnabled();
850 #ifdef MOZ_WAVE
851 static bool IsWaveEnabled();
852 #endif
854 #ifdef MOZ_WEBM
855 static bool IsWebMEnabled();
856 #endif
857 #ifdef NECKO_PROTOCOL_rtsp
858 static bool IsRtspEnabled();
859 #endif
861 #ifdef MOZ_GSTREAMER
862 static bool IsGStreamerEnabled();
863 #endif
865 #ifdef MOZ_OMX_DECODER
866 static bool IsOmxEnabled();
867 #endif
869 #ifdef MOZ_MEDIA_PLUGINS
870 static bool IsMediaPluginsEnabled();
871 #endif
873 #ifdef MOZ_WMF
874 static bool IsWMFEnabled();
875 #endif
877 #ifdef MOZ_APPLEMEDIA
878 static bool IsAppleMP3Enabled();
879 #endif
881 // Schedules the state machine to run one cycle on the shared state
882 // machine thread. Main thread only.
883 nsresult ScheduleStateMachineThread();
885 struct Statistics {
886 // Estimate of the current playback rate (bytes/second).
887 double mPlaybackRate;
888 // Estimate of the current download rate (bytes/second). This
889 // ignores time that the channel was paused by Gecko.
890 double mDownloadRate;
891 // Total length of media stream in bytes; -1 if not known
892 int64_t mTotalBytes;
893 // Current position of the download, in bytes. This is the offset of
894 // the first uncached byte after the decoder position.
895 int64_t mDownloadPosition;
896 // Current position of decoding, in bytes (how much of the stream
897 // has been consumed)
898 int64_t mDecoderPosition;
899 // Current position of playback, in bytes
900 int64_t mPlaybackPosition;
901 // If false, then mDownloadRate cannot be considered a reliable
902 // estimate (probably because the download has only been running
903 // a short time).
904 bool mDownloadRateReliable;
905 // If false, then mPlaybackRate cannot be considered a reliable
906 // estimate (probably because playback has only been running
907 // a short time).
908 bool mPlaybackRateReliable;
909 };
911 // Return statistics. This is used for progress events and other things.
912 // This can be called from any thread. It's only a snapshot of the
913 // current state, since other threads might be changing the state
914 // at any time.
915 virtual Statistics GetStatistics();
917 // Frame decoding/painting related performance counters.
918 // Threadsafe.
919 class FrameStatistics {
920 public:
922 FrameStatistics() :
923 mReentrantMonitor("MediaDecoder::FrameStats"),
924 mParsedFrames(0),
925 mDecodedFrames(0),
926 mPresentedFrames(0) {}
928 // Returns number of frames which have been parsed from the media.
929 // Can be called on any thread.
930 uint32_t GetParsedFrames() {
931 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
932 return mParsedFrames;
933 }
935 // Returns the number of parsed frames which have been decoded.
936 // Can be called on any thread.
937 uint32_t GetDecodedFrames() {
938 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
939 return mDecodedFrames;
940 }
942 // Returns the number of decoded frames which have been sent to the rendering
943 // pipeline for painting ("presented").
944 // Can be called on any thread.
945 uint32_t GetPresentedFrames() {
946 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
947 return mPresentedFrames;
948 }
950 // Increments the parsed and decoded frame counters by the passed in counts.
951 // Can be called on any thread.
952 void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) {
953 if (aParsed == 0 && aDecoded == 0)
954 return;
955 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
956 mParsedFrames += aParsed;
957 mDecodedFrames += aDecoded;
958 }
960 // Increments the presented frame counters.
961 // Can be called on any thread.
962 void NotifyPresentedFrame() {
963 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
964 ++mPresentedFrames;
965 }
967 private:
969 // ReentrantMonitor to protect access of playback statistics.
970 ReentrantMonitor mReentrantMonitor;
972 // Number of frames parsed and demuxed from media.
973 // Access protected by mReentrantMonitor.
974 uint32_t mParsedFrames;
976 // Number of parsed frames which were actually decoded.
977 // Access protected by mReentrantMonitor.
978 uint32_t mDecodedFrames;
980 // Number of decoded frames which were actually sent down the rendering
981 // pipeline to be painted ("presented"). Access protected by mReentrantMonitor.
982 uint32_t mPresentedFrames;
983 };
985 // Return the frame decode/paint related statistics.
986 FrameStatistics& GetFrameStatistics() { return mFrameStats; }
988 // Increments the parsed and decoded frame counters by the passed in counts.
989 // Can be called on any thread.
990 virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) MOZ_OVERRIDE
991 {
992 GetFrameStatistics().NotifyDecodedFrames(aParsed, aDecoded);
993 }
995 protected:
996 /******
997 * The following members should be accessed with the decoder lock held.
998 ******/
1000 // Current decoding position in the stream. This is where the decoder
1001 // is up to consuming the stream. This is not adjusted during decoder
1002 // seek operations, but it's updated at the end when we start playing
1003 // back again.
1004 int64_t mDecoderPosition;
1005 // Current playback position in the stream. This is (approximately)
1006 // where we're up to playing back the stream. This is not adjusted
1007 // during decoder seek operations, but it's updated at the end when we
1008 // start playing back again.
1009 int64_t mPlaybackPosition;
1011 // The current playback position of the media resource in units of
1012 // seconds. This is updated approximately at the framerate of the
1013 // video (if it is a video) or the callback period of the audio.
1014 // It is read and written from the main thread only.
1015 double mCurrentTime;
1017 // Volume that playback should start at. 0.0 = muted. 1.0 = full
1018 // volume. Readable/Writeable from the main thread.
1019 double mInitialVolume;
1021 // PlaybackRate and pitch preservation status we should start at.
1022 // Readable/Writeable from the main thread.
1023 double mInitialPlaybackRate;
1024 bool mInitialPreservesPitch;
1026 // Duration of the media resource. Set to -1 if unknown.
1027 // Set when the metadata is loaded. Accessed on the main thread
1028 // only.
1029 int64_t mDuration;
1031 // True when playback should start with audio captured (not playing).
1032 bool mInitialAudioCaptured;
1034 // True if the resource is seekable at a transport level (server supports byte
1035 // range requests, local file, etc.).
1036 bool mTransportSeekable;
1038 // True if the media is seekable (i.e. supports random access).
1039 bool mMediaSeekable;
1041 // True if the media is same-origin with the element. Data can only be
1042 // passed to MediaStreams when this is true.
1043 bool mSameOriginMedia;
1045 /******
1046 * The following member variables can be accessed from any thread.
1047 ******/
1049 // The state machine object for handling the decoding. It is safe to
1050 // call methods of this object from other threads. Its internal data
1051 // is synchronised on a monitor. The lifetime of this object is
1052 // after mPlayState is LOADING and before mPlayState is SHUTDOWN. It
1053 // is safe to access it during this period.
1054 nsRefPtr<MediaDecoderStateMachine> mDecoderStateMachine;
1056 // Media data resource.
1057 nsRefPtr<MediaResource> mResource;
1059 // |ReentrantMonitor| for detecting when the video play state changes. A call
1060 // to |Wait| on this monitor will block the thread until the next state
1061 // change.
1062 // Using a wrapper class to restrict direct access to the |ReentrantMonitor|
1063 // object. Subclasses may override |MediaDecoder|::|GetReentrantMonitor|
1064 // e.g. |DASHRepDecoder|::|GetReentrantMonitor| returns the monitor in the
1065 // main |DASHDecoder| object. In this case, directly accessing the
1066 // member variable mReentrantMonitor in |DASHRepDecoder| is wrong.
1067 // The wrapper |RestrictedAccessMonitor| restricts use to the getter
1068 // function rather than the object itself.
1069 private:
1070 class RestrictedAccessMonitor
1071 {
1072 public:
1073 RestrictedAccessMonitor(const char* aName) :
1074 mReentrantMonitor(aName)
1075 {
1076 MOZ_COUNT_CTOR(RestrictedAccessMonitor);
1077 }
1078 ~RestrictedAccessMonitor()
1079 {
1080 MOZ_COUNT_DTOR(RestrictedAccessMonitor);
1081 }
1083 // Returns a ref to the reentrant monitor
1084 ReentrantMonitor& GetReentrantMonitor() {
1085 return mReentrantMonitor;
1086 }
1087 private:
1088 ReentrantMonitor mReentrantMonitor;
1089 };
1091 // The |RestrictedAccessMonitor| member object.
1092 RestrictedAccessMonitor mReentrantMonitor;
1094 protected:
1095 // Data about MediaStreams that are being fed by this decoder.
1096 nsTArray<OutputStreamData> mOutputStreams;
1097 // The SourceMediaStream we are using to feed the mOutputStreams. This stream
1098 // is never exposed outside the decoder.
1099 // Only written on the main thread while holding the monitor. Therefore it
1100 // can be read on any thread while holding the monitor, or on the main thread
1101 // without holding the monitor.
1102 nsAutoPtr<DecodedStreamData> mDecodedStream;
1104 // True if this decoder is in dormant state.
1105 // Should be true only when PlayState is PLAY_STATE_LOADING.
1106 bool mIsDormant;
1108 // True if this decoder is exiting from dormant state.
1109 // Should be true only when PlayState is PLAY_STATE_LOADING.
1110 bool mIsExitingDormant;
1112 // Set to one of the valid play states.
1113 // This can only be changed on the main thread while holding the decoder
1114 // monitor. Thus, it can be safely read while holding the decoder monitor
1115 // OR on the main thread.
1116 // Any change to the state on the main thread must call NotifyAll on the
1117 // monitor so the decode thread can wake up.
1118 PlayState mPlayState;
1120 // The state to change to after a seek or load operation.
1121 // This can only be changed on the main thread while holding the decoder
1122 // monitor. Thus, it can be safely read while holding the decoder monitor
1123 // OR on the main thread.
1124 // Any change to the state must call NotifyAll on the monitor.
1125 // This can only be PLAY_STATE_PAUSED or PLAY_STATE_PLAYING.
1126 PlayState mNextState;
1128 // Position to seek to when the seek notification is received by the
1129 // decode thread.
1130 // This can only be changed on the main thread while holding the decoder
1131 // monitor. Thus, it can be safely read while holding the decoder monitor
1132 // OR on the main thread.
1133 // If the SeekTarget's IsValid() accessor returns false, then no seek has
1134 // been requested. When a seek is started this is reset to invalid.
1135 SeekTarget mRequestedSeekTarget;
1137 // True when we have fully loaded the resource and reported that
1138 // to the element (i.e. reached NETWORK_LOADED state).
1139 // Accessed on the main thread only.
1140 bool mCalledResourceLoaded;
1142 // True when seeking or otherwise moving the play position around in
1143 // such a manner that progress event data is inaccurate. This is set
1144 // during seek and duration operations to prevent the progress indicator
1145 // from jumping around. Read/Write from any thread. Must have decode monitor
1146 // locked before accessing.
1147 bool mIgnoreProgressData;
1149 // True if the stream is infinite (e.g. a webradio).
1150 bool mInfiniteStream;
1152 // Start timer to update download progress information.
1153 nsresult StartProgress();
1155 // Stop progress information timer.
1156 nsresult StopProgress();
1158 // Ensures our media stream has been pinned.
1159 void PinForSeek();
1161 // Ensures our media stream has been unpinned.
1162 void UnpinForSeek();
1164 // Timer used for updating progress events
1165 nsCOMPtr<nsITimer> mProgressTimer;
1167 // This should only ever be accessed from the main thread.
1168 // It is set in Init and cleared in Shutdown when the element goes away.
1169 // The decoder does not add a reference the element.
1170 MediaDecoderOwner* mOwner;
1172 // Counters related to decode and presentation of frames.
1173 FrameStatistics mFrameStats;
1175 nsRefPtr<VideoFrameContainer> mVideoFrameContainer;
1177 // Time that the last progress event was fired. Read/Write from the
1178 // main thread only.
1179 TimeStamp mProgressTime;
1181 // Time that data was last read from the media resource. Used for
1182 // computing if the download has stalled and to rate limit progress events
1183 // when data is arriving slower than PROGRESS_MS. A value of null indicates
1184 // that a stall event has already fired and not to fire another one until
1185 // more data is received. Read/Write from the main thread only.
1186 TimeStamp mDataTime;
1188 // Data needed to estimate playback data rate. The timeline used for
1189 // this estimate is "decode time" (where the "current time" is the
1190 // time of the last decoded video frame).
1191 MediaChannelStatistics mPlaybackStatistics;
1193 // True when our media stream has been pinned. We pin the stream
1194 // while seeking.
1195 bool mPinnedForSeek;
1197 // True if the decoder is being shutdown. At this point all events that
1198 // are currently queued need to return immediately to prevent javascript
1199 // being run that operates on the element and decoder during shutdown.
1200 // Read/Write from the main thread only.
1201 bool mShuttingDown;
1203 // True if the playback is paused because the playback rate member is 0.0.
1204 bool mPausedForPlaybackRateNull;
1206 // Be assigned from media element during the initialization and pass to
1207 // AudioStream Class.
1208 dom::AudioChannel mAudioChannel;
1210 // True if the decoder has been directed to minimize its preroll before
1211 // playback starts. After the first time playback starts, we don't attempt
1212 // to minimize preroll, as we assume the user is likely to keep playing,
1213 // or play the media again.
1214 bool mMinimizePreroll;
1215 };
1217 } // namespace mozilla
1219 #endif