content/media/MediaDecoderStateMachine.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/MediaDecoderStateMachine.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,948 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +/*
    1.10 +Each video element for a media file has two threads:
    1.11 +
    1.12 +  1) The Audio thread writes the decoded audio data to the audio
    1.13 +     hardware. This is done in a separate thread to ensure that the
    1.14 +     audio hardware gets a constant stream of data without
    1.15 +     interruption due to decoding or display. At some point
    1.16 +     AudioStream will be refactored to have a callback interface
    1.17 +     where it asks for data and an extra thread will no longer be
    1.18 +     needed.
    1.19 +
    1.20 +  2) The decode thread. This thread reads from the media stream and
    1.21 +     decodes the Theora and Vorbis data. It places the decoded data into
    1.22 +     queues for the other threads to pull from.
    1.23 +
    1.24 +All file reads, seeks, and all decoding must occur on the decode thread.
    1.25 +Synchronisation of state between the thread is done via a monitor owned
    1.26 +by MediaDecoder.
    1.27 +
    1.28 +The lifetime of the decode and audio threads is controlled by the state
    1.29 +machine when it runs on the shared state machine thread. When playback
    1.30 +needs to occur they are created and events dispatched to them to run
    1.31 +them. These events exit when decoding/audio playback is completed or
    1.32 +no longer required.
    1.33 +
    1.34 +A/V synchronisation is handled by the state machine. It examines the audio
    1.35 +playback time and compares this to the next frame in the queue of video
    1.36 +frames. If it is time to play the video frame it is then displayed, otherwise
    1.37 +it schedules the state machine to run again at the time of the next frame.
    1.38 +
    1.39 +Frame skipping is done in the following ways:
    1.40 +
    1.41 +  1) The state machine will skip all frames in the video queue whose
    1.42 +     display time is less than the current audio time. This ensures
    1.43 +     the correct frame for the current time is always displayed.
    1.44 +
    1.45 +  2) The decode thread will stop decoding interframes and read to the
    1.46 +     next keyframe if it determines that decoding the remaining
    1.47 +     interframes will cause playback issues. It detects this by:
    1.48 +       a) If the amount of audio data in the audio queue drops
    1.49 +          below a threshold whereby audio may start to skip.
    1.50 +       b) If the video queue drops below a threshold where it
    1.51 +          will be decoding video data that won't be displayed due
    1.52 +          to the decode thread dropping the frame immediately.
    1.53 +
    1.54 +When hardware accelerated graphics is not available, YCbCr conversion
    1.55 +is done on the decode thread when video frames are decoded.
    1.56 +
    1.57 +The decode thread pushes decoded audio and videos frames into two
    1.58 +separate queues - one for audio and one for video. These are kept
    1.59 +separate to make it easy to constantly feed audio data to the audio
    1.60 +hardware while allowing frame skipping of video data. These queues are
    1.61 +threadsafe, and neither the decode, audio, or state machine should
    1.62 +be able to monopolize them, and cause starvation of the other threads.
    1.63 +
    1.64 +Both queues are bounded by a maximum size. When this size is reached
    1.65 +the decode thread will no longer decode video or audio depending on the
    1.66 +queue that has reached the threshold. If both queues are full, the decode
    1.67 +thread will wait on the decoder monitor.
    1.68 +
    1.69 +When the decode queues are full (they've reaced their maximum size) and
    1.70 +the decoder is not in PLAYING play state, the state machine may opt
    1.71 +to shut down the decode thread in order to conserve resources.
    1.72 +
    1.73 +During playback the audio thread will be idle (via a Wait() on the
    1.74 +monitor) if the audio queue is empty. Otherwise it constantly pops
    1.75 +audio data off the queue and plays it with a blocking write to the audio
    1.76 +hardware (via AudioStream).
    1.77 +
    1.78 +*/
    1.79 +#if !defined(MediaDecoderStateMachine_h__)
    1.80 +#define MediaDecoderStateMachine_h__
    1.81 +
    1.82 +#include "mozilla/Attributes.h"
    1.83 +#include "nsThreadUtils.h"
    1.84 +#include "MediaDecoder.h"
    1.85 +#include "mozilla/ReentrantMonitor.h"
    1.86 +#include "MediaDecoderReader.h"
    1.87 +#include "MediaDecoderOwner.h"
    1.88 +#include "MediaMetadataManager.h"
    1.89 +
    1.90 +class nsITimer;
    1.91 +
    1.92 +namespace mozilla {
    1.93 +
    1.94 +class AudioSegment;
    1.95 +class VideoSegment;
    1.96 +class MediaTaskQueue;
    1.97 +class SharedThreadPool;
    1.98 +
    1.99 +// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
   1.100 +// GetTickCount() and conflicts with MediaDecoderStateMachine::GetCurrentTime
   1.101 +// implementation.
   1.102 +#ifdef GetCurrentTime
   1.103 +#undef GetCurrentTime
   1.104 +#endif
   1.105 +
   1.106 +/*
   1.107 +  The state machine class. This manages the decoding and seeking in the
   1.108 +  MediaDecoderReader on the decode thread, and A/V sync on the shared
   1.109 +  state machine thread, and controls the audio "push" thread.
   1.110 +
   1.111 +  All internal state is synchronised via the decoder monitor. State changes
   1.112 +  are either propagated by NotifyAll on the monitor (typically when state
   1.113 +  changes need to be propagated to non-state machine threads) or by scheduling
   1.114 +  the state machine to run another cycle on the shared state machine thread.
   1.115 +
   1.116 +  See MediaDecoder.h for more details.
   1.117 +*/
   1.118 +class MediaDecoderStateMachine
   1.119 +{
   1.120 +  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachine)
   1.121 +public:
   1.122 +  typedef MediaDecoder::DecodedStreamData DecodedStreamData;
   1.123 +  MediaDecoderStateMachine(MediaDecoder* aDecoder,
   1.124 +                               MediaDecoderReader* aReader,
   1.125 +                               bool aRealTime = false);
   1.126 +
   1.127 +  nsresult Init(MediaDecoderStateMachine* aCloneDonor);
   1.128 +
   1.129 +  // Enumeration for the valid decoding states
   1.130 +  enum State {
   1.131 +    DECODER_STATE_DECODING_METADATA,
   1.132 +    DECODER_STATE_WAIT_FOR_RESOURCES,
   1.133 +    DECODER_STATE_DORMANT,
   1.134 +    DECODER_STATE_DECODING,
   1.135 +    DECODER_STATE_SEEKING,
   1.136 +    DECODER_STATE_BUFFERING,
   1.137 +    DECODER_STATE_COMPLETED,
   1.138 +    DECODER_STATE_SHUTDOWN
   1.139 +  };
   1.140 +
   1.141 +  State GetState() {
   1.142 +    AssertCurrentThreadInMonitor();
   1.143 +    return mState;
   1.144 +  }
   1.145 +
   1.146 +  // Set the audio volume. The decoder monitor must be obtained before
   1.147 +  // calling this.
   1.148 +  void SetVolume(double aVolume);
   1.149 +  void SetAudioCaptured(bool aCapture);
   1.150 +
   1.151 +  // Check if the decoder needs to become dormant state.
   1.152 +  bool IsDormantNeeded();
   1.153 +  // Set/Unset dormant state.
   1.154 +  void SetDormant(bool aDormant);
   1.155 +  void Shutdown();
   1.156 +
   1.157 +  // Called from the main thread to get the duration. The decoder monitor
   1.158 +  // must be obtained before calling this. It is in units of microseconds.
   1.159 +  int64_t GetDuration();
   1.160 +
   1.161 +  // Called from the main thread to set the duration of the media resource
   1.162 +  // if it is able to be obtained via HTTP headers. Called from the
   1.163 +  // state machine thread to set the duration if it is obtained from the
   1.164 +  // media metadata. The decoder monitor must be obtained before calling this.
   1.165 +  // aDuration is in microseconds.
   1.166 +  void SetDuration(int64_t aDuration);
   1.167 +
   1.168 +  // Called while decoding metadata to set the end time of the media
   1.169 +  // resource. The decoder monitor must be obtained before calling this.
   1.170 +  // aEndTime is in microseconds.
   1.171 +  void SetMediaEndTime(int64_t aEndTime);
   1.172 +
   1.173 +  // Called from main thread to update the duration with an estimated value.
   1.174 +  // The duration is only changed if its significantly different than the
   1.175 +  // the current duration, as the incoming duration is an estimate and so
   1.176 +  // often is unstable as more data is read and the estimate is updated.
   1.177 +  // Can result in a durationchangeevent. aDuration is in microseconds.
   1.178 +  void UpdateEstimatedDuration(int64_t aDuration);
   1.179 +
   1.180 +  // Functions used by assertions to ensure we're calling things
   1.181 +  // on the appropriate threads.
   1.182 +  bool OnDecodeThread() const;
   1.183 +  bool OnStateMachineThread() const;
   1.184 +  bool OnAudioThread() const {
   1.185 +    return IsCurrentThread(mAudioThread);
   1.186 +  }
   1.187 +
   1.188 +  MediaDecoderOwner::NextFrameStatus GetNextFrameStatus();
   1.189 +
   1.190 +  // Cause state transitions. These methods obtain the decoder monitor
   1.191 +  // to synchronise the change of state, and to notify other threads
   1.192 +  // that the state has changed.
   1.193 +  void Play();
   1.194 +
   1.195 +  // Seeks to the decoder to aTarget asynchronously.
   1.196 +  void Seek(const SeekTarget& aTarget);
   1.197 +
   1.198 +  // Returns the current playback position in seconds.
   1.199 +  // Called from the main thread to get the current frame time. The decoder
   1.200 +  // monitor must be obtained before calling this.
   1.201 +  double GetCurrentTime() const;
   1.202 +
   1.203 +  // Clear the flag indicating that a playback position change event
   1.204 +  // is currently queued. This is called from the main thread and must
   1.205 +  // be called with the decode monitor held.
   1.206 +  void ClearPositionChangeFlag();
   1.207 +
   1.208 +  // Called from the main thread or the decoder thread to set whether the media
   1.209 +  // resource can seek into unbuffered ranges. The decoder monitor must be
   1.210 +  // obtained before calling this.
   1.211 +  void SetTransportSeekable(bool aSeekable);
   1.212 +
   1.213 +  // Called from the main thread or the decoder thread to set whether the media
   1.214 +  // can seek to random location. This is not true for chained ogg and WebM
   1.215 +  // media without index. The decoder monitor must be obtained before calling
   1.216 +  // this.
   1.217 +  void SetMediaSeekable(bool aSeekable);
   1.218 +
   1.219 +  // Update the playback position. This can result in a timeupdate event
   1.220 +  // and an invalidate of the frame being dispatched asynchronously if
   1.221 +  // there is no such event currently queued.
   1.222 +  // Only called on the decoder thread. Must be called with
   1.223 +  // the decode monitor held.
   1.224 +  void UpdatePlaybackPosition(int64_t aTime);
   1.225 +
   1.226 +  // Causes the state machine to switch to buffering state, and to
   1.227 +  // immediately stop playback and buffer downloaded data. Must be called
   1.228 +  // with the decode monitor held. Called on the state machine thread and
   1.229 +  // the main thread.
   1.230 +  void StartBuffering();
   1.231 +
   1.232 +  // This is called on the state machine thread and audio thread.
   1.233 +  // The decoder monitor must be obtained before calling this.
   1.234 +  bool HasAudio() const {
   1.235 +    AssertCurrentThreadInMonitor();
   1.236 +    return mInfo.HasAudio();
   1.237 +  }
   1.238 +
   1.239 +  // This is called on the state machine thread and audio thread.
   1.240 +  // The decoder monitor must be obtained before calling this.
   1.241 +  bool HasVideo() const {
   1.242 +    AssertCurrentThreadInMonitor();
   1.243 +    return mInfo.HasVideo();
   1.244 +  }
   1.245 +
   1.246 +  // Should be called by main thread.
   1.247 +  bool HaveNextFrameData();
   1.248 +
   1.249 +  // Must be called with the decode monitor held.
   1.250 +  bool IsBuffering() const {
   1.251 +    AssertCurrentThreadInMonitor();
   1.252 +
   1.253 +    return mState == DECODER_STATE_BUFFERING;
   1.254 +  }
   1.255 +
   1.256 +  // Must be called with the decode monitor held.
   1.257 +  bool IsSeeking() const {
   1.258 +    AssertCurrentThreadInMonitor();
   1.259 +
   1.260 +    return mState == DECODER_STATE_SEEKING;
   1.261 +  }
   1.262 +
   1.263 +  nsresult GetBuffered(dom::TimeRanges* aBuffered);
   1.264 +
   1.265 +  void SetPlaybackRate(double aPlaybackRate);
   1.266 +  void SetPreservesPitch(bool aPreservesPitch);
   1.267 +
   1.268 +  size_t SizeOfVideoQueue() {
   1.269 +    if (mReader) {
   1.270 +      return mReader->SizeOfVideoQueueInBytes();
   1.271 +    }
   1.272 +    return 0;
   1.273 +  }
   1.274 +
   1.275 +  size_t SizeOfAudioQueue() {
   1.276 +    if (mReader) {
   1.277 +      return mReader->SizeOfAudioQueueInBytes();
   1.278 +    }
   1.279 +    return 0;
   1.280 +  }
   1.281 +
   1.282 +  void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
   1.283 +
   1.284 +  int64_t GetEndMediaTime() const {
   1.285 +    AssertCurrentThreadInMonitor();
   1.286 +    return mEndTime;
   1.287 +  }
   1.288 +
   1.289 +  bool IsTransportSeekable() {
   1.290 +    AssertCurrentThreadInMonitor();
   1.291 +    return mTransportSeekable;
   1.292 +  }
   1.293 +
   1.294 +  bool IsMediaSeekable() {
   1.295 +    AssertCurrentThreadInMonitor();
   1.296 +    return mMediaSeekable;
   1.297 +  }
   1.298 +
   1.299 +  // Returns the shared state machine thread.
   1.300 +  nsIEventTarget* GetStateMachineThread();
   1.301 +
   1.302 +  // Calls ScheduleStateMachine() after taking the decoder lock. Also
   1.303 +  // notifies the decoder thread in case it's waiting on the decoder lock.
   1.304 +  void ScheduleStateMachineWithLockAndWakeDecoder();
   1.305 +
   1.306 +  // Schedules the shared state machine thread to run the state machine
   1.307 +  // in aUsecs microseconds from now, if it's not already scheduled to run
   1.308 +  // earlier, in which case the request is discarded.
   1.309 +  nsresult ScheduleStateMachine(int64_t aUsecs = 0);
   1.310 +
   1.311 +  // Timer function to implement ScheduleStateMachine(aUsecs).
   1.312 +  nsresult TimeoutExpired(int aGeneration);
   1.313 +
   1.314 +  // Set the media fragment end time. aEndTime is in microseconds.
   1.315 +  void SetFragmentEndTime(int64_t aEndTime);
   1.316 +
   1.317 +  // Drop reference to decoder.  Only called during shutdown dance.
   1.318 +  void ReleaseDecoder() {
   1.319 +    MOZ_ASSERT(mReader);
   1.320 +    if (mReader) {
   1.321 +      mReader->ReleaseDecoder();
   1.322 +    }
   1.323 +    mDecoder = nullptr;
   1.324 +  }
   1.325 +
   1.326 +  // If we're playing into a MediaStream, record the current point in the
   1.327 +  // MediaStream and the current point in our media resource so later we can
   1.328 +  // convert MediaStream playback positions to media resource positions. Best to
   1.329 +  // call this while we're not playing (while the MediaStream is blocked). Can
   1.330 +  // be called on any thread with the decoder monitor held.
   1.331 +  void SetSyncPointForMediaStream();
   1.332 +  int64_t GetCurrentTimeViaMediaStreamSync();
   1.333 +
   1.334 +  // Copy queued audio/video data in the reader to any output MediaStreams that
   1.335 +  // need it.
   1.336 +  void SendStreamData();
   1.337 +  void FinishStreamData();
   1.338 +  bool HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs);
   1.339 +  bool HaveEnoughDecodedVideo();
   1.340 +
   1.341 +  // Returns true if the state machine has shutdown or is in the process of
   1.342 +  // shutting down. The decoder monitor must be held while calling this.
   1.343 +  bool IsShutdown();
   1.344 +
   1.345 +  void QueueMetadata(int64_t aPublishTime, int aChannels, int aRate, bool aHasAudio, bool aHasVideo, MetadataTags* aTags);
   1.346 +
   1.347 +  // Returns true if we're currently playing. The decoder monitor must
   1.348 +  // be held.
   1.349 +  bool IsPlaying();
   1.350 +
   1.351 +  // Called when the reader may have acquired the hardware resources required
   1.352 +  // to begin decoding. The state machine may move into DECODING_METADATA if
   1.353 +  // appropriate. The decoder monitor must be held while calling this.
   1.354 +  void NotifyWaitingForResourcesStatusChanged();
   1.355 +
   1.356 +  // Notifies the state machine that should minimize the number of samples
   1.357 +  // decoded we preroll, until playback starts. The first time playback starts
   1.358 +  // the state machine is free to return to prerolling normally. Note
   1.359 +  // "prerolling" in this context refers to when we decode and buffer decoded
   1.360 +  // samples in advance of when they're needed for playback.
   1.361 +  void SetMinimizePrerollUntilPlaybackStarts();
   1.362 +
   1.363 +protected:
   1.364 +  virtual ~MediaDecoderStateMachine();
   1.365 +
   1.366 +  void AssertCurrentThreadInMonitor() const { mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); }
   1.367 +
   1.368 +  class WakeDecoderRunnable : public nsRunnable {
   1.369 +  public:
   1.370 +    WakeDecoderRunnable(MediaDecoderStateMachine* aSM)
   1.371 +      : mMutex("WakeDecoderRunnable"), mStateMachine(aSM) {}
   1.372 +    NS_IMETHOD Run() MOZ_OVERRIDE
   1.373 +    {
   1.374 +      nsRefPtr<MediaDecoderStateMachine> stateMachine;
   1.375 +      {
   1.376 +        // Don't let Run() (called by media stream graph thread) race with
   1.377 +        // Revoke() (called by decoder state machine thread)
   1.378 +        MutexAutoLock lock(mMutex);
   1.379 +        if (!mStateMachine)
   1.380 +          return NS_OK;
   1.381 +        stateMachine = mStateMachine;
   1.382 +      }
   1.383 +      stateMachine->ScheduleStateMachineWithLockAndWakeDecoder();
   1.384 +      return NS_OK;
   1.385 +    }
   1.386 +    void Revoke()
   1.387 +    {
   1.388 +      MutexAutoLock lock(mMutex);
   1.389 +      mStateMachine = nullptr;
   1.390 +    }
   1.391 +
   1.392 +    Mutex mMutex;
   1.393 +    // Protected by mMutex.
   1.394 +    // We don't use an owning pointer here, because keeping mStateMachine alive
   1.395 +    // would mean in some cases we'd have to destroy mStateMachine from this
   1.396 +    // object, which would be problematic since MediaDecoderStateMachine can
   1.397 +    // only be destroyed on the main thread whereas this object can be destroyed
   1.398 +    // on the media stream graph thread.
   1.399 +    MediaDecoderStateMachine* mStateMachine;
   1.400 +  };
   1.401 +  WakeDecoderRunnable* GetWakeDecoderRunnable();
   1.402 +
   1.403 +  MediaQueue<AudioData>& AudioQueue() { return mReader->AudioQueue(); }
   1.404 +  MediaQueue<VideoData>& VideoQueue() { return mReader->VideoQueue(); }
   1.405 +
   1.406 +  // True if our buffers of decoded audio are not full, and we should
   1.407 +  // decode more.
   1.408 +  bool NeedToDecodeAudio();
   1.409 +
   1.410 +  // Decodes some audio. This should be run on the decode task queue.
   1.411 +  void DecodeAudio();
   1.412 +
   1.413 +  // True if our buffers of decoded video are not full, and we should
   1.414 +  // decode more.
   1.415 +  bool NeedToDecodeVideo();
   1.416 +
   1.417 +  // Decodes some video. This should be run on the decode task queue.
   1.418 +  void DecodeVideo();
   1.419 +
   1.420 +  // Returns true if we've got less than aAudioUsecs microseconds of decoded
   1.421 +  // and playable data. The decoder monitor must be held.
   1.422 +  bool HasLowDecodedData(int64_t aAudioUsecs);
   1.423 +
   1.424 +  // Returns true if we're running low on data which is not yet decoded.
   1.425 +  // The decoder monitor must be held.
   1.426 +  bool HasLowUndecodedData();
   1.427 +
   1.428 +  // Returns true if we have less than aUsecs of undecoded data available.
   1.429 +  bool HasLowUndecodedData(double aUsecs);
   1.430 +
   1.431 +  // Returns the number of unplayed usecs of audio we've got decoded and/or
   1.432 +  // pushed to the hardware waiting to play. This is how much audio we can
   1.433 +  // play without having to run the audio decoder. The decoder monitor
   1.434 +  // must be held.
   1.435 +  int64_t AudioDecodedUsecs();
   1.436 +
   1.437 +  // Returns true when there's decoded audio waiting to play.
   1.438 +  // The decoder monitor must be held.
   1.439 +  bool HasFutureAudio();
   1.440 +
   1.441 +  // Returns true if we recently exited "quick buffering" mode.
   1.442 +  bool JustExitedQuickBuffering();
   1.443 +
   1.444 +  // Waits on the decoder ReentrantMonitor for aUsecs microseconds. If the decoder
   1.445 +  // monitor is awoken by a Notify() call, we'll continue waiting, unless
   1.446 +  // we've moved into shutdown state. This enables us to ensure that we
   1.447 +  // wait for a specified time, and that the myriad of Notify()s we do on
   1.448 +  // the decoder monitor don't cause the audio thread to be starved. aUsecs
   1.449 +  // values of less than 1 millisecond are rounded up to 1 millisecond
   1.450 +  // (see bug 651023). The decoder monitor must be held. Called only on the
   1.451 +  // audio thread.
   1.452 +  void Wait(int64_t aUsecs);
   1.453 +
   1.454 +  // Dispatches an asynchronous event to update the media element's ready state.
   1.455 +  void UpdateReadyState();
   1.456 +
   1.457 +  // Resets playback timing data. Called when we seek, on the decode thread.
   1.458 +  void ResetPlayback();
   1.459 +
   1.460 +  // Returns the audio clock, if we have audio, or -1 if we don't.
   1.461 +  // Called on the state machine thread.
   1.462 +  int64_t GetAudioClock();
   1.463 +
   1.464 +  // Get the video stream position, taking the |playbackRate| change into
   1.465 +  // account. This is a position in the media, not the duration of the playback
   1.466 +  // so far.
   1.467 +  int64_t GetVideoStreamPosition();
   1.468 +
   1.469 +  // Return the current time, either the audio clock if available (if the media
   1.470 +  // has audio, and the playback is possible), or a clock for the video.
   1.471 +  // Called on the state machine thread.
   1.472 +  int64_t GetClock();
   1.473 +
   1.474 +  // Returns the presentation time of the first audio or video frame in the
   1.475 +  // media.  If the media has video, it returns the first video frame. The
   1.476 +  // decoder monitor must be held with exactly one lock count. Called on the
   1.477 +  // state machine thread.
   1.478 +  VideoData* FindStartTime();
   1.479 +
   1.480 +  // Update only the state machine's current playback position (and duration,
   1.481 +  // if unknown).  Does not update the playback position on the decoder or
   1.482 +  // media element -- use UpdatePlaybackPosition for that.  Called on the state
   1.483 +  // machine thread, caller must hold the decoder lock.
   1.484 +  void UpdatePlaybackPositionInternal(int64_t aTime);
   1.485 +
   1.486 +  // Pushes the image down the rendering pipeline. Called on the shared state
   1.487 +  // machine thread. The decoder monitor must *not* be held when calling this.
   1.488 +  void RenderVideoFrame(VideoData* aData, TimeStamp aTarget);
   1.489 +
   1.490 +  // If we have video, display a video frame if it's time for display has
   1.491 +  // arrived, otherwise sleep until it's time for the next frame. Update the
   1.492 +  // current frame time as appropriate, and trigger ready state update.  The
   1.493 +  // decoder monitor must be held with exactly one lock count. Called on the
   1.494 +  // state machine thread.
   1.495 +  void AdvanceFrame();
   1.496 +
   1.497 +  // Write aFrames of audio frames of silence to the audio hardware. Returns
   1.498 +  // the number of frames actually written. The write size is capped at
   1.499 +  // SILENCE_BYTES_CHUNK (32kB), so must be called in a loop to write the
   1.500 +  // desired number of frames. This ensures that the playback position
   1.501 +  // advances smoothly, and guarantees that we don't try to allocate an
   1.502 +  // impossibly large chunk of memory in order to play back silence. Called
   1.503 +  // on the audio thread.
   1.504 +  uint32_t PlaySilence(uint32_t aFrames,
   1.505 +                       uint32_t aChannels,
   1.506 +                       uint64_t aFrameOffset);
   1.507 +
   1.508 +  // Pops an audio chunk from the front of the audio queue, and pushes its
   1.509 +  // audio data to the audio hardware.
   1.510 +  uint32_t PlayFromAudioQueue(uint64_t aFrameOffset, uint32_t aChannels);
   1.511 +
   1.512 +  // Stops the audio thread. The decoder monitor must be held with exactly
   1.513 +  // one lock count. Called on the state machine thread.
   1.514 +  void StopAudioThread();
   1.515 +
   1.516 +  // Starts the audio thread. The decoder monitor must be held with exactly
   1.517 +  // one lock count. Called on the state machine thread.
   1.518 +  nsresult StartAudioThread();
   1.519 +
   1.520 +  // The main loop for the audio thread. Sent to the thread as
   1.521 +  // an nsRunnableMethod. This continually does blocking writes to
   1.522 +  // to audio stream to play audio data.
   1.523 +  void AudioLoop();
   1.524 +
   1.525 +  // Sets internal state which causes playback of media to pause.
   1.526 +  // The decoder monitor must be held.
   1.527 +  void StopPlayback();
   1.528 +
   1.529 +  // Sets internal state which causes playback of media to begin or resume.
   1.530 +  // Must be called with the decode monitor held.
   1.531 +  void StartPlayback();
   1.532 +
   1.533 +  // Moves the decoder into decoding state. Called on the state machine
   1.534 +  // thread. The decoder monitor must be held.
   1.535 +  void StartDecoding();
   1.536 +
   1.537 +  // Moves the decoder into the shutdown state, and dispatches an error
   1.538 +  // event to the media element. This begins shutting down the decoder.
   1.539 +  // The decoder monitor must be held. This is only called on the
   1.540 +  // decode thread.
   1.541 +  void DecodeError();
   1.542 +
   1.543 +  void StartWaitForResources();
   1.544 +
   1.545 +  // Dispatches a task to the decode task queue to begin decoding metadata.
   1.546 +  // This is threadsafe and can be called on any thread.
   1.547 +  // The decoder monitor must be held.
   1.548 +  nsresult EnqueueDecodeMetadataTask();
   1.549 +
   1.550 +  nsresult DispatchAudioDecodeTaskIfNeeded();
   1.551 +
   1.552 +  // Ensures a to decode audio has been dispatched to the decode task queue.
   1.553 +  // If a task to decode has already been dispatched, this does nothing,
   1.554 +  // otherwise this dispatches a task to do the decode.
   1.555 +  // This is called on the state machine or decode threads.
   1.556 +  // The decoder monitor must be held.
   1.557 +  nsresult EnsureAudioDecodeTaskQueued();
   1.558 +
   1.559 +  nsresult DispatchVideoDecodeTaskIfNeeded();
   1.560 +
   1.561 +  // Ensures a to decode video has been dispatched to the decode task queue.
   1.562 +  // If a task to decode has already been dispatched, this does nothing,
   1.563 +  // otherwise this dispatches a task to do the decode.
   1.564 +  // The decoder monitor must be held.
   1.565 +  nsresult EnsureVideoDecodeTaskQueued();
   1.566 +
   1.567 +  // Dispatches a task to the decode task queue to seek the decoder.
   1.568 +  // The decoder monitor must be held.
   1.569 +  nsresult EnqueueDecodeSeekTask();
   1.570 +
   1.571 +  // Calls the reader's SetIdle(), with aIsIdle as parameter. This is only
   1.572 +  // called in a task dispatched to the decode task queue, don't call it
   1.573 +  // directly.
   1.574 +  void SetReaderIdle();
   1.575 +  void SetReaderActive();
   1.576 +
   1.577 +  // Re-evaluates the state and determines whether we need to dispatch
   1.578 +  // events to run the decode, or if not whether we should set the reader
   1.579 +  // to idle mode. This is threadsafe, and can be called from any thread.
   1.580 +  // The decoder monitor must be held.
   1.581 +  void DispatchDecodeTasksIfNeeded();
   1.582 +
   1.583 +  // Called before we do anything on the decode task queue to set the reader
   1.584 +  // as not idle if it was idle. This is called before we decode, seek, or
   1.585 +  // decode metadata (in case we were dormant or awaiting resources).
   1.586 +  void EnsureActive();
   1.587 +
   1.588 +  // Queries our state to see whether the decode has finished for all streams.
   1.589 +  // If so, we move into DECODER_STATE_COMPLETED and schedule the state machine
   1.590 +  // to run.
   1.591 +  // The decoder monitor must be held.
   1.592 +  void CheckIfDecodeComplete();
   1.593 +
   1.594 +  // Returns the "media time". This is the absolute time which the media
   1.595 +  // playback has reached. i.e. this returns values in the range
   1.596 +  // [mStartTime, mEndTime], and mStartTime will not be 0 if the media does
   1.597 +  // not start at 0. Note this is different to the value returned
   1.598 +  // by GetCurrentTime(), which is in the range [0,duration].
   1.599 +  int64_t GetMediaTime() const {
   1.600 +    AssertCurrentThreadInMonitor();
   1.601 +    return mStartTime + mCurrentFrameTime;
   1.602 +  }
   1.603 +
   1.604 +  // Returns an upper bound on the number of microseconds of audio that is
   1.605 +  // decoded and playable. This is the sum of the number of usecs of audio which
   1.606 +  // is decoded and in the reader's audio queue, and the usecs of unplayed audio
   1.607 +  // which has been pushed to the audio hardware for playback. Note that after
   1.608 +  // calling this, the audio hardware may play some of the audio pushed to
   1.609 +  // hardware, so this can only be used as a upper bound. The decoder monitor
   1.610 +  // must be held when calling this. Called on the decode thread.
   1.611 +  int64_t GetDecodedAudioDuration();
   1.612 +
   1.613 +  // Load metadata. Called on the decode thread. The decoder monitor
   1.614 +  // must be held with exactly one lock count.
   1.615 +  nsresult DecodeMetadata();
   1.616 +
   1.617 +  // Seeks to mSeekTarget. Called on the decode thread. The decoder monitor
   1.618 +  // must be held with exactly one lock count.
   1.619 +  void DecodeSeek();
   1.620 +
   1.621 +  // Decode loop, decodes data until EOF or shutdown.
   1.622 +  // Called on the decode thread.
   1.623 +  void DecodeLoop();
   1.624 +
   1.625 +  void CallDecodeMetadata();
   1.626 +
   1.627 +  // Copy audio from an AudioData packet to aOutput. This may require
   1.628 +  // inserting silence depending on the timing of the audio packet.
   1.629 +  void SendStreamAudio(AudioData* aAudio, DecodedStreamData* aStream,
   1.630 +                       AudioSegment* aOutput);
   1.631 +
   1.632 +  // State machine thread run function. Defers to RunStateMachine().
   1.633 +  nsresult CallRunStateMachine();
   1.634 +
   1.635 +  // Performs one "cycle" of the state machine. Polls the state, and may send
   1.636 +  // a video frame to be displayed, and generally manages the decode. Called
   1.637 +  // periodically via timer to ensure the video stays in sync.
   1.638 +  nsresult RunStateMachine();
   1.639 +
   1.640 +  bool IsStateMachineScheduled() const {
   1.641 +    AssertCurrentThreadInMonitor();
   1.642 +    return !mTimeout.IsNull();
   1.643 +  }
   1.644 +
   1.645 +  // Returns true if we're not playing and the decode thread has filled its
   1.646 +  // decode buffers and is waiting. We can shut the decode thread down in this
   1.647 +  // case as it may not be needed again.
   1.648 +  bool IsPausedAndDecoderWaiting();
   1.649 +
   1.650 +  // The decoder object that created this state machine. The state machine
   1.651 +  // holds a strong reference to the decoder to ensure that the decoder stays
   1.652 +  // alive once media element has started the decoder shutdown process, and has
   1.653 +  // dropped its reference to the decoder. This enables the state machine to
   1.654 +  // keep using the decoder's monitor until the state machine has finished
   1.655 +  // shutting down, without fear of the monitor being destroyed. After
   1.656 +  // shutting down, the state machine will then release this reference,
   1.657 +  // causing the decoder to be destroyed. This is accessed on the decode,
   1.658 +  // state machine, audio and main threads.
   1.659 +  nsRefPtr<MediaDecoder> mDecoder;
   1.660 +
   1.661 +  // The decoder monitor must be obtained before modifying this state.
   1.662 +  // NotifyAll on the monitor must be called when the state is changed so
   1.663 +  // that interested threads can wake up and alter behaviour if appropriate
   1.664 +  // Accessed on state machine, audio, main, and AV thread.
   1.665 +  State mState;
   1.666 +
   1.667 +  // Thread for pushing audio onto the audio hardware.
   1.668 +  // The "audio push thread".
   1.669 +  nsCOMPtr<nsIThread> mAudioThread;
   1.670 +
   1.671 +  // The task queue in which we run decode tasks. This is referred to as
   1.672 +  // the "decode thread", though in practise tasks can run on a different
   1.673 +  // thread every time they're called.
   1.674 +  RefPtr<MediaTaskQueue> mDecodeTaskQueue;
   1.675 +
   1.676 +  RefPtr<SharedThreadPool> mStateMachineThreadPool;
   1.677 +
   1.678 +  // Timer to run the state machine cycles. Used by
   1.679 +  // ScheduleStateMachine(). Access protected by decoder monitor.
   1.680 +  nsCOMPtr<nsITimer> mTimer;
   1.681 +
   1.682 +  // Timestamp at which the next state machine cycle will run.
   1.683 +  // Access protected by decoder monitor.
   1.684 +  TimeStamp mTimeout;
   1.685 +
   1.686 +  // Used to check if there are state machine cycles are running in sequence.
   1.687 +  DebugOnly<bool> mInRunningStateMachine;
   1.688 +
   1.689 +  // The time that playback started from the system clock. This is used for
   1.690 +  // timing the presentation of video frames when there's no audio.
   1.691 +  // Accessed only via the state machine thread.
   1.692 +  TimeStamp mPlayStartTime;
   1.693 +
   1.694 +  // When we start writing decoded data to a new DecodedDataStream, or we
   1.695 +  // restart writing due to PlaybackStarted(), we record where we are in the
   1.696 +  // MediaStream and what that corresponds to in the media.
   1.697 +  StreamTime mSyncPointInMediaStream;
   1.698 +  int64_t mSyncPointInDecodedStream; // microseconds
   1.699 +
   1.700 +  // When the playbackRate changes, and there is no audio clock, it is necessary
   1.701 +  // to reset the mPlayStartTime. This is done next time the clock is queried,
   1.702 +  // when this member is true. Access protected by decoder monitor.
   1.703 +  bool mResetPlayStartTime;
   1.704 +
   1.705 +  // The amount of time we've spent playing already the media. The current
   1.706 +  // playback position is therefore |Now() - mPlayStartTime +
   1.707 +  // mPlayDuration|, which must be adjusted by mStartTime if used with media
   1.708 +  // timestamps.  Accessed only via the state machine thread.
   1.709 +  int64_t mPlayDuration;
   1.710 +
   1.711 +  // Time that buffering started. Used for buffering timeout and only
   1.712 +  // accessed on the state machine thread. This is null while we're not
   1.713 +  // buffering.
   1.714 +  TimeStamp mBufferingStart;
   1.715 +
   1.716 +  // Start time of the media, in microseconds. This is the presentation
   1.717 +  // time of the first frame decoded from the media, and is used to calculate
   1.718 +  // duration and as a bounds for seeking. Accessed on state machine, decode,
   1.719 +  // and main threads. Access controlled by decoder monitor.
   1.720 +  int64_t mStartTime;
   1.721 +
   1.722 +  // Time of the last frame in the media, in microseconds. This is the
   1.723 +  // end time of the last frame in the media. Accessed on state
   1.724 +  // machine, decode, and main threads. Access controlled by decoder monitor.
   1.725 +  int64_t mEndTime;
   1.726 +
   1.727 +  // Position to seek to in microseconds when the seek state transition occurs.
   1.728 +  // The decoder monitor lock must be obtained before reading or writing
   1.729 +  // this value. Accessed on main and decode thread.
   1.730 +  SeekTarget mSeekTarget;
   1.731 +
   1.732 +  // Media Fragment end time in microseconds. Access controlled by decoder monitor.
   1.733 +  int64_t mFragmentEndTime;
   1.734 +
   1.735 +  // The audio stream resource. Used on the state machine, and audio threads.
   1.736 +  // This is created and destroyed on the audio thread, while holding the
   1.737 +  // decoder monitor, so if this is used off the audio thread, you must
   1.738 +  // first acquire the decoder monitor and check that it is non-null.
   1.739 +  RefPtr<AudioStream> mAudioStream;
   1.740 +
   1.741 +  // The reader, don't call its methods with the decoder monitor held.
   1.742 +  // This is created in the play state machine's constructor, and destroyed
   1.743 +  // in the play state machine's destructor.
   1.744 +  nsAutoPtr<MediaDecoderReader> mReader;
   1.745 +
   1.746 +  // Accessed only on the state machine thread.
   1.747 +  // Not an nsRevocableEventPtr since we must Revoke() it well before
   1.748 +  // this object is destroyed, anyway.
   1.749 +  // Protected by decoder monitor except during the SHUTDOWN state after the
   1.750 +  // decoder thread has been stopped.
   1.751 +  nsRevocableEventPtr<WakeDecoderRunnable> mPendingWakeDecoder;
   1.752 +
   1.753 +  // The time of the current frame in microseconds. This is referenced from
   1.754 +  // 0 which is the initial playback position. Set by the state machine
   1.755 +  // thread, and read-only from the main thread to get the current
   1.756 +  // time value. Synchronised via decoder monitor.
   1.757 +  int64_t mCurrentFrameTime;
   1.758 +
   1.759 +  // The presentation time of the first audio frame that was played in
   1.760 +  // microseconds. We can add this to the audio stream position to determine
   1.761 +  // the current audio time. Accessed on audio and state machine thread.
   1.762 +  // Synchronized by decoder monitor.
   1.763 +  int64_t mAudioStartTime;
   1.764 +
   1.765 +  // The end time of the last audio frame that's been pushed onto the audio
   1.766 +  // hardware in microseconds. This will approximately be the end time of the
   1.767 +  // audio stream, unless another frame is pushed to the hardware.
   1.768 +  int64_t mAudioEndTime;
   1.769 +
   1.770 +  // The presentation end time of the last video frame which has been displayed
   1.771 +  // in microseconds. Accessed from the state machine thread.
   1.772 +  int64_t mVideoFrameEndTime;
   1.773 +
   1.774 +  // Volume of playback. 0.0 = muted. 1.0 = full volume. Read/Written
   1.775 +  // from the state machine and main threads. Synchronised via decoder
   1.776 +  // monitor.
   1.777 +  double mVolume;
   1.778 +
   1.779 +  // Playback rate. 1.0 : normal speed, 0.5 : two times slower. Synchronized via
   1.780 +  // decoder monitor.
   1.781 +  double mPlaybackRate;
   1.782 +
   1.783 +  // Pitch preservation for the playback rate. Synchronized via decoder monitor.
   1.784 +  bool mPreservesPitch;
   1.785 +
   1.786 +  // Position at which the last playback rate change occured, used to compute
   1.787 +  // the actual position in the stream when the playback rate changes and there
   1.788 +  // is no audio to be sync-ed to. Synchronized via decoder monitor.
   1.789 +  int64_t mBasePosition;
   1.790 +
   1.791 +  // Time at which we started decoding. Synchronised via decoder monitor.
   1.792 +  TimeStamp mDecodeStartTime;
   1.793 +
   1.794 +  // The maximum number of second we spend buffering when we are short on
   1.795 +  // unbuffered data.
   1.796 +  uint32_t mBufferingWait;
   1.797 +  int64_t  mLowDataThresholdUsecs;
   1.798 +
   1.799 +  // If we've got more than mAmpleVideoFrames decoded video frames waiting in
   1.800 +  // the video queue, we will not decode any more video frames until some have
   1.801 +  // been consumed by the play state machine thread.
   1.802 +  uint32_t mAmpleVideoFrames;
   1.803 +
   1.804 +  // Low audio threshold. If we've decoded less than this much audio we
   1.805 +  // consider our audio decode "behind", and we may skip video decoding
   1.806 +  // in order to allow our audio decoding to catch up. We favour audio
   1.807 +  // decoding over video. We increase this threshold if we're slow to
   1.808 +  // decode video frames, in order to reduce the chance of audio underruns.
   1.809 +  // Note that we don't ever reset this threshold, it only ever grows as
   1.810 +  // we detect that the decode can't keep up with rendering.
   1.811 +  int64_t mLowAudioThresholdUsecs;
   1.812 +
   1.813 +  // Our "ample" audio threshold. Once we've this much audio decoded, we
   1.814 +  // pause decoding. If we increase mLowAudioThresholdUsecs, we'll also
   1.815 +  // increase this too appropriately (we don't want mLowAudioThresholdUsecs
   1.816 +  // to be greater than ampleAudioThreshold, else we'd stop decoding!).
   1.817 +  // Note that we don't ever reset this threshold, it only ever grows as
   1.818 +  // we detect that the decode can't keep up with rendering.
   1.819 +  int64_t mAmpleAudioThresholdUsecs;
   1.820 +
   1.821 +  // At the start of decoding we want to "preroll" the decode until we've
   1.822 +  // got a few frames decoded before we consider whether decode is falling
   1.823 +  // behind. Otherwise our "we're falling behind" logic will trigger
   1.824 +  // unneccessarily if we start playing as soon as the first sample is
   1.825 +  // decoded. These two fields store how many video frames and audio
   1.826 +  // samples we must consume before are considered to be finished prerolling.
   1.827 +  uint32_t mAudioPrerollUsecs;
   1.828 +  uint32_t mVideoPrerollFrames;
   1.829 +
   1.830 +  // When we start decoding (either for the first time, or after a pause)
   1.831 +  // we may be low on decoded data. We don't want our "low data" logic to
   1.832 +  // kick in and decide that we're low on decoded data because the download
   1.833 +  // can't keep up with the decode, and cause us to pause playback. So we
   1.834 +  // have a "preroll" stage, where we ignore the results of our "low data"
   1.835 +  // logic during the first few frames of our decode. This occurs during
   1.836 +  // playback. The flags below are true when the corresponding stream is
   1.837 +  // being "prerolled".
   1.838 +  bool mIsAudioPrerolling;
   1.839 +  bool mIsVideoPrerolling;
   1.840 +
   1.841 +  // True when we have an audio stream that we're decoding, and we have not
   1.842 +  // yet decoded to end of stream.
   1.843 +  bool mIsAudioDecoding;
   1.844 +
   1.845 +  // True when we have a video stream that we're decoding, and we have not
   1.846 +  // yet decoded to end of stream.
   1.847 +  bool mIsVideoDecoding;
   1.848 +
   1.849 +  // True when we have dispatched a task to the decode task queue to run
   1.850 +  // the audio decode.
   1.851 +  bool mDispatchedAudioDecodeTask;
   1.852 +
   1.853 +  // True when we have dispatched a task to the decode task queue to run
   1.854 +  // the video decode.
   1.855 +  bool mDispatchedVideoDecodeTask;
   1.856 +
   1.857 +  // True when the reader is initialized, but has been ordered "idle" by the
   1.858 +  // state machine. This happens when the MediaQueue's of decoded data are
   1.859 +  // "full" and playback is paused. The reader may choose to use the idle
   1.860 +  // notification to enter a low power state.
   1.861 +  bool mIsReaderIdle;
   1.862 +
   1.863 +  // If the video decode is falling behind the audio, we'll start dropping the
   1.864 +  // inter-frames up until the next keyframe which is at or before the current
   1.865 +  // playback position. skipToNextKeyframe is true if we're currently
   1.866 +  // skipping up to the next keyframe.
   1.867 +  bool mSkipToNextKeyFrame;
   1.868 +
   1.869 +  // True if we shouldn't play our audio (but still write it to any capturing
   1.870 +  // streams). When this is true, mStopAudioThread is always true and
   1.871 +  // the audio thread will never start again after it has stopped.
   1.872 +  bool mAudioCaptured;
   1.873 +
   1.874 +  // True if the media resource can be seeked on a transport level. Accessed
   1.875 +  // from the state machine and main threads. Synchronised via decoder monitor.
   1.876 +  bool mTransportSeekable;
   1.877 +
   1.878 +  // True if the media can be seeked. Accessed from the state machine and main
   1.879 +  // threads. Synchronised via decoder monitor.
   1.880 +  bool mMediaSeekable;
   1.881 +
   1.882 +  // True if an event to notify about a change in the playback
   1.883 +  // position has been queued, but not yet run. It is set to false when
   1.884 +  // the event is run. This allows coalescing of these events as they can be
   1.885 +  // produced many times per second. Synchronised via decoder monitor.
   1.886 +  // Accessed on main and state machine threads.
   1.887 +  bool mPositionChangeQueued;
   1.888 +
   1.889 +  // True if the audio playback thread has finished. It is finished
   1.890 +  // when either all the audio frames have completed playing, or we've moved
   1.891 +  // into shutdown state, and the threads are to be
   1.892 +  // destroyed. Written by the audio playback thread and read and written by
   1.893 +  // the state machine thread. Synchronised via decoder monitor.
   1.894 +  // When data is being sent to a MediaStream, this is true when all data has
   1.895 +  // been written to the MediaStream.
   1.896 +  bool mAudioCompleted;
   1.897 +
   1.898 +  // True if mDuration has a value obtained from an HTTP header, or from
   1.899 +  // the media index/metadata. Accessed on the state machine thread.
   1.900 +  bool mGotDurationFromMetaData;
   1.901 +
   1.902 +  // True if we've dispatched an event to the decode task queue to call
   1.903 +  // DecodeThreadRun(). We use this flag to prevent us from dispatching
   1.904 +  // unneccessary runnables, since the decode thread runs in a loop.
   1.905 +  bool mDispatchedEventToDecode;
   1.906 +
   1.907 +  // False while audio thread should be running. Accessed state machine
   1.908 +  // and audio threads. Syncrhonised by decoder monitor.
   1.909 +  bool mStopAudioThread;
   1.910 +
   1.911 +  // If this is true while we're in buffering mode, we can exit early,
   1.912 +  // as it's likely we may be able to playback. This happens when we enter
   1.913 +  // buffering mode soon after the decode starts, because the decode-ahead
   1.914 +  // ran fast enough to exhaust all data while the download is starting up.
   1.915 +  // Synchronised via decoder monitor.
   1.916 +  bool mQuickBuffering;
   1.917 +
   1.918 +  // True if we should not decode/preroll unnecessary samples, unless we're
   1.919 +  // played. "Prerolling" in this context refers to when we decode and
   1.920 +  // buffer decoded samples in advance of when they're needed for playback.
   1.921 +  // This flag is set for preload=metadata media, and means we won't
   1.922 +  // decode more than the first video frame and first block of audio samples
   1.923 +  // for that media when we startup, or after a seek. When Play() is called,
   1.924 +  // we reset this flag, as we assume the user is playing the media, so
   1.925 +  // prerolling is appropriate then. This flag is used to reduce the overhead
   1.926 +  // of prerolling samples for media elements that may not play, both
   1.927 +  // memory and CPU overhead.
   1.928 +  bool mMinimizePreroll;
   1.929 +
   1.930 +  // True if the decode thread has gone filled its buffers and is now
   1.931 +  // waiting to be awakened before it continues decoding. Synchronized
   1.932 +  // by the decoder monitor.
   1.933 +  bool mDecodeThreadWaiting;
   1.934 +
   1.935 +  // True is we are decoding a realtime stream, like a camera stream
   1.936 +  bool mRealTime;
   1.937 +
   1.938 +  // Stores presentation info required for playback. The decoder monitor
   1.939 +  // must be held when accessing this.
   1.940 +  MediaInfo mInfo;
   1.941 +
   1.942 +  mozilla::MediaMetadataManager mMetadataManager;
   1.943 +
   1.944 +  MediaDecoderOwner::NextFrameStatus mLastFrameStatus;
   1.945 +
   1.946 +  // The id of timer tasks, used to ignore tasks that are scheduled previously.
   1.947 +  int mTimerId;
   1.948 +};
   1.949 +
   1.950 +} // namespace mozilla;
   1.951 +#endif

mercurial