Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
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 |