content/media/MediaDecoderStateMachine.h

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

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 for a media file has two threads:
michael@0 8
michael@0 9 1) The Audio thread writes the decoded audio data to the audio
michael@0 10 hardware. This is done in a separate thread to ensure that the
michael@0 11 audio hardware gets a constant stream of data without
michael@0 12 interruption due to decoding or display. At some point
michael@0 13 AudioStream will be refactored to have a callback interface
michael@0 14 where it asks for data and an extra thread will no longer be
michael@0 15 needed.
michael@0 16
michael@0 17 2) The decode thread. This thread reads from the media stream and
michael@0 18 decodes the Theora and Vorbis data. It places the decoded data into
michael@0 19 queues for the other threads to pull from.
michael@0 20
michael@0 21 All file reads, seeks, and all decoding must occur on the decode thread.
michael@0 22 Synchronisation of state between the thread is done via a monitor owned
michael@0 23 by MediaDecoder.
michael@0 24
michael@0 25 The lifetime of the decode and audio threads is controlled by the state
michael@0 26 machine when it runs on the shared state machine thread. When playback
michael@0 27 needs to occur they are created and events dispatched to them to run
michael@0 28 them. These events exit when decoding/audio playback is completed or
michael@0 29 no longer required.
michael@0 30
michael@0 31 A/V synchronisation is handled by the state machine. It examines the audio
michael@0 32 playback time and compares this to the next frame in the queue of video
michael@0 33 frames. If it is time to play the video frame it is then displayed, otherwise
michael@0 34 it schedules the state machine to run again at the time of the next frame.
michael@0 35
michael@0 36 Frame skipping is done in the following ways:
michael@0 37
michael@0 38 1) The state machine will skip all frames in the video queue whose
michael@0 39 display time is less than the current audio time. This ensures
michael@0 40 the correct frame for the current time is always displayed.
michael@0 41
michael@0 42 2) The decode thread will stop decoding interframes and read to the
michael@0 43 next keyframe if it determines that decoding the remaining
michael@0 44 interframes will cause playback issues. It detects this by:
michael@0 45 a) If the amount of audio data in the audio queue drops
michael@0 46 below a threshold whereby audio may start to skip.
michael@0 47 b) If the video queue drops below a threshold where it
michael@0 48 will be decoding video data that won't be displayed due
michael@0 49 to the decode thread dropping the frame immediately.
michael@0 50
michael@0 51 When hardware accelerated graphics is not available, YCbCr conversion
michael@0 52 is done on the decode thread when video frames are decoded.
michael@0 53
michael@0 54 The decode thread pushes decoded audio and videos frames into two
michael@0 55 separate queues - one for audio and one for video. These are kept
michael@0 56 separate to make it easy to constantly feed audio data to the audio
michael@0 57 hardware while allowing frame skipping of video data. These queues are
michael@0 58 threadsafe, and neither the decode, audio, or state machine should
michael@0 59 be able to monopolize them, and cause starvation of the other threads.
michael@0 60
michael@0 61 Both queues are bounded by a maximum size. When this size is reached
michael@0 62 the decode thread will no longer decode video or audio depending on the
michael@0 63 queue that has reached the threshold. If both queues are full, the decode
michael@0 64 thread will wait on the decoder monitor.
michael@0 65
michael@0 66 When the decode queues are full (they've reaced their maximum size) and
michael@0 67 the decoder is not in PLAYING play state, the state machine may opt
michael@0 68 to shut down the decode thread in order to conserve resources.
michael@0 69
michael@0 70 During playback the audio thread will be idle (via a Wait() on the
michael@0 71 monitor) if the audio queue is empty. Otherwise it constantly pops
michael@0 72 audio data off the queue and plays it with a blocking write to the audio
michael@0 73 hardware (via AudioStream).
michael@0 74
michael@0 75 */
michael@0 76 #if !defined(MediaDecoderStateMachine_h__)
michael@0 77 #define MediaDecoderStateMachine_h__
michael@0 78
michael@0 79 #include "mozilla/Attributes.h"
michael@0 80 #include "nsThreadUtils.h"
michael@0 81 #include "MediaDecoder.h"
michael@0 82 #include "mozilla/ReentrantMonitor.h"
michael@0 83 #include "MediaDecoderReader.h"
michael@0 84 #include "MediaDecoderOwner.h"
michael@0 85 #include "MediaMetadataManager.h"
michael@0 86
michael@0 87 class nsITimer;
michael@0 88
michael@0 89 namespace mozilla {
michael@0 90
michael@0 91 class AudioSegment;
michael@0 92 class VideoSegment;
michael@0 93 class MediaTaskQueue;
michael@0 94 class SharedThreadPool;
michael@0 95
michael@0 96 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
michael@0 97 // GetTickCount() and conflicts with MediaDecoderStateMachine::GetCurrentTime
michael@0 98 // implementation.
michael@0 99 #ifdef GetCurrentTime
michael@0 100 #undef GetCurrentTime
michael@0 101 #endif
michael@0 102
michael@0 103 /*
michael@0 104 The state machine class. This manages the decoding and seeking in the
michael@0 105 MediaDecoderReader on the decode thread, and A/V sync on the shared
michael@0 106 state machine thread, and controls the audio "push" thread.
michael@0 107
michael@0 108 All internal state is synchronised via the decoder monitor. State changes
michael@0 109 are either propagated by NotifyAll on the monitor (typically when state
michael@0 110 changes need to be propagated to non-state machine threads) or by scheduling
michael@0 111 the state machine to run another cycle on the shared state machine thread.
michael@0 112
michael@0 113 See MediaDecoder.h for more details.
michael@0 114 */
michael@0 115 class MediaDecoderStateMachine
michael@0 116 {
michael@0 117 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachine)
michael@0 118 public:
michael@0 119 typedef MediaDecoder::DecodedStreamData DecodedStreamData;
michael@0 120 MediaDecoderStateMachine(MediaDecoder* aDecoder,
michael@0 121 MediaDecoderReader* aReader,
michael@0 122 bool aRealTime = false);
michael@0 123
michael@0 124 nsresult Init(MediaDecoderStateMachine* aCloneDonor);
michael@0 125
michael@0 126 // Enumeration for the valid decoding states
michael@0 127 enum State {
michael@0 128 DECODER_STATE_DECODING_METADATA,
michael@0 129 DECODER_STATE_WAIT_FOR_RESOURCES,
michael@0 130 DECODER_STATE_DORMANT,
michael@0 131 DECODER_STATE_DECODING,
michael@0 132 DECODER_STATE_SEEKING,
michael@0 133 DECODER_STATE_BUFFERING,
michael@0 134 DECODER_STATE_COMPLETED,
michael@0 135 DECODER_STATE_SHUTDOWN
michael@0 136 };
michael@0 137
michael@0 138 State GetState() {
michael@0 139 AssertCurrentThreadInMonitor();
michael@0 140 return mState;
michael@0 141 }
michael@0 142
michael@0 143 // Set the audio volume. The decoder monitor must be obtained before
michael@0 144 // calling this.
michael@0 145 void SetVolume(double aVolume);
michael@0 146 void SetAudioCaptured(bool aCapture);
michael@0 147
michael@0 148 // Check if the decoder needs to become dormant state.
michael@0 149 bool IsDormantNeeded();
michael@0 150 // Set/Unset dormant state.
michael@0 151 void SetDormant(bool aDormant);
michael@0 152 void Shutdown();
michael@0 153
michael@0 154 // Called from the main thread to get the duration. The decoder monitor
michael@0 155 // must be obtained before calling this. It is in units of microseconds.
michael@0 156 int64_t GetDuration();
michael@0 157
michael@0 158 // Called from the main thread to set the duration of the media resource
michael@0 159 // if it is able to be obtained via HTTP headers. Called from the
michael@0 160 // state machine thread to set the duration if it is obtained from the
michael@0 161 // media metadata. The decoder monitor must be obtained before calling this.
michael@0 162 // aDuration is in microseconds.
michael@0 163 void SetDuration(int64_t aDuration);
michael@0 164
michael@0 165 // Called while decoding metadata to set the end time of the media
michael@0 166 // resource. The decoder monitor must be obtained before calling this.
michael@0 167 // aEndTime is in microseconds.
michael@0 168 void SetMediaEndTime(int64_t aEndTime);
michael@0 169
michael@0 170 // Called from main thread to update the duration with an estimated value.
michael@0 171 // The duration is only changed if its significantly different than the
michael@0 172 // the current duration, as the incoming duration is an estimate and so
michael@0 173 // often is unstable as more data is read and the estimate is updated.
michael@0 174 // Can result in a durationchangeevent. aDuration is in microseconds.
michael@0 175 void UpdateEstimatedDuration(int64_t aDuration);
michael@0 176
michael@0 177 // Functions used by assertions to ensure we're calling things
michael@0 178 // on the appropriate threads.
michael@0 179 bool OnDecodeThread() const;
michael@0 180 bool OnStateMachineThread() const;
michael@0 181 bool OnAudioThread() const {
michael@0 182 return IsCurrentThread(mAudioThread);
michael@0 183 }
michael@0 184
michael@0 185 MediaDecoderOwner::NextFrameStatus GetNextFrameStatus();
michael@0 186
michael@0 187 // Cause state transitions. These methods obtain the decoder monitor
michael@0 188 // to synchronise the change of state, and to notify other threads
michael@0 189 // that the state has changed.
michael@0 190 void Play();
michael@0 191
michael@0 192 // Seeks to the decoder to aTarget asynchronously.
michael@0 193 void Seek(const SeekTarget& aTarget);
michael@0 194
michael@0 195 // Returns the current playback position in seconds.
michael@0 196 // Called from the main thread to get the current frame time. The decoder
michael@0 197 // monitor must be obtained before calling this.
michael@0 198 double GetCurrentTime() const;
michael@0 199
michael@0 200 // Clear the flag indicating that a playback position change event
michael@0 201 // is currently queued. This is called from the main thread and must
michael@0 202 // be called with the decode monitor held.
michael@0 203 void ClearPositionChangeFlag();
michael@0 204
michael@0 205 // Called from the main thread or the decoder thread to set whether the media
michael@0 206 // resource can seek into unbuffered ranges. The decoder monitor must be
michael@0 207 // obtained before calling this.
michael@0 208 void SetTransportSeekable(bool aSeekable);
michael@0 209
michael@0 210 // Called from the main thread or the decoder thread to set whether the media
michael@0 211 // can seek to random location. This is not true for chained ogg and WebM
michael@0 212 // media without index. The decoder monitor must be obtained before calling
michael@0 213 // this.
michael@0 214 void SetMediaSeekable(bool aSeekable);
michael@0 215
michael@0 216 // Update the playback position. This can result in a timeupdate event
michael@0 217 // and an invalidate of the frame being dispatched asynchronously if
michael@0 218 // there is no such event currently queued.
michael@0 219 // Only called on the decoder thread. Must be called with
michael@0 220 // the decode monitor held.
michael@0 221 void UpdatePlaybackPosition(int64_t aTime);
michael@0 222
michael@0 223 // Causes the state machine to switch to buffering state, and to
michael@0 224 // immediately stop playback and buffer downloaded data. Must be called
michael@0 225 // with the decode monitor held. Called on the state machine thread and
michael@0 226 // the main thread.
michael@0 227 void StartBuffering();
michael@0 228
michael@0 229 // This is called on the state machine thread and audio thread.
michael@0 230 // The decoder monitor must be obtained before calling this.
michael@0 231 bool HasAudio() const {
michael@0 232 AssertCurrentThreadInMonitor();
michael@0 233 return mInfo.HasAudio();
michael@0 234 }
michael@0 235
michael@0 236 // This is called on the state machine thread and audio thread.
michael@0 237 // The decoder monitor must be obtained before calling this.
michael@0 238 bool HasVideo() const {
michael@0 239 AssertCurrentThreadInMonitor();
michael@0 240 return mInfo.HasVideo();
michael@0 241 }
michael@0 242
michael@0 243 // Should be called by main thread.
michael@0 244 bool HaveNextFrameData();
michael@0 245
michael@0 246 // Must be called with the decode monitor held.
michael@0 247 bool IsBuffering() const {
michael@0 248 AssertCurrentThreadInMonitor();
michael@0 249
michael@0 250 return mState == DECODER_STATE_BUFFERING;
michael@0 251 }
michael@0 252
michael@0 253 // Must be called with the decode monitor held.
michael@0 254 bool IsSeeking() const {
michael@0 255 AssertCurrentThreadInMonitor();
michael@0 256
michael@0 257 return mState == DECODER_STATE_SEEKING;
michael@0 258 }
michael@0 259
michael@0 260 nsresult GetBuffered(dom::TimeRanges* aBuffered);
michael@0 261
michael@0 262 void SetPlaybackRate(double aPlaybackRate);
michael@0 263 void SetPreservesPitch(bool aPreservesPitch);
michael@0 264
michael@0 265 size_t SizeOfVideoQueue() {
michael@0 266 if (mReader) {
michael@0 267 return mReader->SizeOfVideoQueueInBytes();
michael@0 268 }
michael@0 269 return 0;
michael@0 270 }
michael@0 271
michael@0 272 size_t SizeOfAudioQueue() {
michael@0 273 if (mReader) {
michael@0 274 return mReader->SizeOfAudioQueueInBytes();
michael@0 275 }
michael@0 276 return 0;
michael@0 277 }
michael@0 278
michael@0 279 void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
michael@0 280
michael@0 281 int64_t GetEndMediaTime() const {
michael@0 282 AssertCurrentThreadInMonitor();
michael@0 283 return mEndTime;
michael@0 284 }
michael@0 285
michael@0 286 bool IsTransportSeekable() {
michael@0 287 AssertCurrentThreadInMonitor();
michael@0 288 return mTransportSeekable;
michael@0 289 }
michael@0 290
michael@0 291 bool IsMediaSeekable() {
michael@0 292 AssertCurrentThreadInMonitor();
michael@0 293 return mMediaSeekable;
michael@0 294 }
michael@0 295
michael@0 296 // Returns the shared state machine thread.
michael@0 297 nsIEventTarget* GetStateMachineThread();
michael@0 298
michael@0 299 // Calls ScheduleStateMachine() after taking the decoder lock. Also
michael@0 300 // notifies the decoder thread in case it's waiting on the decoder lock.
michael@0 301 void ScheduleStateMachineWithLockAndWakeDecoder();
michael@0 302
michael@0 303 // Schedules the shared state machine thread to run the state machine
michael@0 304 // in aUsecs microseconds from now, if it's not already scheduled to run
michael@0 305 // earlier, in which case the request is discarded.
michael@0 306 nsresult ScheduleStateMachine(int64_t aUsecs = 0);
michael@0 307
michael@0 308 // Timer function to implement ScheduleStateMachine(aUsecs).
michael@0 309 nsresult TimeoutExpired(int aGeneration);
michael@0 310
michael@0 311 // Set the media fragment end time. aEndTime is in microseconds.
michael@0 312 void SetFragmentEndTime(int64_t aEndTime);
michael@0 313
michael@0 314 // Drop reference to decoder. Only called during shutdown dance.
michael@0 315 void ReleaseDecoder() {
michael@0 316 MOZ_ASSERT(mReader);
michael@0 317 if (mReader) {
michael@0 318 mReader->ReleaseDecoder();
michael@0 319 }
michael@0 320 mDecoder = nullptr;
michael@0 321 }
michael@0 322
michael@0 323 // If we're playing into a MediaStream, record the current point in the
michael@0 324 // MediaStream and the current point in our media resource so later we can
michael@0 325 // convert MediaStream playback positions to media resource positions. Best to
michael@0 326 // call this while we're not playing (while the MediaStream is blocked). Can
michael@0 327 // be called on any thread with the decoder monitor held.
michael@0 328 void SetSyncPointForMediaStream();
michael@0 329 int64_t GetCurrentTimeViaMediaStreamSync();
michael@0 330
michael@0 331 // Copy queued audio/video data in the reader to any output MediaStreams that
michael@0 332 // need it.
michael@0 333 void SendStreamData();
michael@0 334 void FinishStreamData();
michael@0 335 bool HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs);
michael@0 336 bool HaveEnoughDecodedVideo();
michael@0 337
michael@0 338 // Returns true if the state machine has shutdown or is in the process of
michael@0 339 // shutting down. The decoder monitor must be held while calling this.
michael@0 340 bool IsShutdown();
michael@0 341
michael@0 342 void QueueMetadata(int64_t aPublishTime, int aChannels, int aRate, bool aHasAudio, bool aHasVideo, MetadataTags* aTags);
michael@0 343
michael@0 344 // Returns true if we're currently playing. The decoder monitor must
michael@0 345 // be held.
michael@0 346 bool IsPlaying();
michael@0 347
michael@0 348 // Called when the reader may have acquired the hardware resources required
michael@0 349 // to begin decoding. The state machine may move into DECODING_METADATA if
michael@0 350 // appropriate. The decoder monitor must be held while calling this.
michael@0 351 void NotifyWaitingForResourcesStatusChanged();
michael@0 352
michael@0 353 // Notifies the state machine that should minimize the number of samples
michael@0 354 // decoded we preroll, until playback starts. The first time playback starts
michael@0 355 // the state machine is free to return to prerolling normally. Note
michael@0 356 // "prerolling" in this context refers to when we decode and buffer decoded
michael@0 357 // samples in advance of when they're needed for playback.
michael@0 358 void SetMinimizePrerollUntilPlaybackStarts();
michael@0 359
michael@0 360 protected:
michael@0 361 virtual ~MediaDecoderStateMachine();
michael@0 362
michael@0 363 void AssertCurrentThreadInMonitor() const { mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); }
michael@0 364
michael@0 365 class WakeDecoderRunnable : public nsRunnable {
michael@0 366 public:
michael@0 367 WakeDecoderRunnable(MediaDecoderStateMachine* aSM)
michael@0 368 : mMutex("WakeDecoderRunnable"), mStateMachine(aSM) {}
michael@0 369 NS_IMETHOD Run() MOZ_OVERRIDE
michael@0 370 {
michael@0 371 nsRefPtr<MediaDecoderStateMachine> stateMachine;
michael@0 372 {
michael@0 373 // Don't let Run() (called by media stream graph thread) race with
michael@0 374 // Revoke() (called by decoder state machine thread)
michael@0 375 MutexAutoLock lock(mMutex);
michael@0 376 if (!mStateMachine)
michael@0 377 return NS_OK;
michael@0 378 stateMachine = mStateMachine;
michael@0 379 }
michael@0 380 stateMachine->ScheduleStateMachineWithLockAndWakeDecoder();
michael@0 381 return NS_OK;
michael@0 382 }
michael@0 383 void Revoke()
michael@0 384 {
michael@0 385 MutexAutoLock lock(mMutex);
michael@0 386 mStateMachine = nullptr;
michael@0 387 }
michael@0 388
michael@0 389 Mutex mMutex;
michael@0 390 // Protected by mMutex.
michael@0 391 // We don't use an owning pointer here, because keeping mStateMachine alive
michael@0 392 // would mean in some cases we'd have to destroy mStateMachine from this
michael@0 393 // object, which would be problematic since MediaDecoderStateMachine can
michael@0 394 // only be destroyed on the main thread whereas this object can be destroyed
michael@0 395 // on the media stream graph thread.
michael@0 396 MediaDecoderStateMachine* mStateMachine;
michael@0 397 };
michael@0 398 WakeDecoderRunnable* GetWakeDecoderRunnable();
michael@0 399
michael@0 400 MediaQueue<AudioData>& AudioQueue() { return mReader->AudioQueue(); }
michael@0 401 MediaQueue<VideoData>& VideoQueue() { return mReader->VideoQueue(); }
michael@0 402
michael@0 403 // True if our buffers of decoded audio are not full, and we should
michael@0 404 // decode more.
michael@0 405 bool NeedToDecodeAudio();
michael@0 406
michael@0 407 // Decodes some audio. This should be run on the decode task queue.
michael@0 408 void DecodeAudio();
michael@0 409
michael@0 410 // True if our buffers of decoded video are not full, and we should
michael@0 411 // decode more.
michael@0 412 bool NeedToDecodeVideo();
michael@0 413
michael@0 414 // Decodes some video. This should be run on the decode task queue.
michael@0 415 void DecodeVideo();
michael@0 416
michael@0 417 // Returns true if we've got less than aAudioUsecs microseconds of decoded
michael@0 418 // and playable data. The decoder monitor must be held.
michael@0 419 bool HasLowDecodedData(int64_t aAudioUsecs);
michael@0 420
michael@0 421 // Returns true if we're running low on data which is not yet decoded.
michael@0 422 // The decoder monitor must be held.
michael@0 423 bool HasLowUndecodedData();
michael@0 424
michael@0 425 // Returns true if we have less than aUsecs of undecoded data available.
michael@0 426 bool HasLowUndecodedData(double aUsecs);
michael@0 427
michael@0 428 // Returns the number of unplayed usecs of audio we've got decoded and/or
michael@0 429 // pushed to the hardware waiting to play. This is how much audio we can
michael@0 430 // play without having to run the audio decoder. The decoder monitor
michael@0 431 // must be held.
michael@0 432 int64_t AudioDecodedUsecs();
michael@0 433
michael@0 434 // Returns true when there's decoded audio waiting to play.
michael@0 435 // The decoder monitor must be held.
michael@0 436 bool HasFutureAudio();
michael@0 437
michael@0 438 // Returns true if we recently exited "quick buffering" mode.
michael@0 439 bool JustExitedQuickBuffering();
michael@0 440
michael@0 441 // Waits on the decoder ReentrantMonitor for aUsecs microseconds. If the decoder
michael@0 442 // monitor is awoken by a Notify() call, we'll continue waiting, unless
michael@0 443 // we've moved into shutdown state. This enables us to ensure that we
michael@0 444 // wait for a specified time, and that the myriad of Notify()s we do on
michael@0 445 // the decoder monitor don't cause the audio thread to be starved. aUsecs
michael@0 446 // values of less than 1 millisecond are rounded up to 1 millisecond
michael@0 447 // (see bug 651023). The decoder monitor must be held. Called only on the
michael@0 448 // audio thread.
michael@0 449 void Wait(int64_t aUsecs);
michael@0 450
michael@0 451 // Dispatches an asynchronous event to update the media element's ready state.
michael@0 452 void UpdateReadyState();
michael@0 453
michael@0 454 // Resets playback timing data. Called when we seek, on the decode thread.
michael@0 455 void ResetPlayback();
michael@0 456
michael@0 457 // Returns the audio clock, if we have audio, or -1 if we don't.
michael@0 458 // Called on the state machine thread.
michael@0 459 int64_t GetAudioClock();
michael@0 460
michael@0 461 // Get the video stream position, taking the |playbackRate| change into
michael@0 462 // account. This is a position in the media, not the duration of the playback
michael@0 463 // so far.
michael@0 464 int64_t GetVideoStreamPosition();
michael@0 465
michael@0 466 // Return the current time, either the audio clock if available (if the media
michael@0 467 // has audio, and the playback is possible), or a clock for the video.
michael@0 468 // Called on the state machine thread.
michael@0 469 int64_t GetClock();
michael@0 470
michael@0 471 // Returns the presentation time of the first audio or video frame in the
michael@0 472 // media. If the media has video, it returns the first video frame. The
michael@0 473 // decoder monitor must be held with exactly one lock count. Called on the
michael@0 474 // state machine thread.
michael@0 475 VideoData* FindStartTime();
michael@0 476
michael@0 477 // Update only the state machine's current playback position (and duration,
michael@0 478 // if unknown). Does not update the playback position on the decoder or
michael@0 479 // media element -- use UpdatePlaybackPosition for that. Called on the state
michael@0 480 // machine thread, caller must hold the decoder lock.
michael@0 481 void UpdatePlaybackPositionInternal(int64_t aTime);
michael@0 482
michael@0 483 // Pushes the image down the rendering pipeline. Called on the shared state
michael@0 484 // machine thread. The decoder monitor must *not* be held when calling this.
michael@0 485 void RenderVideoFrame(VideoData* aData, TimeStamp aTarget);
michael@0 486
michael@0 487 // If we have video, display a video frame if it's time for display has
michael@0 488 // arrived, otherwise sleep until it's time for the next frame. Update the
michael@0 489 // current frame time as appropriate, and trigger ready state update. The
michael@0 490 // decoder monitor must be held with exactly one lock count. Called on the
michael@0 491 // state machine thread.
michael@0 492 void AdvanceFrame();
michael@0 493
michael@0 494 // Write aFrames of audio frames of silence to the audio hardware. Returns
michael@0 495 // the number of frames actually written. The write size is capped at
michael@0 496 // SILENCE_BYTES_CHUNK (32kB), so must be called in a loop to write the
michael@0 497 // desired number of frames. This ensures that the playback position
michael@0 498 // advances smoothly, and guarantees that we don't try to allocate an
michael@0 499 // impossibly large chunk of memory in order to play back silence. Called
michael@0 500 // on the audio thread.
michael@0 501 uint32_t PlaySilence(uint32_t aFrames,
michael@0 502 uint32_t aChannels,
michael@0 503 uint64_t aFrameOffset);
michael@0 504
michael@0 505 // Pops an audio chunk from the front of the audio queue, and pushes its
michael@0 506 // audio data to the audio hardware.
michael@0 507 uint32_t PlayFromAudioQueue(uint64_t aFrameOffset, uint32_t aChannels);
michael@0 508
michael@0 509 // Stops the audio thread. The decoder monitor must be held with exactly
michael@0 510 // one lock count. Called on the state machine thread.
michael@0 511 void StopAudioThread();
michael@0 512
michael@0 513 // Starts the audio thread. The decoder monitor must be held with exactly
michael@0 514 // one lock count. Called on the state machine thread.
michael@0 515 nsresult StartAudioThread();
michael@0 516
michael@0 517 // The main loop for the audio thread. Sent to the thread as
michael@0 518 // an nsRunnableMethod. This continually does blocking writes to
michael@0 519 // to audio stream to play audio data.
michael@0 520 void AudioLoop();
michael@0 521
michael@0 522 // Sets internal state which causes playback of media to pause.
michael@0 523 // The decoder monitor must be held.
michael@0 524 void StopPlayback();
michael@0 525
michael@0 526 // Sets internal state which causes playback of media to begin or resume.
michael@0 527 // Must be called with the decode monitor held.
michael@0 528 void StartPlayback();
michael@0 529
michael@0 530 // Moves the decoder into decoding state. Called on the state machine
michael@0 531 // thread. The decoder monitor must be held.
michael@0 532 void StartDecoding();
michael@0 533
michael@0 534 // Moves the decoder into the shutdown state, and dispatches an error
michael@0 535 // event to the media element. This begins shutting down the decoder.
michael@0 536 // The decoder monitor must be held. This is only called on the
michael@0 537 // decode thread.
michael@0 538 void DecodeError();
michael@0 539
michael@0 540 void StartWaitForResources();
michael@0 541
michael@0 542 // Dispatches a task to the decode task queue to begin decoding metadata.
michael@0 543 // This is threadsafe and can be called on any thread.
michael@0 544 // The decoder monitor must be held.
michael@0 545 nsresult EnqueueDecodeMetadataTask();
michael@0 546
michael@0 547 nsresult DispatchAudioDecodeTaskIfNeeded();
michael@0 548
michael@0 549 // Ensures a to decode audio has been dispatched to the decode task queue.
michael@0 550 // If a task to decode has already been dispatched, this does nothing,
michael@0 551 // otherwise this dispatches a task to do the decode.
michael@0 552 // This is called on the state machine or decode threads.
michael@0 553 // The decoder monitor must be held.
michael@0 554 nsresult EnsureAudioDecodeTaskQueued();
michael@0 555
michael@0 556 nsresult DispatchVideoDecodeTaskIfNeeded();
michael@0 557
michael@0 558 // Ensures a to decode video has been dispatched to the decode task queue.
michael@0 559 // If a task to decode has already been dispatched, this does nothing,
michael@0 560 // otherwise this dispatches a task to do the decode.
michael@0 561 // The decoder monitor must be held.
michael@0 562 nsresult EnsureVideoDecodeTaskQueued();
michael@0 563
michael@0 564 // Dispatches a task to the decode task queue to seek the decoder.
michael@0 565 // The decoder monitor must be held.
michael@0 566 nsresult EnqueueDecodeSeekTask();
michael@0 567
michael@0 568 // Calls the reader's SetIdle(), with aIsIdle as parameter. This is only
michael@0 569 // called in a task dispatched to the decode task queue, don't call it
michael@0 570 // directly.
michael@0 571 void SetReaderIdle();
michael@0 572 void SetReaderActive();
michael@0 573
michael@0 574 // Re-evaluates the state and determines whether we need to dispatch
michael@0 575 // events to run the decode, or if not whether we should set the reader
michael@0 576 // to idle mode. This is threadsafe, and can be called from any thread.
michael@0 577 // The decoder monitor must be held.
michael@0 578 void DispatchDecodeTasksIfNeeded();
michael@0 579
michael@0 580 // Called before we do anything on the decode task queue to set the reader
michael@0 581 // as not idle if it was idle. This is called before we decode, seek, or
michael@0 582 // decode metadata (in case we were dormant or awaiting resources).
michael@0 583 void EnsureActive();
michael@0 584
michael@0 585 // Queries our state to see whether the decode has finished for all streams.
michael@0 586 // If so, we move into DECODER_STATE_COMPLETED and schedule the state machine
michael@0 587 // to run.
michael@0 588 // The decoder monitor must be held.
michael@0 589 void CheckIfDecodeComplete();
michael@0 590
michael@0 591 // Returns the "media time". This is the absolute time which the media
michael@0 592 // playback has reached. i.e. this returns values in the range
michael@0 593 // [mStartTime, mEndTime], and mStartTime will not be 0 if the media does
michael@0 594 // not start at 0. Note this is different to the value returned
michael@0 595 // by GetCurrentTime(), which is in the range [0,duration].
michael@0 596 int64_t GetMediaTime() const {
michael@0 597 AssertCurrentThreadInMonitor();
michael@0 598 return mStartTime + mCurrentFrameTime;
michael@0 599 }
michael@0 600
michael@0 601 // Returns an upper bound on the number of microseconds of audio that is
michael@0 602 // decoded and playable. This is the sum of the number of usecs of audio which
michael@0 603 // is decoded and in the reader's audio queue, and the usecs of unplayed audio
michael@0 604 // which has been pushed to the audio hardware for playback. Note that after
michael@0 605 // calling this, the audio hardware may play some of the audio pushed to
michael@0 606 // hardware, so this can only be used as a upper bound. The decoder monitor
michael@0 607 // must be held when calling this. Called on the decode thread.
michael@0 608 int64_t GetDecodedAudioDuration();
michael@0 609
michael@0 610 // Load metadata. Called on the decode thread. The decoder monitor
michael@0 611 // must be held with exactly one lock count.
michael@0 612 nsresult DecodeMetadata();
michael@0 613
michael@0 614 // Seeks to mSeekTarget. Called on the decode thread. The decoder monitor
michael@0 615 // must be held with exactly one lock count.
michael@0 616 void DecodeSeek();
michael@0 617
michael@0 618 // Decode loop, decodes data until EOF or shutdown.
michael@0 619 // Called on the decode thread.
michael@0 620 void DecodeLoop();
michael@0 621
michael@0 622 void CallDecodeMetadata();
michael@0 623
michael@0 624 // Copy audio from an AudioData packet to aOutput. This may require
michael@0 625 // inserting silence depending on the timing of the audio packet.
michael@0 626 void SendStreamAudio(AudioData* aAudio, DecodedStreamData* aStream,
michael@0 627 AudioSegment* aOutput);
michael@0 628
michael@0 629 // State machine thread run function. Defers to RunStateMachine().
michael@0 630 nsresult CallRunStateMachine();
michael@0 631
michael@0 632 // Performs one "cycle" of the state machine. Polls the state, and may send
michael@0 633 // a video frame to be displayed, and generally manages the decode. Called
michael@0 634 // periodically via timer to ensure the video stays in sync.
michael@0 635 nsresult RunStateMachine();
michael@0 636
michael@0 637 bool IsStateMachineScheduled() const {
michael@0 638 AssertCurrentThreadInMonitor();
michael@0 639 return !mTimeout.IsNull();
michael@0 640 }
michael@0 641
michael@0 642 // Returns true if we're not playing and the decode thread has filled its
michael@0 643 // decode buffers and is waiting. We can shut the decode thread down in this
michael@0 644 // case as it may not be needed again.
michael@0 645 bool IsPausedAndDecoderWaiting();
michael@0 646
michael@0 647 // The decoder object that created this state machine. The state machine
michael@0 648 // holds a strong reference to the decoder to ensure that the decoder stays
michael@0 649 // alive once media element has started the decoder shutdown process, and has
michael@0 650 // dropped its reference to the decoder. This enables the state machine to
michael@0 651 // keep using the decoder's monitor until the state machine has finished
michael@0 652 // shutting down, without fear of the monitor being destroyed. After
michael@0 653 // shutting down, the state machine will then release this reference,
michael@0 654 // causing the decoder to be destroyed. This is accessed on the decode,
michael@0 655 // state machine, audio and main threads.
michael@0 656 nsRefPtr<MediaDecoder> mDecoder;
michael@0 657
michael@0 658 // The decoder monitor must be obtained before modifying this state.
michael@0 659 // NotifyAll on the monitor must be called when the state is changed so
michael@0 660 // that interested threads can wake up and alter behaviour if appropriate
michael@0 661 // Accessed on state machine, audio, main, and AV thread.
michael@0 662 State mState;
michael@0 663
michael@0 664 // Thread for pushing audio onto the audio hardware.
michael@0 665 // The "audio push thread".
michael@0 666 nsCOMPtr<nsIThread> mAudioThread;
michael@0 667
michael@0 668 // The task queue in which we run decode tasks. This is referred to as
michael@0 669 // the "decode thread", though in practise tasks can run on a different
michael@0 670 // thread every time they're called.
michael@0 671 RefPtr<MediaTaskQueue> mDecodeTaskQueue;
michael@0 672
michael@0 673 RefPtr<SharedThreadPool> mStateMachineThreadPool;
michael@0 674
michael@0 675 // Timer to run the state machine cycles. Used by
michael@0 676 // ScheduleStateMachine(). Access protected by decoder monitor.
michael@0 677 nsCOMPtr<nsITimer> mTimer;
michael@0 678
michael@0 679 // Timestamp at which the next state machine cycle will run.
michael@0 680 // Access protected by decoder monitor.
michael@0 681 TimeStamp mTimeout;
michael@0 682
michael@0 683 // Used to check if there are state machine cycles are running in sequence.
michael@0 684 DebugOnly<bool> mInRunningStateMachine;
michael@0 685
michael@0 686 // The time that playback started from the system clock. This is used for
michael@0 687 // timing the presentation of video frames when there's no audio.
michael@0 688 // Accessed only via the state machine thread.
michael@0 689 TimeStamp mPlayStartTime;
michael@0 690
michael@0 691 // When we start writing decoded data to a new DecodedDataStream, or we
michael@0 692 // restart writing due to PlaybackStarted(), we record where we are in the
michael@0 693 // MediaStream and what that corresponds to in the media.
michael@0 694 StreamTime mSyncPointInMediaStream;
michael@0 695 int64_t mSyncPointInDecodedStream; // microseconds
michael@0 696
michael@0 697 // When the playbackRate changes, and there is no audio clock, it is necessary
michael@0 698 // to reset the mPlayStartTime. This is done next time the clock is queried,
michael@0 699 // when this member is true. Access protected by decoder monitor.
michael@0 700 bool mResetPlayStartTime;
michael@0 701
michael@0 702 // The amount of time we've spent playing already the media. The current
michael@0 703 // playback position is therefore |Now() - mPlayStartTime +
michael@0 704 // mPlayDuration|, which must be adjusted by mStartTime if used with media
michael@0 705 // timestamps. Accessed only via the state machine thread.
michael@0 706 int64_t mPlayDuration;
michael@0 707
michael@0 708 // Time that buffering started. Used for buffering timeout and only
michael@0 709 // accessed on the state machine thread. This is null while we're not
michael@0 710 // buffering.
michael@0 711 TimeStamp mBufferingStart;
michael@0 712
michael@0 713 // Start time of the media, in microseconds. This is the presentation
michael@0 714 // time of the first frame decoded from the media, and is used to calculate
michael@0 715 // duration and as a bounds for seeking. Accessed on state machine, decode,
michael@0 716 // and main threads. Access controlled by decoder monitor.
michael@0 717 int64_t mStartTime;
michael@0 718
michael@0 719 // Time of the last frame in the media, in microseconds. This is the
michael@0 720 // end time of the last frame in the media. Accessed on state
michael@0 721 // machine, decode, and main threads. Access controlled by decoder monitor.
michael@0 722 int64_t mEndTime;
michael@0 723
michael@0 724 // Position to seek to in microseconds when the seek state transition occurs.
michael@0 725 // The decoder monitor lock must be obtained before reading or writing
michael@0 726 // this value. Accessed on main and decode thread.
michael@0 727 SeekTarget mSeekTarget;
michael@0 728
michael@0 729 // Media Fragment end time in microseconds. Access controlled by decoder monitor.
michael@0 730 int64_t mFragmentEndTime;
michael@0 731
michael@0 732 // The audio stream resource. Used on the state machine, and audio threads.
michael@0 733 // This is created and destroyed on the audio thread, while holding the
michael@0 734 // decoder monitor, so if this is used off the audio thread, you must
michael@0 735 // first acquire the decoder monitor and check that it is non-null.
michael@0 736 RefPtr<AudioStream> mAudioStream;
michael@0 737
michael@0 738 // The reader, don't call its methods with the decoder monitor held.
michael@0 739 // This is created in the play state machine's constructor, and destroyed
michael@0 740 // in the play state machine's destructor.
michael@0 741 nsAutoPtr<MediaDecoderReader> mReader;
michael@0 742
michael@0 743 // Accessed only on the state machine thread.
michael@0 744 // Not an nsRevocableEventPtr since we must Revoke() it well before
michael@0 745 // this object is destroyed, anyway.
michael@0 746 // Protected by decoder monitor except during the SHUTDOWN state after the
michael@0 747 // decoder thread has been stopped.
michael@0 748 nsRevocableEventPtr<WakeDecoderRunnable> mPendingWakeDecoder;
michael@0 749
michael@0 750 // The time of the current frame in microseconds. This is referenced from
michael@0 751 // 0 which is the initial playback position. Set by the state machine
michael@0 752 // thread, and read-only from the main thread to get the current
michael@0 753 // time value. Synchronised via decoder monitor.
michael@0 754 int64_t mCurrentFrameTime;
michael@0 755
michael@0 756 // The presentation time of the first audio frame that was played in
michael@0 757 // microseconds. We can add this to the audio stream position to determine
michael@0 758 // the current audio time. Accessed on audio and state machine thread.
michael@0 759 // Synchronized by decoder monitor.
michael@0 760 int64_t mAudioStartTime;
michael@0 761
michael@0 762 // The end time of the last audio frame that's been pushed onto the audio
michael@0 763 // hardware in microseconds. This will approximately be the end time of the
michael@0 764 // audio stream, unless another frame is pushed to the hardware.
michael@0 765 int64_t mAudioEndTime;
michael@0 766
michael@0 767 // The presentation end time of the last video frame which has been displayed
michael@0 768 // in microseconds. Accessed from the state machine thread.
michael@0 769 int64_t mVideoFrameEndTime;
michael@0 770
michael@0 771 // Volume of playback. 0.0 = muted. 1.0 = full volume. Read/Written
michael@0 772 // from the state machine and main threads. Synchronised via decoder
michael@0 773 // monitor.
michael@0 774 double mVolume;
michael@0 775
michael@0 776 // Playback rate. 1.0 : normal speed, 0.5 : two times slower. Synchronized via
michael@0 777 // decoder monitor.
michael@0 778 double mPlaybackRate;
michael@0 779
michael@0 780 // Pitch preservation for the playback rate. Synchronized via decoder monitor.
michael@0 781 bool mPreservesPitch;
michael@0 782
michael@0 783 // Position at which the last playback rate change occured, used to compute
michael@0 784 // the actual position in the stream when the playback rate changes and there
michael@0 785 // is no audio to be sync-ed to. Synchronized via decoder monitor.
michael@0 786 int64_t mBasePosition;
michael@0 787
michael@0 788 // Time at which we started decoding. Synchronised via decoder monitor.
michael@0 789 TimeStamp mDecodeStartTime;
michael@0 790
michael@0 791 // The maximum number of second we spend buffering when we are short on
michael@0 792 // unbuffered data.
michael@0 793 uint32_t mBufferingWait;
michael@0 794 int64_t mLowDataThresholdUsecs;
michael@0 795
michael@0 796 // If we've got more than mAmpleVideoFrames decoded video frames waiting in
michael@0 797 // the video queue, we will not decode any more video frames until some have
michael@0 798 // been consumed by the play state machine thread.
michael@0 799 uint32_t mAmpleVideoFrames;
michael@0 800
michael@0 801 // Low audio threshold. If we've decoded less than this much audio we
michael@0 802 // consider our audio decode "behind", and we may skip video decoding
michael@0 803 // in order to allow our audio decoding to catch up. We favour audio
michael@0 804 // decoding over video. We increase this threshold if we're slow to
michael@0 805 // decode video frames, in order to reduce the chance of audio underruns.
michael@0 806 // Note that we don't ever reset this threshold, it only ever grows as
michael@0 807 // we detect that the decode can't keep up with rendering.
michael@0 808 int64_t mLowAudioThresholdUsecs;
michael@0 809
michael@0 810 // Our "ample" audio threshold. Once we've this much audio decoded, we
michael@0 811 // pause decoding. If we increase mLowAudioThresholdUsecs, we'll also
michael@0 812 // increase this too appropriately (we don't want mLowAudioThresholdUsecs
michael@0 813 // to be greater than ampleAudioThreshold, else we'd stop decoding!).
michael@0 814 // Note that we don't ever reset this threshold, it only ever grows as
michael@0 815 // we detect that the decode can't keep up with rendering.
michael@0 816 int64_t mAmpleAudioThresholdUsecs;
michael@0 817
michael@0 818 // At the start of decoding we want to "preroll" the decode until we've
michael@0 819 // got a few frames decoded before we consider whether decode is falling
michael@0 820 // behind. Otherwise our "we're falling behind" logic will trigger
michael@0 821 // unneccessarily if we start playing as soon as the first sample is
michael@0 822 // decoded. These two fields store how many video frames and audio
michael@0 823 // samples we must consume before are considered to be finished prerolling.
michael@0 824 uint32_t mAudioPrerollUsecs;
michael@0 825 uint32_t mVideoPrerollFrames;
michael@0 826
michael@0 827 // When we start decoding (either for the first time, or after a pause)
michael@0 828 // we may be low on decoded data. We don't want our "low data" logic to
michael@0 829 // kick in and decide that we're low on decoded data because the download
michael@0 830 // can't keep up with the decode, and cause us to pause playback. So we
michael@0 831 // have a "preroll" stage, where we ignore the results of our "low data"
michael@0 832 // logic during the first few frames of our decode. This occurs during
michael@0 833 // playback. The flags below are true when the corresponding stream is
michael@0 834 // being "prerolled".
michael@0 835 bool mIsAudioPrerolling;
michael@0 836 bool mIsVideoPrerolling;
michael@0 837
michael@0 838 // True when we have an audio stream that we're decoding, and we have not
michael@0 839 // yet decoded to end of stream.
michael@0 840 bool mIsAudioDecoding;
michael@0 841
michael@0 842 // True when we have a video stream that we're decoding, and we have not
michael@0 843 // yet decoded to end of stream.
michael@0 844 bool mIsVideoDecoding;
michael@0 845
michael@0 846 // True when we have dispatched a task to the decode task queue to run
michael@0 847 // the audio decode.
michael@0 848 bool mDispatchedAudioDecodeTask;
michael@0 849
michael@0 850 // True when we have dispatched a task to the decode task queue to run
michael@0 851 // the video decode.
michael@0 852 bool mDispatchedVideoDecodeTask;
michael@0 853
michael@0 854 // True when the reader is initialized, but has been ordered "idle" by the
michael@0 855 // state machine. This happens when the MediaQueue's of decoded data are
michael@0 856 // "full" and playback is paused. The reader may choose to use the idle
michael@0 857 // notification to enter a low power state.
michael@0 858 bool mIsReaderIdle;
michael@0 859
michael@0 860 // If the video decode is falling behind the audio, we'll start dropping the
michael@0 861 // inter-frames up until the next keyframe which is at or before the current
michael@0 862 // playback position. skipToNextKeyframe is true if we're currently
michael@0 863 // skipping up to the next keyframe.
michael@0 864 bool mSkipToNextKeyFrame;
michael@0 865
michael@0 866 // True if we shouldn't play our audio (but still write it to any capturing
michael@0 867 // streams). When this is true, mStopAudioThread is always true and
michael@0 868 // the audio thread will never start again after it has stopped.
michael@0 869 bool mAudioCaptured;
michael@0 870
michael@0 871 // True if the media resource can be seeked on a transport level. Accessed
michael@0 872 // from the state machine and main threads. Synchronised via decoder monitor.
michael@0 873 bool mTransportSeekable;
michael@0 874
michael@0 875 // True if the media can be seeked. Accessed from the state machine and main
michael@0 876 // threads. Synchronised via decoder monitor.
michael@0 877 bool mMediaSeekable;
michael@0 878
michael@0 879 // True if an event to notify about a change in the playback
michael@0 880 // position has been queued, but not yet run. It is set to false when
michael@0 881 // the event is run. This allows coalescing of these events as they can be
michael@0 882 // produced many times per second. Synchronised via decoder monitor.
michael@0 883 // Accessed on main and state machine threads.
michael@0 884 bool mPositionChangeQueued;
michael@0 885
michael@0 886 // True if the audio playback thread has finished. It is finished
michael@0 887 // when either all the audio frames have completed playing, or we've moved
michael@0 888 // into shutdown state, and the threads are to be
michael@0 889 // destroyed. Written by the audio playback thread and read and written by
michael@0 890 // the state machine thread. Synchronised via decoder monitor.
michael@0 891 // When data is being sent to a MediaStream, this is true when all data has
michael@0 892 // been written to the MediaStream.
michael@0 893 bool mAudioCompleted;
michael@0 894
michael@0 895 // True if mDuration has a value obtained from an HTTP header, or from
michael@0 896 // the media index/metadata. Accessed on the state machine thread.
michael@0 897 bool mGotDurationFromMetaData;
michael@0 898
michael@0 899 // True if we've dispatched an event to the decode task queue to call
michael@0 900 // DecodeThreadRun(). We use this flag to prevent us from dispatching
michael@0 901 // unneccessary runnables, since the decode thread runs in a loop.
michael@0 902 bool mDispatchedEventToDecode;
michael@0 903
michael@0 904 // False while audio thread should be running. Accessed state machine
michael@0 905 // and audio threads. Syncrhonised by decoder monitor.
michael@0 906 bool mStopAudioThread;
michael@0 907
michael@0 908 // If this is true while we're in buffering mode, we can exit early,
michael@0 909 // as it's likely we may be able to playback. This happens when we enter
michael@0 910 // buffering mode soon after the decode starts, because the decode-ahead
michael@0 911 // ran fast enough to exhaust all data while the download is starting up.
michael@0 912 // Synchronised via decoder monitor.
michael@0 913 bool mQuickBuffering;
michael@0 914
michael@0 915 // True if we should not decode/preroll unnecessary samples, unless we're
michael@0 916 // played. "Prerolling" in this context refers to when we decode and
michael@0 917 // buffer decoded samples in advance of when they're needed for playback.
michael@0 918 // This flag is set for preload=metadata media, and means we won't
michael@0 919 // decode more than the first video frame and first block of audio samples
michael@0 920 // for that media when we startup, or after a seek. When Play() is called,
michael@0 921 // we reset this flag, as we assume the user is playing the media, so
michael@0 922 // prerolling is appropriate then. This flag is used to reduce the overhead
michael@0 923 // of prerolling samples for media elements that may not play, both
michael@0 924 // memory and CPU overhead.
michael@0 925 bool mMinimizePreroll;
michael@0 926
michael@0 927 // True if the decode thread has gone filled its buffers and is now
michael@0 928 // waiting to be awakened before it continues decoding. Synchronized
michael@0 929 // by the decoder monitor.
michael@0 930 bool mDecodeThreadWaiting;
michael@0 931
michael@0 932 // True is we are decoding a realtime stream, like a camera stream
michael@0 933 bool mRealTime;
michael@0 934
michael@0 935 // Stores presentation info required for playback. The decoder monitor
michael@0 936 // must be held when accessing this.
michael@0 937 MediaInfo mInfo;
michael@0 938
michael@0 939 mozilla::MediaMetadataManager mMetadataManager;
michael@0 940
michael@0 941 MediaDecoderOwner::NextFrameStatus mLastFrameStatus;
michael@0 942
michael@0 943 // The id of timer tasks, used to ignore tasks that are scheduled previously.
michael@0 944 int mTimerId;
michael@0 945 };
michael@0 946
michael@0 947 } // namespace mozilla;
michael@0 948 #endif

mercurial