content/media/MediaDecoder.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rwxr-xr-x

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial