2010-04-02 07:03:07 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: ML 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Chris Double <chris.double@double.co.nz>
|
|
|
|
* Chris Pearce <chris@pearce.org.nz>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
2010-04-27 12:53:44 +04:00
|
|
|
/*
|
2010-05-06 06:31:02 +04:00
|
|
|
Each video element for a media file has two additional threads beyond
|
2010-04-27 12:53:44 +04:00
|
|
|
those needed by nsBuiltinDecoder.
|
|
|
|
|
|
|
|
1) The Audio thread writes the decoded audio data to the audio
|
|
|
|
hardware. This is done in a seperate thread to ensure that the
|
|
|
|
audio hardware gets a constant stream of data without
|
|
|
|
interruption due to decoding or display. At some point
|
|
|
|
libsydneyaudio will be refactored to have a callback interface
|
|
|
|
where it asks for data and an extra thread will no longer be
|
|
|
|
needed.
|
|
|
|
|
|
|
|
2) The decode thread. This thread reads from the media stream and
|
|
|
|
decodes the Theora and Vorbis data. It places the decoded data in
|
|
|
|
a queue for the other threads to pull from.
|
|
|
|
|
|
|
|
All file reads and seeks must occur on either the state machine thread
|
|
|
|
or the decode thread. Synchronisation is done via a monitor owned by
|
|
|
|
nsBuiltinDecoder.
|
|
|
|
|
|
|
|
The decode thread and the audio thread are created and destroyed in
|
|
|
|
the state machine thread. When playback needs to occur they are
|
|
|
|
created and events dispatched to them to start them. These events exit
|
|
|
|
when decoding is completed or no longer required (during seeking or
|
|
|
|
shutdown).
|
|
|
|
|
|
|
|
The decode thread has its own monitor to ensure that its internal
|
|
|
|
state is independent of the other threads, and to ensure that it's not
|
|
|
|
hogging the nsBuiltinDecoder monitor while decoding.
|
|
|
|
|
|
|
|
a/v synchronisation is handled by the state machine thread. It
|
|
|
|
examines the audio playback time and compares this to the next frame
|
|
|
|
in the queue of frames. If it is time to play the video frame it is
|
|
|
|
then displayed.
|
|
|
|
|
|
|
|
Frame skipping is done in the following ways:
|
|
|
|
|
|
|
|
1) The state machine thread will skip all frames in the video queue whose
|
|
|
|
display time is less than the current audio time. This ensures
|
|
|
|
the correct frame for the current time is always displayed.
|
|
|
|
|
|
|
|
2) The decode thread will stop decoding interframes and read to the
|
|
|
|
next keyframe if it determines that decoding the remaining
|
|
|
|
interframes will cause playback issues. It detects this by:
|
|
|
|
a) If the amount of audio data in the audio queue drops
|
|
|
|
below a threshold whereby audio may start to skip.
|
|
|
|
b) If the video queue drops below a threshold where it
|
|
|
|
will be decoding video data that won't be displayed due
|
|
|
|
to the decode thread dropping the frame immediately.
|
|
|
|
|
|
|
|
YCbCr conversion is done on the decode thread when it is time to display
|
|
|
|
the video frame. This means frames that are skipped will not have the
|
|
|
|
YCbCr conversion done, improving playback.
|
|
|
|
|
|
|
|
The decode thread pushes decoded audio and videos frames into two
|
|
|
|
separate queues - one for audio and one for video. These are kept
|
|
|
|
separate to make it easy to constantly feed audio data to the sound
|
|
|
|
hardware while allowing frame skipping of video data. These queues are
|
|
|
|
threadsafe, and neither the decode, audio, or state machine thread should
|
|
|
|
be able to monopolize them, and cause starvation of the other threads.
|
|
|
|
|
|
|
|
Both queues are bounded by a maximum size. When this size is reached
|
|
|
|
the decode thread will no longer decode video or audio depending on the
|
|
|
|
queue that has reached the threshold.
|
|
|
|
|
|
|
|
During playback the audio thread will be idle (via a Wait() on the
|
|
|
|
monitor) if the audio queue is empty. Otherwise it constantly pops an
|
|
|
|
item off the queue and plays it with a blocking write to the audio
|
|
|
|
hardware (via nsAudioStream and libsydneyaudio).
|
|
|
|
|
|
|
|
The decode thread idles if the video queue is empty or if it is
|
|
|
|
not yet time to display the next frame.
|
|
|
|
*/
|
2010-05-06 06:31:02 +04:00
|
|
|
#if !defined(nsBuiltinDecoderStateMachine_h__)
|
|
|
|
#define nsBuiltinDecoderStateMachine_h__
|
2010-04-02 07:03:07 +04:00
|
|
|
|
|
|
|
#include "prmem.h"
|
|
|
|
#include "nsThreadUtils.h"
|
2010-04-27 12:53:44 +04:00
|
|
|
#include "nsBuiltinDecoder.h"
|
2010-05-06 06:31:02 +04:00
|
|
|
#include "nsBuiltinDecoderReader.h"
|
2010-08-25 17:10:00 +04:00
|
|
|
#include "nsAudioAvailableEventManager.h"
|
2010-04-02 07:03:07 +04:00
|
|
|
#include "nsHTMLMediaElement.h"
|
2011-04-29 23:21:57 +04:00
|
|
|
#include "mozilla/ReentrantMonitor.h"
|
2010-04-02 07:03:07 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
The playback state machine class. This manages the decoding in the
|
2010-05-06 06:31:02 +04:00
|
|
|
nsBuiltinDecoderReader on the decode thread, seeking and in-sync-playback on the
|
2010-04-02 07:03:07 +04:00
|
|
|
state machine thread, and controls the audio "push" thread.
|
|
|
|
|
|
|
|
All internal state is synchronised via the decoder monitor. NotifyAll
|
|
|
|
on the monitor is called when the state of the state machine is changed
|
|
|
|
by the main thread. The following changes to state cause a notify:
|
|
|
|
|
|
|
|
mState and data related to that state changed (mSeekTime, etc)
|
2010-05-06 06:31:02 +04:00
|
|
|
Metadata Loaded
|
2010-04-02 07:03:07 +04:00
|
|
|
First Frame Loaded
|
|
|
|
Frame decoded
|
|
|
|
data pushed or popped from the video and audio queues
|
|
|
|
|
2010-05-06 06:31:02 +04:00
|
|
|
See nsBuiltinDecoder.h for more details.
|
2010-04-02 07:03:07 +04:00
|
|
|
*/
|
2010-05-06 06:31:02 +04:00
|
|
|
class nsBuiltinDecoderStateMachine : public nsDecoderStateMachine
|
2010-04-02 07:03:07 +04:00
|
|
|
{
|
|
|
|
public:
|
2011-04-29 23:21:57 +04:00
|
|
|
typedef mozilla::ReentrantMonitor ReentrantMonitor;
|
2010-05-06 06:31:02 +04:00
|
|
|
typedef mozilla::TimeStamp TimeStamp;
|
|
|
|
typedef mozilla::TimeDuration TimeDuration;
|
|
|
|
|
|
|
|
nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder, nsBuiltinDecoderReader* aReader);
|
|
|
|
~nsBuiltinDecoderStateMachine();
|
2010-04-02 07:03:07 +04:00
|
|
|
|
2010-04-27 12:53:44 +04:00
|
|
|
// nsDecoderStateMachine interface
|
2010-09-21 04:49:50 +04:00
|
|
|
virtual nsresult Init(nsDecoderStateMachine* aCloneDonor);
|
2010-05-06 06:31:02 +04:00
|
|
|
State GetState()
|
|
|
|
{
|
2011-04-29 23:21:57 +04:00
|
|
|
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
2010-05-06 06:31:02 +04:00
|
|
|
return mState;
|
|
|
|
}
|
2011-01-17 06:03:00 +03:00
|
|
|
virtual void SetVolume(double aVolume);
|
2010-04-27 12:53:44 +04:00
|
|
|
virtual void Shutdown();
|
|
|
|
virtual PRInt64 GetDuration();
|
|
|
|
virtual void SetDuration(PRInt64 aDuration);
|
2011-05-09 01:10:28 +04:00
|
|
|
void SetEndTime(PRInt64 aEndTime);
|
2011-03-24 01:28:57 +03:00
|
|
|
virtual PRBool OnDecodeThread() const {
|
2010-04-27 12:53:44 +04:00
|
|
|
return IsCurrentThread(mDecodeThread);
|
|
|
|
}
|
2010-04-02 07:03:07 +04:00
|
|
|
|
2010-04-27 12:53:44 +04:00
|
|
|
virtual nsHTMLMediaElement::NextFrameStatus GetNextFrameStatus();
|
2011-03-24 01:28:57 +03:00
|
|
|
virtual void Play();
|
2011-01-17 06:03:00 +03:00
|
|
|
virtual void Seek(double aTime);
|
2011-03-24 01:28:57 +03:00
|
|
|
virtual double GetCurrentTime() const;
|
2010-04-27 12:53:44 +04:00
|
|
|
virtual void ClearPositionChangeFlag();
|
|
|
|
virtual void SetSeekable(PRBool aSeekable);
|
2010-05-06 06:31:02 +04:00
|
|
|
virtual void UpdatePlaybackPosition(PRInt64 aTime);
|
2010-07-23 02:48:32 +04:00
|
|
|
virtual void StartBuffering();
|
2010-05-06 06:31:02 +04:00
|
|
|
|
|
|
|
|
|
|
|
// Load metadata Called on the state machine thread. The decoder monitor must be held with
|
|
|
|
// exactly one lock count.
|
|
|
|
virtual void LoadMetadata();
|
2010-04-02 07:03:07 +04:00
|
|
|
|
|
|
|
// State machine thread run function. Polls the state, sends frames to be
|
|
|
|
// displayed at appropriate times, and generally manages the decode.
|
|
|
|
NS_IMETHOD Run();
|
|
|
|
|
|
|
|
// This is called on the state machine thread and audio thread.
|
|
|
|
// The decoder monitor must be obtained before calling this.
|
|
|
|
PRBool HasAudio() const {
|
2011-04-29 23:21:57 +04:00
|
|
|
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
2011-03-24 06:53:03 +03:00
|
|
|
return mInfo.mHasAudio;
|
2010-04-02 07:03:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// This is called on the state machine thread and audio thread.
|
|
|
|
// The decoder monitor must be obtained before calling this.
|
|
|
|
PRBool HasVideo() const {
|
2011-04-29 23:21:57 +04:00
|
|
|
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
2011-03-24 06:53:03 +03:00
|
|
|
return mInfo.mHasVideo;
|
2010-04-02 07:03:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Should be called by main thread.
|
2010-05-13 04:59:42 +04:00
|
|
|
PRBool HaveNextFrameData() const;
|
2010-04-02 07:03:07 +04:00
|
|
|
|
|
|
|
// Must be called with the decode monitor held.
|
|
|
|
PRBool IsBuffering() const {
|
2011-04-29 23:21:57 +04:00
|
|
|
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
2010-04-02 07:03:07 +04:00
|
|
|
|
2010-05-06 06:31:02 +04:00
|
|
|
return mState == nsBuiltinDecoderStateMachine::DECODER_STATE_BUFFERING;
|
2010-04-02 07:03:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Must be called with the decode monitor held.
|
|
|
|
PRBool IsSeeking() const {
|
2011-04-29 23:21:57 +04:00
|
|
|
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
2010-04-02 07:03:07 +04:00
|
|
|
|
2010-05-06 06:31:02 +04:00
|
|
|
return mState == nsBuiltinDecoderStateMachine::DECODER_STATE_SEEKING;
|
2010-04-02 07:03:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Functions used by assertions to ensure we're calling things
|
|
|
|
// on the appropriate threads.
|
2010-04-27 12:53:44 +04:00
|
|
|
PRBool OnAudioThread() {
|
|
|
|
return IsCurrentThread(mAudioThread);
|
2010-04-02 07:03:07 +04:00
|
|
|
}
|
|
|
|
|
2010-04-27 12:53:44 +04:00
|
|
|
PRBool OnStateMachineThread() {
|
|
|
|
return mDecoder->OnStateMachineThread();
|
2010-04-02 07:03:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Decode loop, called on the decode thread.
|
|
|
|
void DecodeLoop();
|
|
|
|
|
|
|
|
// The decoder object that created this state machine. The decoder
|
|
|
|
// always outlives us since it controls our lifetime. This is accessed
|
|
|
|
// read only on the AV, state machine, audio and main thread.
|
2010-04-27 12:53:44 +04:00
|
|
|
nsBuiltinDecoder* mDecoder;
|
2010-04-02 07:03:07 +04:00
|
|
|
|
|
|
|
// The decoder monitor must be obtained before modifying this state.
|
|
|
|
// NotifyAll on the monitor must be called when the state is changed by
|
|
|
|
// the main thread so the decoder thread can wake up.
|
|
|
|
// Accessed on state machine, audio, main, and AV thread.
|
|
|
|
State mState;
|
|
|
|
|
2011-03-24 01:28:58 +03:00
|
|
|
nsresult GetBuffered(nsTimeRanges* aBuffered);
|
2010-08-05 11:40:35 +04:00
|
|
|
|
2010-09-13 12:45:50 +04:00
|
|
|
void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) {
|
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
|
|
|
mReader->NotifyDataArrived(aBuffer, aLength, aOffset);
|
|
|
|
}
|
|
|
|
|
2010-10-07 02:58:36 +04:00
|
|
|
PRInt64 GetEndMediaTime() const {
|
2011-04-29 23:21:57 +04:00
|
|
|
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
2010-10-07 02:58:36 +04:00
|
|
|
return mEndTime;
|
|
|
|
}
|
|
|
|
|
2011-05-09 01:10:28 +04:00
|
|
|
PRBool GetSeekable() {
|
|
|
|
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
|
|
|
return mSeekable;
|
|
|
|
}
|
|
|
|
|
2011-04-12 01:15:45 +04:00
|
|
|
// Sets the current frame buffer length for the MozAudioAvailable event.
|
|
|
|
// Accessed on the main and state machine threads.
|
|
|
|
virtual void SetFrameBufferLength(PRUint32 aLength);
|
|
|
|
|
2010-05-06 06:31:02 +04:00
|
|
|
protected:
|
2010-04-02 07:03:07 +04:00
|
|
|
|
2011-04-14 02:12:23 +04:00
|
|
|
// Returns PR_TRUE if we've got less than aAudioUsecs microseconds of decoded
|
|
|
|
// and playable data. The decoder monitor must be held.
|
|
|
|
PRBool HasLowDecodedData(PRInt64 aAudioUsecs) const;
|
2011-03-24 01:28:57 +03:00
|
|
|
|
2011-03-24 01:28:57 +03:00
|
|
|
// Returns PR_TRUE if we're running low on data which is not yet decoded.
|
|
|
|
// The decoder monitor must be held.
|
|
|
|
PRBool HasLowUndecodedData() const;
|
|
|
|
|
2011-04-14 02:12:23 +04:00
|
|
|
// Returns the number of microseconds of undecoded data available for
|
2011-03-24 01:28:57 +03:00
|
|
|
// decoding. The decoder monitor must be held.
|
|
|
|
PRInt64 GetUndecodedData() const;
|
2010-11-28 23:06:38 +03:00
|
|
|
|
2011-04-14 02:12:23 +04:00
|
|
|
// Returns the number of unplayed usecs of audio we've got decoded and/or
|
2010-09-15 03:24:47 +04:00
|
|
|
// pushed to the hardware waiting to play. This is how much audio we can
|
2011-03-24 01:28:57 +03:00
|
|
|
// play without having to run the audio decoder. The decoder monitor
|
|
|
|
// must be held.
|
2011-04-14 02:12:23 +04:00
|
|
|
PRInt64 AudioDecodedUsecs() const;
|
2010-09-15 03:24:47 +04:00
|
|
|
|
2010-05-13 04:59:42 +04:00
|
|
|
// Returns PR_TRUE when there's decoded audio waiting to play.
|
|
|
|
// The decoder monitor must be held.
|
|
|
|
PRBool HasFutureAudio() const;
|
|
|
|
|
2011-03-24 01:28:57 +03:00
|
|
|
// Returns PR_TRUE if we recently exited "quick buffering" mode.
|
|
|
|
PRBool JustExitedQuickBuffering();
|
|
|
|
|
2011-04-29 23:21:57 +04:00
|
|
|
// Waits on the decoder ReentrantMonitor for aUsecs microseconds. If the decoder
|
2011-04-14 02:12:23 +04:00
|
|
|
// monitor is awoken by a Notify() call, we'll continue waiting, unless
|
|
|
|
// we've moved into shutdown state. This enables us to ensure that we
|
2011-05-12 06:02:34 +04:00
|
|
|
// wait for a specified time, and that the myriad of Notify()s we do on
|
|
|
|
// the decoder monitor don't cause the audio thread to be starved. aUsecs
|
|
|
|
// values of less than 1 millisecond are rounded up to 1 millisecond
|
|
|
|
// (see bug 651023). The decoder monitor must be held.
|
2011-04-14 02:12:23 +04:00
|
|
|
void Wait(PRInt64 aUsecs);
|
2010-04-02 07:03:07 +04:00
|
|
|
|
|
|
|
// Dispatches an asynchronous event to update the media element's ready state.
|
|
|
|
void UpdateReadyState();
|
|
|
|
|
|
|
|
// Resets playback timing data. Called when we seek, on the state machine
|
|
|
|
// thread.
|
|
|
|
void ResetPlayback();
|
|
|
|
|
|
|
|
// Returns the audio clock, if we have audio, or -1 if we don't.
|
|
|
|
// Called on the state machine thread.
|
|
|
|
PRInt64 GetAudioClock();
|
|
|
|
|
|
|
|
// Returns the presentation time of the first sample or frame in the media.
|
|
|
|
// If the media has video, it returns the first video frame. The decoder
|
|
|
|
// monitor must be held with exactly one lock count. Called on the state
|
|
|
|
// machine thread.
|
|
|
|
VideoData* FindStartTime();
|
|
|
|
|
2011-02-01 05:57:13 +03:00
|
|
|
// Update only the state machine's current playback position (and duration,
|
|
|
|
// if unknown). Does not update the playback position on the decoder or
|
|
|
|
// media element -- use UpdatePlaybackPosition for that. Called on the state
|
|
|
|
// machine thread, caller must hold the decoder lock.
|
|
|
|
void UpdatePlaybackPositionInternal(PRInt64 aTime);
|
|
|
|
|
2010-04-02 07:03:07 +04:00
|
|
|
// Performs YCbCr to RGB conversion, and pushes the image down the
|
2011-03-24 06:53:03 +03:00
|
|
|
// rendering pipeline. Called on the state machine thread. The decoder
|
|
|
|
// monitor must not be held when calling this.
|
2011-06-24 02:08:54 +04:00
|
|
|
void RenderVideoFrame(VideoData* aData, TimeStamp aTarget);
|
2011-03-24 06:53:03 +03:00
|
|
|
|
2010-04-02 07:03:07 +04:00
|
|
|
// If we have video, display a video frame if it's time for display has
|
|
|
|
// arrived, otherwise sleep until it's time for the next sample. Update
|
|
|
|
// the current frame time as appropriate, and trigger ready state update.
|
|
|
|
// The decoder monitor must be held with exactly one lock count. Called
|
|
|
|
// on the state machine thread.
|
|
|
|
void AdvanceFrame();
|
|
|
|
|
2010-08-13 06:28:15 +04:00
|
|
|
// Pushes up to aSamples samples of silence onto the audio hardware. Returns
|
|
|
|
// the number of samples acutally pushed to the hardware. This pushes up to
|
|
|
|
// 32KB worth of samples to the hardware before returning, so must be called
|
|
|
|
// in a loop to ensure that the desired number of samples are pushed to the
|
|
|
|
// hardware. This ensures that the playback position advances smoothly, and
|
|
|
|
// guarantees that we don't try to allocate an impossibly large chunk of
|
|
|
|
// memory in order to play back silence. Called on the audio thread.
|
2011-04-14 02:12:23 +04:00
|
|
|
PRUint32 PlaySilence(PRUint32 aSamples,
|
|
|
|
PRUint32 aChannels,
|
2010-08-25 17:10:00 +04:00
|
|
|
PRUint64 aSampleOffset);
|
2010-08-13 06:28:15 +04:00
|
|
|
|
|
|
|
// Pops an audio chunk from the front of the audio queue, and pushes its
|
2010-08-25 17:10:00 +04:00
|
|
|
// sound data to the audio hardware. MozAudioAvailable sample data is also
|
|
|
|
// queued here. Called on the audio thread.
|
|
|
|
PRUint32 PlayFromAudioQueue(PRUint64 aSampleOffset, PRUint32 aChannels);
|
2010-08-13 06:28:15 +04:00
|
|
|
|
2011-07-12 07:39:10 +04:00
|
|
|
// Stops the decode thread. The decoder monitor must be held with exactly
|
2010-04-02 07:03:07 +04:00
|
|
|
// one lock count. Called on the state machine thread.
|
2011-07-12 07:39:10 +04:00
|
|
|
void StopDecodeThread();
|
2010-04-02 07:03:07 +04:00
|
|
|
|
2011-07-12 07:39:10 +04:00
|
|
|
// Stops the audio thread. The decoder monitor must be held with exactly
|
2010-04-02 07:03:07 +04:00
|
|
|
// one lock count. Called on the state machine thread.
|
2011-07-12 07:39:10 +04:00
|
|
|
void StopAudioThread();
|
|
|
|
|
|
|
|
// Starts the decode thread. The decoder monitor must be held with exactly
|
|
|
|
// one lock count. Called on the state machine thread.
|
|
|
|
nsresult StartDecodeThread();
|
|
|
|
|
|
|
|
// Starts the audio thread. The decoder monitor must be held with exactly
|
|
|
|
// one lock count. Called on the state machine thread.
|
|
|
|
nsresult StartAudioThread();
|
2010-04-02 07:03:07 +04:00
|
|
|
|
|
|
|
// The main loop for the audio thread. Sent to the thread as
|
2010-04-21 03:21:35 +04:00
|
|
|
// an nsRunnableMethod. This continually does blocking writes to
|
2010-04-02 07:03:07 +04:00
|
|
|
// to audio stream to play audio data.
|
|
|
|
void AudioLoop();
|
|
|
|
|
|
|
|
// Stop or pause playback of media. This has two modes, denoted by
|
|
|
|
// aMode being either AUDIO_PAUSE or AUDIO_SHUTDOWN.
|
|
|
|
//
|
|
|
|
// AUDIO_PAUSE: Suspends the audio stream to be resumed later.
|
|
|
|
// This does not close the OS based audio stream
|
|
|
|
//
|
|
|
|
// AUDIO_SHUTDOWN: Closes and destroys the audio stream and
|
|
|
|
// releases any OS resources.
|
|
|
|
//
|
|
|
|
// The decoder monitor must be held with exactly one lock count. Called
|
|
|
|
// on the state machine thread.
|
|
|
|
enum eStopMode {AUDIO_PAUSE, AUDIO_SHUTDOWN};
|
|
|
|
void StopPlayback(eStopMode aMode);
|
|
|
|
|
|
|
|
// Resume playback of media. Must be called with the decode monitor held.
|
|
|
|
// This resumes a paused audio stream. The decoder monitor must be held with
|
|
|
|
// exactly one lock count. Called on the state machine thread.
|
|
|
|
void StartPlayback();
|
|
|
|
|
2011-03-24 01:28:57 +03:00
|
|
|
// Moves the decoder into decoding state. Called on the state machine
|
|
|
|
// thread. The decoder monitor must be held.
|
|
|
|
void StartDecoding();
|
|
|
|
|
2010-04-02 07:03:07 +04:00
|
|
|
// Returns PR_TRUE if we're currently playing. The decoder monitor must
|
|
|
|
// be held.
|
|
|
|
PRBool IsPlaying();
|
|
|
|
|
2010-09-15 03:24:47 +04:00
|
|
|
// Returns the "media time". This is the absolute time which the media
|
|
|
|
// playback has reached. i.e. this returns values in the range
|
|
|
|
// [mStartTime, mEndTime], and mStartTime will not be 0 if the media does
|
|
|
|
// not start at 0. Note this is different to the value returned
|
|
|
|
// by GetCurrentTime(), which is in the range [0,duration].
|
|
|
|
PRInt64 GetMediaTime() const {
|
2011-04-29 23:21:57 +04:00
|
|
|
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
2010-09-15 03:24:47 +04:00
|
|
|
return mStartTime + mCurrentFrameTime;
|
|
|
|
}
|
|
|
|
|
2011-04-14 02:12:23 +04:00
|
|
|
// Returns an upper bound on the number of microseconds of audio that is
|
|
|
|
// decoded and playable. This is the sum of the number of usecs of audio which
|
|
|
|
// is decoded and in the reader's audio queue, and the usecs of unplayed audio
|
2011-01-13 04:06:15 +03:00
|
|
|
// which has been pushed to the audio hardware for playback. Note that after
|
|
|
|
// calling this, the audio hardware may play some of the audio pushed to
|
|
|
|
// hardware, so this can only be used as a upper bound. The decoder monitor
|
|
|
|
// must be held when calling this. Called on the decoder thread.
|
|
|
|
PRInt64 GetDecodedAudioDuration();
|
|
|
|
|
2011-04-29 23:21:57 +04:00
|
|
|
// ReentrantMonitor on mAudioStream. This monitor must be held in
|
|
|
|
// order to delete or use the audio stream. This stops us destroying
|
|
|
|
// the audio stream while it's being used on another thread
|
|
|
|
// (typically when it's being written to on the audio thread).
|
|
|
|
ReentrantMonitor mAudioReentrantMonitor;
|
2010-04-02 07:03:07 +04:00
|
|
|
|
|
|
|
// The size of the decoded YCbCr frame.
|
|
|
|
// Accessed on state machine thread.
|
|
|
|
PRUint32 mCbCrSize;
|
|
|
|
|
|
|
|
// Accessed on state machine thread.
|
|
|
|
nsAutoArrayPtr<unsigned char> mCbCrBuffer;
|
|
|
|
|
|
|
|
// Thread for pushing audio onto the audio hardware.
|
|
|
|
// The "audio push thread".
|
|
|
|
nsCOMPtr<nsIThread> mAudioThread;
|
|
|
|
|
|
|
|
// Thread for decoding video in background. The "decode thread".
|
|
|
|
nsCOMPtr<nsIThread> mDecodeThread;
|
|
|
|
|
2011-02-18 05:30:33 +03:00
|
|
|
// The time that playback started from the system clock. This is used for
|
|
|
|
// timing the presentation of video frames when there's no audio.
|
2010-04-02 07:03:07 +04:00
|
|
|
// Accessed only via the state machine thread.
|
|
|
|
TimeStamp mPlayStartTime;
|
|
|
|
|
|
|
|
// The amount of time we've spent playing already the media. The current
|
2011-02-18 05:30:33 +03:00
|
|
|
// playback position is therefore |Now() - mPlayStartTime +
|
|
|
|
// mPlayDuration|, which must be adjusted by mStartTime if used with media
|
|
|
|
// timestamps. Accessed only via the state machine thread.
|
2011-04-14 02:12:23 +04:00
|
|
|
PRInt64 mPlayDuration;
|
2010-04-02 07:03:07 +04:00
|
|
|
|
|
|
|
// Time that buffering started. Used for buffering timeout and only
|
2011-01-18 03:53:18 +03:00
|
|
|
// accessed on the state machine thread. This is null while we're not
|
|
|
|
// buffering.
|
2010-04-02 07:03:07 +04:00
|
|
|
TimeStamp mBufferingStart;
|
|
|
|
|
2011-04-14 02:12:23 +04:00
|
|
|
// Start time of the media, in microseconds. This is the presentation
|
2010-04-02 07:03:07 +04:00
|
|
|
// time of the first sample decoded from the media, and is used to calculate
|
|
|
|
// duration and as a bounds for seeking. Accessed on state machine and
|
|
|
|
// main thread. Access controlled by decoder monitor.
|
|
|
|
PRInt64 mStartTime;
|
|
|
|
|
2011-04-14 02:12:23 +04:00
|
|
|
// Time of the last page in the media, in microseconds. This is the
|
2010-04-02 07:03:07 +04:00
|
|
|
// end time of the last sample in the media. Accessed on state
|
|
|
|
// machine and main thread. Access controlled by decoder monitor.
|
|
|
|
PRInt64 mEndTime;
|
|
|
|
|
2011-04-14 02:12:23 +04:00
|
|
|
// Position to seek to in microseconds when the seek state transition occurs.
|
2010-04-02 07:03:07 +04:00
|
|
|
// The decoder monitor lock must be obtained before reading or writing
|
|
|
|
// this value. Accessed on main and state machine thread.
|
|
|
|
PRInt64 mSeekTime;
|
|
|
|
|
2011-04-29 23:21:57 +04:00
|
|
|
// The audio stream resource. Used on the state machine, audio, and
|
|
|
|
// main threads. You must hold the mAudioReentrantMonitor, and must
|
|
|
|
// NOT hold the decoder monitor when using the audio stream!
|
2010-11-17 07:14:19 +03:00
|
|
|
nsRefPtr<nsAudioStream> mAudioStream;
|
2010-04-02 07:03:07 +04:00
|
|
|
|
2010-05-06 06:31:02 +04:00
|
|
|
// The reader, don't call its methods with the decoder monitor held.
|
|
|
|
// This is created in the play state machine's constructor, and destroyed
|
|
|
|
// in the play state machine's destructor.
|
|
|
|
nsAutoPtr<nsBuiltinDecoderReader> mReader;
|
|
|
|
|
2011-04-14 02:12:23 +04:00
|
|
|
// The time of the current frame in microseconds. This is referenced from
|
2010-04-02 07:03:07 +04:00
|
|
|
// 0 which is the initial playback position. Set by the state machine
|
|
|
|
// thread, and read-only from the main thread to get the current
|
|
|
|
// time value. Synchronised via decoder monitor.
|
|
|
|
PRInt64 mCurrentFrameTime;
|
|
|
|
|
2011-04-14 02:12:23 +04:00
|
|
|
// The presentation time of the first audio sample that was played in
|
|
|
|
// microseconds. We can add this to the audio stream position to determine
|
|
|
|
// the current audio time. Accessed on audio and state machine thread.
|
|
|
|
// Synchronized by decoder monitor.
|
2010-04-02 07:03:07 +04:00
|
|
|
PRInt64 mAudioStartTime;
|
|
|
|
|
|
|
|
// The end time of the last audio sample that's been pushed onto the audio
|
2011-04-14 02:12:23 +04:00
|
|
|
// hardware in microseconds. This will approximately be the end time of the
|
|
|
|
// audio stream, unless another sample is pushed to the hardware.
|
2010-04-02 07:03:07 +04:00
|
|
|
PRInt64 mAudioEndTime;
|
|
|
|
|
2011-04-14 02:12:23 +04:00
|
|
|
// The presentation end time of the last video frame which has been displayed
|
|
|
|
// in microseconds. Accessed from the state machine thread.
|
2010-05-31 08:02:00 +04:00
|
|
|
PRInt64 mVideoFrameEndTime;
|
2010-04-02 07:03:07 +04:00
|
|
|
|
|
|
|
// Volume of playback. 0.0 = muted. 1.0 = full volume. Read/Written
|
|
|
|
// from the state machine and main threads. Synchronised via decoder
|
|
|
|
// monitor.
|
2011-01-17 06:03:00 +03:00
|
|
|
double mVolume;
|
2010-04-02 07:03:07 +04:00
|
|
|
|
2011-03-24 01:28:57 +03:00
|
|
|
// Time at which we started decoding. Synchronised via decoder monitor.
|
|
|
|
TimeStamp mDecodeStartTime;
|
|
|
|
|
2010-04-02 07:03:07 +04:00
|
|
|
// PR_TRUE if the media resource can be seeked. Accessed from the state
|
|
|
|
// machine and main threads. Synchronised via decoder monitor.
|
|
|
|
PRPackedBool mSeekable;
|
|
|
|
|
|
|
|
// PR_TRUE if an event to notify about a change in the playback
|
|
|
|
// position has been queued, but not yet run. It is set to PR_FALSE when
|
|
|
|
// the event is run. This allows coalescing of these events as they can be
|
|
|
|
// produced many times per second. Synchronised via decoder monitor.
|
|
|
|
// Accessed on main and state machine threads.
|
|
|
|
PRPackedBool mPositionChangeQueued;
|
|
|
|
|
|
|
|
// PR_TRUE if the audio playback thread has finished. It is finished
|
|
|
|
// when either all the audio samples in the Vorbis bitstream have completed
|
|
|
|
// playing, or we've moved into shutdown state, and the threads are to be
|
|
|
|
// destroyed. Written by the audio playback thread and read and written by
|
|
|
|
// the state machine thread. Synchronised via decoder monitor.
|
|
|
|
PRPackedBool mAudioCompleted;
|
|
|
|
|
2010-10-07 02:58:36 +04:00
|
|
|
// PR_TRUE if mDuration has a value obtained from an HTTP header, or from
|
|
|
|
// the media index/metadata. Accessed on the state machine thread.
|
|
|
|
PRPackedBool mGotDurationFromMetaData;
|
2010-04-02 07:03:07 +04:00
|
|
|
|
2011-07-12 07:39:10 +04:00
|
|
|
// PR_FALSE while decode thread should be running. Accessed state machine
|
|
|
|
// and decode threads. Syncrhonised by decoder monitor.
|
|
|
|
PRPackedBool mStopDecodeThread;
|
|
|
|
|
|
|
|
// PR_FALSE while audio thread should be running. Accessed state machine
|
|
|
|
// and audio threads. Syncrhonised by decoder monitor.
|
|
|
|
PRPackedBool mStopAudioThread;
|
2010-04-02 07:03:07 +04:00
|
|
|
|
2011-03-24 01:28:57 +03:00
|
|
|
// If this is PR_TRUE while we're in buffering mode, we can exit early,
|
|
|
|
// as it's likely we may be able to playback. This happens when we enter
|
|
|
|
// buffering mode soon after the decode starts, because the decode-ahead
|
|
|
|
// ran fast enough to exhaust all data while the download is starting up.
|
|
|
|
// Synchronised via decoder monitor.
|
|
|
|
PRPackedBool mQuickBuffering;
|
|
|
|
|
2010-08-25 17:10:00 +04:00
|
|
|
private:
|
|
|
|
// Manager for queuing and dispatching MozAudioAvailable events. The
|
|
|
|
// event manager is accessed from the state machine and audio threads,
|
|
|
|
// and takes care of synchronizing access to its internal queue.
|
|
|
|
nsAudioAvailableEventManager mEventManager;
|
2011-03-24 06:53:03 +03:00
|
|
|
|
|
|
|
// Stores presentation info required for playback. The decoder monitor
|
|
|
|
// must be held when accessing this.
|
|
|
|
nsVideoInfo mInfo;
|
2010-08-25 17:10:00 +04:00
|
|
|
};
|
2010-08-18 21:04:31 +04:00
|
|
|
|
2010-04-02 07:03:07 +04:00
|
|
|
#endif
|