mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 592833 - Backout due to suspected android crashtest permaorange. r=philor
This commit is contained in:
parent
560834288e
commit
a24dd67388
@ -1987,11 +1987,11 @@ void nsHTMLMediaElement::NetworkError()
|
||||
|
||||
void nsHTMLMediaElement::DecodeError()
|
||||
{
|
||||
if (mDecoder) {
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = nsnull;
|
||||
}
|
||||
if (mIsLoadingFromSourceChildren) {
|
||||
if (mDecoder) {
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = nsnull;
|
||||
}
|
||||
mError = nsnull;
|
||||
if (mSourceLoadCandidate) {
|
||||
DispatchAsyncSourceError(mSourceLoadCandidate);
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include "nsTArray.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "nsBuiltinDecoder.h"
|
||||
#include "nsBuiltinDecoderStateMachine.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -123,6 +122,20 @@ PRBool nsBuiltinDecoder::Init(nsHTMLMediaElement* aElement)
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void nsBuiltinDecoder::Stop()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread");
|
||||
|
||||
// The decode thread must die before the state machine can die.
|
||||
// The state machine must die before the reader.
|
||||
// The state machine must die before the decoder.
|
||||
if (mStateMachineThread)
|
||||
mStateMachineThread->Shutdown();
|
||||
|
||||
mStateMachineThread = nsnull;
|
||||
mDecoderStateMachine = nsnull;
|
||||
}
|
||||
|
||||
void nsBuiltinDecoder::Shutdown()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
@ -148,6 +161,17 @@ void nsBuiltinDecoder::Shutdown()
|
||||
ChangeState(PLAY_STATE_SHUTDOWN);
|
||||
nsMediaDecoder::Shutdown();
|
||||
|
||||
// We can't destroy mDecoderStateMachine until mStateMachineThread is shut down.
|
||||
// It's unsafe to Shutdown() the decode thread here, as
|
||||
// nsIThread::Shutdown() may run events, such as JS event handlers,
|
||||
// and we could be running at an unsafe time such as during element
|
||||
// destruction.
|
||||
// So we destroy the decoder on the main thread in an asynchronous event.
|
||||
// See bug 468721.
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &nsBuiltinDecoder::Stop);
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
|
||||
nsContentUtils::UnregisterShutdownObserver(this);
|
||||
}
|
||||
|
||||
@ -159,8 +183,8 @@ nsBuiltinDecoder::~nsBuiltinDecoder()
|
||||
}
|
||||
|
||||
nsresult nsBuiltinDecoder::Load(nsMediaStream* aStream,
|
||||
nsIStreamListener** aStreamListener,
|
||||
nsMediaDecoder* aCloneDonor)
|
||||
nsIStreamListener** aStreamListener,
|
||||
nsMediaDecoder* aCloneDonor)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
if (aStreamListener) {
|
||||
@ -205,7 +229,7 @@ nsresult nsBuiltinDecoder::Load(nsMediaStream* aStream,
|
||||
|
||||
ChangeState(PLAY_STATE_LOADING);
|
||||
|
||||
return ScheduleStateMachineThread();
|
||||
return StartStateMachineThread();
|
||||
}
|
||||
|
||||
nsresult nsBuiltinDecoder::RequestFrameBufferLength(PRUint32 aLength)
|
||||
@ -220,25 +244,23 @@ nsresult nsBuiltinDecoder::RequestFrameBufferLength(PRUint32 aLength)
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult nsBuiltinDecoder::ScheduleStateMachineThread()
|
||||
nsresult nsBuiltinDecoder::StartStateMachineThread()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
NS_ASSERTION(mDecoderStateMachine,
|
||||
"Must have state machine to start state machine thread");
|
||||
|
||||
if (mShuttingDown)
|
||||
if (mStateMachineThread) {
|
||||
return NS_OK;
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
nsBuiltinDecoderStateMachine* m =
|
||||
static_cast<nsBuiltinDecoderStateMachine*>(mDecoderStateMachine.get());
|
||||
return m->ScheduleStateMachine();
|
||||
}
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(mStateMachineThread));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return mStateMachineThread->Dispatch(mDecoderStateMachine, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult nsBuiltinDecoder::Play()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
nsresult res = ScheduleStateMachineThread();
|
||||
nsresult res = StartStateMachineThread();
|
||||
NS_ENSURE_SUCCESS(res,res);
|
||||
if (mPlayState == PLAY_STATE_SEEKING) {
|
||||
mNextState = PLAY_STATE_PLAYING;
|
||||
@ -276,7 +298,7 @@ nsresult nsBuiltinDecoder::Seek(double aTime)
|
||||
ChangeState(PLAY_STATE_SEEKING);
|
||||
}
|
||||
|
||||
return ScheduleStateMachineThread();
|
||||
return StartStateMachineThread();
|
||||
}
|
||||
|
||||
nsresult nsBuiltinDecoder::PlaybackRateChanged()
|
||||
@ -510,7 +532,7 @@ nsBuiltinDecoder::GetStatistics()
|
||||
double nsBuiltinDecoder::ComputePlaybackRate(PRPackedBool* aReliable)
|
||||
{
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
NS_ASSERTION(NS_IsMainThread() || OnStateMachineThread(),
|
||||
NS_ASSERTION(NS_IsMainThread() || IsCurrentThread(mStateMachineThread),
|
||||
"Should be on main or state machine thread.");
|
||||
|
||||
PRInt64 length = mStream ? mStream->GetLength() : -1;
|
||||
@ -523,7 +545,7 @@ double nsBuiltinDecoder::ComputePlaybackRate(PRPackedBool* aReliable)
|
||||
|
||||
void nsBuiltinDecoder::UpdatePlaybackRate()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread() || OnStateMachineThread(),
|
||||
NS_ASSERTION(NS_IsMainThread() || IsCurrentThread(mStateMachineThread),
|
||||
"Should be on main or state machine thread.");
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
if (!mStream)
|
||||
@ -849,9 +871,7 @@ void nsBuiltinDecoder::Resume(PRBool aForceBuffering)
|
||||
|
||||
void nsBuiltinDecoder::StopProgressUpdates()
|
||||
{
|
||||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine or decode thread.");
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
NS_ASSERTION(IsCurrentThread(mStateMachineThread), "Should be on state machine thread.");
|
||||
mIgnoreProgressData = PR_TRUE;
|
||||
if (mStream) {
|
||||
mStream->SetReadMode(nsMediaCacheStream::MODE_METADATA);
|
||||
@ -860,9 +880,7 @@ void nsBuiltinDecoder::StopProgressUpdates()
|
||||
|
||||
void nsBuiltinDecoder::StartProgressUpdates()
|
||||
{
|
||||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine or decode thread.");
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
NS_ASSERTION(IsCurrentThread(mStateMachineThread), "Should be on state machine thread.");
|
||||
mIgnoreProgressData = PR_FALSE;
|
||||
if (mStream) {
|
||||
mStream->SetReadMode(nsMediaCacheStream::MODE_PLAYBACK);
|
||||
@ -883,7 +901,3 @@ void nsBuiltinDecoder::UpdatePlaybackOffset(PRInt64 aOffset)
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mPlaybackPosition = NS_MAX(aOffset, mPlaybackPosition);
|
||||
}
|
||||
|
||||
PRBool nsBuiltinDecoder::OnStateMachineThread() const {
|
||||
return IsCurrentThread(nsBuiltinDecoderStateMachine::GetStateMachineThread());
|
||||
}
|
||||
|
@ -37,28 +37,24 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/*
|
||||
Each video element based on nsBuiltinDecoder has a state machine to manage
|
||||
its play state and keep the current frame up to date. All state machines
|
||||
share time in a single shared thread. Each decoder also has one thread
|
||||
dedicated to decoding audio and video data. This thread is shutdown when
|
||||
playback is paused. Each decoder also has a thread to push decoded audio
|
||||
to the hardware. This thread is not created until playback starts, but
|
||||
currently is not destroyed when paused, only when playback ends.
|
||||
Each video element based on nsBuiltinDecoder has at least one thread
|
||||
dedicated to decoding video.
|
||||
|
||||
The decoder owns the resources for downloading the media file, and the
|
||||
high level state. It holds an owning reference to the state machine
|
||||
(a subclass of nsDecoderStateMachine; nsBuiltinDecoderStateMachine) that
|
||||
owns all the resources related to decoding data, and manages the low level
|
||||
decoding operations and A/V sync.
|
||||
This thread (called the state machine thread owns the resources for
|
||||
downloading and reading the media file. nsDecoderStateMachine is the
|
||||
class that needs to be implemented and it gets run on the state
|
||||
machine thread.
|
||||
|
||||
Each state machine runs on the shared state machine thread. Every time some
|
||||
action is required for a state machine, it is scheduled to run on the shared
|
||||
the state machine thread. The state machine runs one "cycle" on the state
|
||||
machine thread, and then returns. If necessary, it will schedule itself to
|
||||
run again in future. While running this cycle, it must not block the
|
||||
thread, as other state machines' events may need to run. State shared
|
||||
between a state machine's threads is synchronised via the monitor owned
|
||||
by its nsBuiltinDecoder object.
|
||||
The state machine thread has one event that is dispatched to it (the
|
||||
implementation of nsDecoderStateMachine) and that event runs for the
|
||||
lifetime of the playback of the resource. State shared between threads
|
||||
is synchronised with the main thread via a monitor held by the
|
||||
nsBuiltinDecoder object.
|
||||
|
||||
The state machine thread event consist of a Run method which is an
|
||||
infinite loop that performs the decoding operation and checks the
|
||||
state that the state machine is in and processes operations on that
|
||||
state.
|
||||
|
||||
The Main thread controls the decode state machine by setting the value
|
||||
of a mPlayState variable and notifying on the monitor based on the
|
||||
@ -89,37 +85,25 @@ SHUTDOWN
|
||||
State transition occurs when the Media Element calls the Play, Seek,
|
||||
etc methods on the nsBuiltinDecoder object. When the transition
|
||||
occurs nsBuiltinDecoder then calls the methods on the decoder state
|
||||
machine object to cause it to behave as required by the play state.
|
||||
State transitions will likely schedule the state machine to run to
|
||||
affect the change.
|
||||
machine object to cause it to behave appropriate to the play state.
|
||||
|
||||
An implementation of the nsDecoderStateMachine class is the event
|
||||
that gets dispatched to the state machine thread. Each time the event is run,
|
||||
the state machine must cycle the state machine once, and then return.
|
||||
|
||||
The state machine has the following states:
|
||||
that gets dispatched to the state machine thread. It has the following states:
|
||||
|
||||
DECODING_METADATA
|
||||
The media headers are being loaded, and things like framerate, etc are
|
||||
being determined, and the first frame of audio/video data is being decoded.
|
||||
DECODING
|
||||
The decode has started. If the PlayState is PLAYING, the decode thread
|
||||
should be alive and decoding video and audio frame, the audio thread
|
||||
should be playing audio, and the state machine should run periodically
|
||||
to update the video frames being displayed.
|
||||
The decode and audio threads are started and video frames displayed at
|
||||
the required time.
|
||||
SEEKING
|
||||
A seek operation is in progress. The decode thread should be seeking.
|
||||
A seek operation is in progress.
|
||||
BUFFERING
|
||||
Decoding is paused while data is buffered for smooth playback. If playback
|
||||
is paused (PlayState transitions to PAUSED) we'll destory the decode thread.
|
||||
Decoding is paused while data is buffered for smooth playback.
|
||||
COMPLETED
|
||||
The resource has completed decoding, but possibly not finished playback.
|
||||
The decode thread will be destroyed. Once playback finished, the audio
|
||||
thread will also be destroyed.
|
||||
The resource has completed decoding, but not finished playback.
|
||||
SHUTDOWN
|
||||
The decoder object and its state machine are about to be destroyed.
|
||||
Once the last state machine has been destroyed, the shared state machine
|
||||
thread will also be destroyed. It will be recreated later if needed.
|
||||
The decoder object is about to be destroyed.
|
||||
|
||||
The following result in state transitions.
|
||||
|
||||
@ -173,41 +157,41 @@ player SHUTDOWN decoder SHUTDOWN
|
||||
The general sequence of events is:
|
||||
|
||||
1) The video element calls Load on nsMediaDecoder. This creates the
|
||||
state machine and starts the channel for downloading the
|
||||
file. It instantiates and schedules the nsDecoderStateMachine. The
|
||||
state machine thread and starts the channel for downloading the
|
||||
file. It instantiates and starts the nsDecoderStateMachine. The
|
||||
high level LOADING state is entered, which results in the decode
|
||||
thread being created and starting to decode metadata. These are
|
||||
the headers that give the video size, framerate, etc. Load() returns
|
||||
immediately to the calling video element.
|
||||
state machine to start decoding metadata. These are the headers
|
||||
that give the video size, framerate, etc. It returns immediately
|
||||
to the calling video element.
|
||||
|
||||
2) When the metadata has been loaded by the decode thread, the state machine
|
||||
will call a method on the video element object to inform it that this
|
||||
step is done, so it can do the things required by the video specification
|
||||
at this stage. The decode thread then continues to decode the first frame
|
||||
2) When the metadata has been loaded by the decode thread it will call
|
||||
a method on the video element object to inform it that this step is
|
||||
done, so it can do the things required by the video specification
|
||||
at this stage. The decoder then continues to decode the first frame
|
||||
of data.
|
||||
|
||||
3) When the first frame of data has been successfully decoded the state
|
||||
machine calls a method on the video element object to inform it that
|
||||
this step has been done, once again so it can do the required things
|
||||
by the video specification at this stage.
|
||||
3) When the first frame of data has been successfully decoded it calls
|
||||
a method on the video element object to inform it that this step
|
||||
has been done, once again so it can do the required things by the
|
||||
video specification at this stage.
|
||||
|
||||
This results in the high level state changing to PLAYING or PAUSED
|
||||
depending on any user action that may have occurred.
|
||||
|
||||
While the play state is PLAYING, the decode thread will decode
|
||||
data, and the audio thread will push audio data to the hardware to
|
||||
be played. The state machine will run periodically on the shared
|
||||
state machine thread to ensure video frames are played at the
|
||||
correct time; i.e. the state machine manages A/V sync.
|
||||
The decode thread plays audio and video, if the correct frame time
|
||||
comes around and the decoder play state is PLAYING.
|
||||
|
||||
a/v synchronisation is handled by the nsDecoderStateMachine implementation.
|
||||
|
||||
The Shutdown method on nsBuiltinDecoder closes the download channel, and
|
||||
signals to the state machine that it should shutdown. The state machine
|
||||
shuts down asynchronously, and will release the owning reference to the
|
||||
state machine once its threads are shutdown.
|
||||
|
||||
The owning object of a nsBuiltinDecoder object *MUST* call Shutdown when
|
||||
destroying the nsBuiltinDecoder object.
|
||||
The Shutdown method on nsBuiltinDecoder can spin the event loop as it
|
||||
waits for threads to complete. Spinning the event loop is a bad thing
|
||||
to happen during certain times like destruction of the media
|
||||
element. To work around this the Shutdown method does nothing but
|
||||
queue an event to the main thread to perform the actual Shutdown. This
|
||||
way the shutdown can occur at a safe time.
|
||||
|
||||
This means the owning object of a nsBuiltinDecoder object *MUST* call
|
||||
Shutdown when destroying the nsBuiltinDecoder object.
|
||||
*/
|
||||
#if !defined(nsBuiltinDecoder_h_)
|
||||
#define nsBuiltinDecoder_h_
|
||||
@ -285,9 +269,6 @@ public:
|
||||
// on the appropriate threads.
|
||||
virtual PRBool OnDecodeThread() const = 0;
|
||||
|
||||
// Returns PR_TRUE if the current thread is the state machine thread.
|
||||
virtual PRBool OnStateMachineThread() const = 0;
|
||||
|
||||
virtual nsHTMLMediaElement::NextFrameStatus GetNextFrameStatus() = 0;
|
||||
|
||||
// Cause state transitions. These methods obtain the decoder monitor
|
||||
@ -444,13 +425,19 @@ class nsBuiltinDecoder : public nsMediaDecoder
|
||||
// Tells our nsMediaStream to put all loads in the background.
|
||||
virtual void MoveLoadsToBackground();
|
||||
|
||||
// Stop the state machine thread and drop references to the thread and
|
||||
// state machine.
|
||||
void Stop();
|
||||
|
||||
void AudioAvailable(float* aFrameBuffer, PRUint32 aFrameBufferLength, float aTime);
|
||||
|
||||
// Called by the state machine to notify the decoder that the duration
|
||||
// has changed.
|
||||
void DurationChanged();
|
||||
|
||||
PRBool OnStateMachineThread() const;
|
||||
PRBool OnStateMachineThread() {
|
||||
return IsCurrentThread(mStateMachineThread);
|
||||
}
|
||||
|
||||
PRBool OnDecodeThread() const {
|
||||
return mDecoderStateMachine->OnDecodeThread();
|
||||
@ -580,9 +567,9 @@ public:
|
||||
// Notifies the element that decoding has failed.
|
||||
void DecodeError();
|
||||
|
||||
// Schedules the state machine to run one cycle on the shared state
|
||||
// machine thread. Main thread only.
|
||||
nsresult ScheduleStateMachineThread();
|
||||
// Ensures the state machine thread is running, starting a new one
|
||||
// if necessary.
|
||||
nsresult StartStateMachineThread();
|
||||
|
||||
/******
|
||||
* The following members should be accessed with the decoder lock held.
|
||||
@ -603,6 +590,9 @@ public:
|
||||
// time of the last decoded video frame).
|
||||
nsChannelStatistics mPlaybackStatistics;
|
||||
|
||||
// Thread to manage playback state machine.
|
||||
nsCOMPtr<nsIThread> mStateMachineThread;
|
||||
|
||||
// The current playback position of the media resource in units of
|
||||
// seconds. This is updated approximately at the framerate of the
|
||||
// video (if it is a video) or the callback period of the audio.
|
||||
|
@ -190,7 +190,8 @@ VideoData* VideoData::Create(nsVideoInfo& aInfo,
|
||||
}
|
||||
|
||||
nsBuiltinDecoderReader::nsBuiltinDecoderReader(nsBuiltinDecoder* aDecoder)
|
||||
: mDecoder(aDecoder)
|
||||
: mReentrantMonitor("media.decoderreader"),
|
||||
mDecoder(aDecoder)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsBuiltinDecoderReader);
|
||||
}
|
||||
@ -213,8 +214,7 @@ nsresult nsBuiltinDecoderReader::ResetDecode()
|
||||
|
||||
VideoData* nsBuiltinDecoderReader::FindStartTime(PRInt64& aOutStartTime)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on state machine or decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on state machine thread.");
|
||||
|
||||
// Extract the start times of the bitstreams in order to calculate
|
||||
// the duration.
|
||||
@ -274,6 +274,7 @@ nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget)
|
||||
PRBool skip = PR_FALSE;
|
||||
eof = !DecodeVideoFrame(skip, 0);
|
||||
{
|
||||
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
|
||||
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
|
||||
if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -298,6 +299,7 @@ nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget)
|
||||
}
|
||||
}
|
||||
{
|
||||
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
|
||||
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
|
||||
if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -313,6 +315,7 @@ nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget)
|
||||
while (!eof && mAudioQueue.GetSize() == 0) {
|
||||
eof = !DecodeAudioData();
|
||||
{
|
||||
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
|
||||
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
|
||||
if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -398,10 +398,12 @@ private:
|
||||
PRBool mEndOfStream;
|
||||
};
|
||||
|
||||
// Encapsulates the decoding and reading of media data. Reading can only be
|
||||
// done on the decode thread thread. Never hold the decoder monitor when
|
||||
// calling into this class. Unless otherwise specified, methods and fields of
|
||||
// this class can only be accessed on the decode thread.
|
||||
// Encapsulates the decoding and reading of media data. Reading can be done
|
||||
// on either the state machine thread (when loading and seeking) or on
|
||||
// the reader thread (when it's reading and decoding). The reader encapsulates
|
||||
// the reading state and maintains it's own monitor to ensure thread safety
|
||||
// and correctness. Never hold the nsBuiltinDecoder's monitor when calling into
|
||||
// this class.
|
||||
class nsBuiltinDecoderReader : public nsRunnable {
|
||||
public:
|
||||
typedef mozilla::ReentrantMonitor ReentrantMonitor;
|
||||
@ -450,12 +452,10 @@ public:
|
||||
PRInt64 aEndTime,
|
||||
PRInt64 aCurrentTime) = 0;
|
||||
|
||||
// Queue of audio samples. This queue is threadsafe, and is accessed from
|
||||
// the audio, decoder, state machine, and main threads.
|
||||
// Queue of audio samples. This queue is threadsafe.
|
||||
MediaQueue<SoundData> mAudioQueue;
|
||||
|
||||
// Queue of video samples. This queue is threadsafe, and is accessed from
|
||||
// the decoder, state machine, and main threads.
|
||||
// Queue of video samples. This queue is threadsafe.
|
||||
MediaQueue<VideoData> mVideoQueue;
|
||||
|
||||
// Populates aBuffered with the time ranges which are buffered. aStartTime
|
||||
@ -492,10 +492,16 @@ protected:
|
||||
return DecodeVideoFrame(f, 0);
|
||||
}
|
||||
|
||||
// Reference to the owning decoder object.
|
||||
// The lock which we hold whenever we read or decode. This ensures the thread
|
||||
// safety of the reader and its data fields.
|
||||
ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
// Reference to the owning decoder object. Do not hold the
|
||||
// reader's monitor when accessing this.
|
||||
nsBuiltinDecoder* mDecoder;
|
||||
|
||||
// Stores presentation info required for playback.
|
||||
// Stores presentation info required for playback. The reader's monitor
|
||||
// must be held when accessing this.
|
||||
nsVideoInfo mInfo;
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -37,10 +37,11 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/*
|
||||
Each video element for a media file has two threads:
|
||||
Each video element for a media file has two additional threads beyond
|
||||
those needed by nsBuiltinDecoder.
|
||||
|
||||
1) The Audio thread writes the decoded audio data to the audio
|
||||
hardware. This is done in a separate thread to ensure that the
|
||||
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
|
||||
@ -48,27 +49,31 @@ Each video element for a media file has two threads:
|
||||
needed.
|
||||
|
||||
2) The decode thread. This thread reads from the media stream and
|
||||
decodes the Theora and Vorbis data. It places the decoded data into
|
||||
queues for the other threads to pull from.
|
||||
decodes the Theora and Vorbis data. It places the decoded data in
|
||||
a queue for the other threads to pull from.
|
||||
|
||||
All file reads, seeks, and all decoding must occur on the decode thread.
|
||||
Synchronisation of state between the thread is done via a monitor owned
|
||||
by nsBuiltinDecoder.
|
||||
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 lifetime of the decode and audio threads is controlled by the state
|
||||
machine when it runs on the shared state machine thread. When playback
|
||||
needs to occur they are created and events dispatched to them to run
|
||||
them. These events exit when decoding/audio playback is completed or
|
||||
no longer required.
|
||||
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. It examines the audio
|
||||
playback time and compares this to the next frame in the queue of video
|
||||
frames. If it is time to play the video frame it is then displayed, otherwise
|
||||
it schedules the state machine to run again at the time of the next frame.
|
||||
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 will skip all frames in the video queue whose
|
||||
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.
|
||||
|
||||
@ -81,30 +86,28 @@ Frame skipping is done in the following ways:
|
||||
will be decoding video data that won't be displayed due
|
||||
to the decode thread dropping the frame immediately.
|
||||
|
||||
When hardware accelerated graphics is not available, YCbCr conversion
|
||||
is done on the decode thread when video frames are decoded.
|
||||
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 should
|
||||
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. If both queues are full, the decode
|
||||
thread will wait on the decoder monitor.
|
||||
|
||||
When the decode queues are full (they've reaced their maximum size) and
|
||||
the decoder is not in PLAYING play state, the state machine may opt
|
||||
to shut down the decode thread in order to conserve resources.
|
||||
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
|
||||
sound data off the queue and plays it with a blocking write to the audio
|
||||
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.
|
||||
*/
|
||||
#if !defined(nsBuiltinDecoderStateMachine_h__)
|
||||
#define nsBuiltinDecoderStateMachine_h__
|
||||
@ -116,17 +119,21 @@ hardware (via nsAudioStream and libsydneyaudio).
|
||||
#include "nsAudioAvailableEventManager.h"
|
||||
#include "nsHTMLMediaElement.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
/*
|
||||
The state machine class. This manages the decoding and seeking in the
|
||||
nsBuiltinDecoderReader on the decode thread, and A/V sync on the shared
|
||||
The playback state machine class. This manages the decoding in the
|
||||
nsBuiltinDecoderReader on the decode thread, seeking and in-sync-playback on the
|
||||
state machine thread, and controls the audio "push" thread.
|
||||
|
||||
All internal state is synchronised via the decoder monitor. State changes
|
||||
are either propagated by NotifyAll on the monitor (typically when state
|
||||
changes need to be propagated to non-state machine threads) or by scheduling
|
||||
the state machine to run another cycle on the shared state machine 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)
|
||||
Metadata Loaded
|
||||
First Frame Loaded
|
||||
Frame decoded
|
||||
data pushed or popped from the video and audio queues
|
||||
|
||||
See nsBuiltinDecoder.h for more details.
|
||||
*/
|
||||
@ -165,7 +172,13 @@ public:
|
||||
virtual void UpdatePlaybackPosition(PRInt64 aTime);
|
||||
virtual void StartBuffering();
|
||||
|
||||
// State machine thread run function. Defers to RunStateMachine().
|
||||
|
||||
// Load metadata Called on the state machine thread. The decoder monitor must be held with
|
||||
// exactly one lock count.
|
||||
virtual void LoadMetadata();
|
||||
|
||||
// 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.
|
||||
@ -201,29 +214,26 @@ public:
|
||||
|
||||
// Functions used by assertions to ensure we're calling things
|
||||
// on the appropriate threads.
|
||||
PRBool OnAudioThread() const {
|
||||
PRBool OnAudioThread() {
|
||||
return IsCurrentThread(mAudioThread);
|
||||
}
|
||||
|
||||
PRBool OnStateMachineThread() const {
|
||||
return IsCurrentThread(GetStateMachineThread());
|
||||
PRBool OnStateMachineThread() {
|
||||
return mDecoder->OnStateMachineThread();
|
||||
}
|
||||
|
||||
// The decoder object that created this state machine. The state machine
|
||||
// holds a strong reference to the decoder to ensure that the decoder stays
|
||||
// alive once media element has started the decoder shutdown process, and has
|
||||
// dropped its reference to the decoder. This enables the state machine to
|
||||
// keep using the decoder's monitor until the state machine has finished
|
||||
// shutting down, without fear of the monitor being destroyed. After
|
||||
// shutting down, the state machine will then release this reference,
|
||||
// causing the decoder to be destroyed. This is accessed on the decode,
|
||||
// state machine, audio and main threads.
|
||||
nsRefPtr<nsBuiltinDecoder> mDecoder;
|
||||
|
||||
// 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.
|
||||
nsBuiltinDecoder* mDecoder;
|
||||
|
||||
// The decoder monitor must be obtained before modifying this state.
|
||||
// NotifyAll on the monitor must be called when the state is changed so
|
||||
// that interested threads can wake up and alter behaviour if appropriate
|
||||
// Accessed on state machine, audio, main, and AV thread.
|
||||
// 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;
|
||||
|
||||
nsresult GetBuffered(nsTimeRanges* aBuffered);
|
||||
@ -247,23 +257,6 @@ public:
|
||||
// Accessed on the main and state machine threads.
|
||||
virtual void SetFrameBufferLength(PRUint32 aLength);
|
||||
|
||||
// Returns the shared state machine thread.
|
||||
static nsIThread* GetStateMachineThread();
|
||||
|
||||
// Schedules the shared state machine thread to run the state machine.
|
||||
// If the state machine thread is the currently running the state machine,
|
||||
// we wait until that has completely finished before running the state
|
||||
// machine again.
|
||||
nsresult ScheduleStateMachine();
|
||||
|
||||
// Schedules the shared state machine thread to run the state machine
|
||||
// in aUsecs microseconds from now, if it's not already scheduled to run
|
||||
// earlier, in which case the request is discarded.
|
||||
nsresult ScheduleStateMachine(PRInt64 aUsecs);
|
||||
|
||||
// Timer function to implement ScheduleStateMachine(aUsecs).
|
||||
void TimeoutExpired();
|
||||
|
||||
protected:
|
||||
|
||||
// Returns PR_TRUE if we've got less than aAudioUsecs microseconds of decoded
|
||||
@ -297,14 +290,14 @@ protected:
|
||||
// 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. Called only on the
|
||||
// audio thread.
|
||||
// (see bug 651023). The decoder monitor must be held.
|
||||
void Wait(PRInt64 aUsecs);
|
||||
|
||||
// Dispatches an asynchronous event to update the media element's ready state.
|
||||
void UpdateReadyState();
|
||||
|
||||
// Resets playback timing data. Called when we seek, on the decode thread.
|
||||
// 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.
|
||||
@ -323,8 +316,9 @@ protected:
|
||||
// machine thread, caller must hold the decoder lock.
|
||||
void UpdatePlaybackPositionInternal(PRInt64 aTime);
|
||||
|
||||
// Pushes the image down the rendering pipeline. Called on the shared state
|
||||
// machine thread. The decoder monitor must *not* be held when calling this.
|
||||
// Performs YCbCr to RGB conversion, and pushes the image down the
|
||||
// rendering pipeline. Called on the state machine thread. The decoder
|
||||
// monitor must not be held when calling this.
|
||||
void RenderVideoFrame(VideoData* aData, TimeStamp aTarget);
|
||||
|
||||
// If we have video, display a video frame if it's time for display has
|
||||
@ -350,35 +344,36 @@ protected:
|
||||
// queued here. Called on the audio thread.
|
||||
PRUint32 PlayFromAudioQueue(PRUint64 aSampleOffset, PRUint32 aChannels);
|
||||
|
||||
// Stops the decode thread. The decoder monitor must be held with exactly
|
||||
// Stops the decode threads. The decoder monitor must be held with exactly
|
||||
// one lock count. Called on the state machine thread.
|
||||
void StopDecodeThread();
|
||||
void StopDecodeThreads();
|
||||
|
||||
// Stops the audio thread. The decoder monitor must be held with exactly
|
||||
// Starts the decode threads. The decoder monitor must be held with exactly
|
||||
// one lock count. Called on the state machine thread.
|
||||
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();
|
||||
nsresult StartDecodeThreads();
|
||||
|
||||
// The main loop for the audio thread. Sent to the thread as
|
||||
// an nsRunnableMethod. This continually does blocking writes to
|
||||
// to audio stream to play audio data.
|
||||
void AudioLoop();
|
||||
|
||||
// Sets internal state which causes playback of media to pause.
|
||||
// The decoder monitor must be held. Called on the main, state machine,
|
||||
// and decode threads.
|
||||
void StopPlayback();
|
||||
// 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);
|
||||
|
||||
// Sets internal state which causes playback of media to begin or resume.
|
||||
// Must be called with the decode monitor held. Called on the state machine
|
||||
// and decode threads.
|
||||
// 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();
|
||||
|
||||
// Moves the decoder into decoding state. Called on the state machine
|
||||
@ -405,42 +400,14 @@ protected:
|
||||
// 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 decode thread.
|
||||
// must be held when calling this. Called on the decoder thread.
|
||||
PRInt64 GetDecodedAudioDuration();
|
||||
|
||||
// Load metadata. Called on the decode thread. The decoder monitor
|
||||
// must be held with exactly one lock count.
|
||||
nsresult DecodeMetadata();
|
||||
|
||||
// Seeks to mSeekTarget. Called on the decode thread. The decoder monitor
|
||||
// must be held with exactly one lock count.
|
||||
void DecodeSeek();
|
||||
|
||||
// Decode loop, decodes data until EOF or shutdown.
|
||||
// Called on the decode thread.
|
||||
void DecodeLoop();
|
||||
|
||||
// Decode thread run function. Determines which of the Decode*() functions
|
||||
// to call.
|
||||
void DecodeThreadRun();
|
||||
|
||||
// State machine thread run function. Defers to RunStateMachine().
|
||||
nsresult CallRunStateMachine();
|
||||
|
||||
// Performs one "cycle" of the state machine. Polls the state, and may send
|
||||
// a video frame to be displayed, and generally manages the decode. Called
|
||||
// periodically via timer to ensure the video stays in sync.
|
||||
nsresult RunStateMachine();
|
||||
|
||||
PRBool IsStateMachineScheduled() const {
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
return !mTimeout.IsNull() || mRunAgain;
|
||||
}
|
||||
|
||||
// Returns PR_TRUE if we're not playing and the decode thread has filled its
|
||||
// decode buffers and is waiting. We can shut the decode thread down in this
|
||||
// case as it may not be needed again.
|
||||
PRBool IsPausedAndDecoderWaiting();
|
||||
// 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;
|
||||
|
||||
// The size of the decoded YCbCr frame.
|
||||
// Accessed on state machine thread.
|
||||
@ -456,15 +423,6 @@ protected:
|
||||
// Thread for decoding video in background. The "decode thread".
|
||||
nsCOMPtr<nsIThread> mDecodeThread;
|
||||
|
||||
// Timer to call the state machine Run() method. Used by
|
||||
// ScheduleStateMachine(). Access protected by decoder monitor.
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
|
||||
// Timestamp at which the next state machine Run() method will be called.
|
||||
// If this is non-null, a call to Run() is scheduled, either by a timer,
|
||||
// or via an event. Access protected by decoder monitor.
|
||||
TimeStamp mTimeout;
|
||||
|
||||
// The time that playback started from the system clock. This is used for
|
||||
// timing the presentation of video frames when there's no audio.
|
||||
// Accessed only via the state machine thread.
|
||||
@ -483,24 +441,23 @@ protected:
|
||||
|
||||
// Start time of the media, in microseconds. This is the presentation
|
||||
// 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, decode,
|
||||
// and main threads. Access controlled by decoder monitor.
|
||||
// duration and as a bounds for seeking. Accessed on state machine and
|
||||
// main thread. Access controlled by decoder monitor.
|
||||
PRInt64 mStartTime;
|
||||
|
||||
// Time of the last page in the media, in microseconds. This is the
|
||||
// end time of the last sample in the media. Accessed on state
|
||||
// machine, decode, and main threads. Access controlled by decoder monitor.
|
||||
// machine and main thread. Access controlled by decoder monitor.
|
||||
PRInt64 mEndTime;
|
||||
|
||||
// Position to seek to in microseconds when the seek state transition occurs.
|
||||
// The decoder monitor lock must be obtained before reading or writing
|
||||
// this value. Accessed on main and decode thread.
|
||||
// this value. Accessed on main and state machine thread.
|
||||
PRInt64 mSeekTime;
|
||||
|
||||
// The audio stream resource. Used on the state machine, and audio threads.
|
||||
// This is created and destroyed on the audio thread, while holding the
|
||||
// decoder monitor, so if this is used off the audio thread, you must
|
||||
// first acquire the decoder monitor and check that it is non-null.
|
||||
// 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!
|
||||
nsRefPtr<nsAudioStream> mAudioStream;
|
||||
|
||||
// The reader, don't call its methods with the decoder monitor held.
|
||||
@ -559,20 +516,9 @@ protected:
|
||||
// the media index/metadata. Accessed on the state machine thread.
|
||||
PRPackedBool mGotDurationFromMetaData;
|
||||
|
||||
// PR_FALSE while decode thread should be running. Accessed state machine
|
||||
// and decode threads. Syncrhonised by decoder monitor.
|
||||
PRPackedBool mStopDecodeThread;
|
||||
|
||||
// PR_TRUE when the decode thread run function has finished, but the thread
|
||||
// has not necessarily been shut down yet. This can happen if we switch
|
||||
// from COMPLETED state to SEEKING before the state machine has a chance
|
||||
// to run in the COMPLETED state and shutdown the decode thread.
|
||||
// Synchronised by the decoder monitor.
|
||||
PRPackedBool mDecodeThreadIdle;
|
||||
|
||||
// PR_FALSE while audio thread should be running. Accessed state machine
|
||||
// and audio threads. Syncrhonised by decoder monitor.
|
||||
PRPackedBool mStopAudioThread;
|
||||
// PR_FALSE while decode threads should be running. Accessed on audio,
|
||||
// state machine and decode threads. Syncrhonised by decoder monitor.
|
||||
PRPackedBool mStopDecodeThreads;
|
||||
|
||||
// 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
|
||||
@ -581,26 +527,6 @@ protected:
|
||||
// Synchronised via decoder monitor.
|
||||
PRPackedBool mQuickBuffering;
|
||||
|
||||
// PR_TRUE if the shared state machine thread is currently running this
|
||||
// state machine.
|
||||
PRPackedBool mIsRunning;
|
||||
|
||||
// PR_TRUE if we should run the state machine again once the current
|
||||
// state machine run has finished.
|
||||
PRPackedBool mRunAgain;
|
||||
|
||||
// PR_TRUE if we've dispatched an event to run the state machine. It's
|
||||
// imperative that we don't dispatch multiple events to run the state
|
||||
// machine at the same time, as our code assume all events are synchronous.
|
||||
// If we dispatch multiple events, the second event can run while the
|
||||
// first is shutting down a thread, causing inconsistent state.
|
||||
PRPackedBool mDispatchedRunEvent;
|
||||
|
||||
// PR_TRUE if the decode thread has gone filled its buffers and is now
|
||||
// waiting to be awakened before it continues decoding. Synchronized
|
||||
// by the decoder monitor.
|
||||
PRPackedBool mDecodeThreadWaiting;
|
||||
|
||||
private:
|
||||
// Manager for queuing and dispatching MozAudioAvailable events. The
|
||||
// event manager is accessed from the state machine and audio threads,
|
||||
|
@ -65,6 +65,20 @@ class nsTimeRanges;
|
||||
#define FRAMEBUFFER_LENGTH_MIN 512
|
||||
#define FRAMEBUFFER_LENGTH_MAX 16384
|
||||
|
||||
// Shuts down a thread asynchronously.
|
||||
class ShutdownThreadEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ShutdownThreadEvent(nsIThread* aThread) : mThread(aThread) {}
|
||||
~ShutdownThreadEvent() {}
|
||||
NS_IMETHOD Run() {
|
||||
mThread->Shutdown();
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
};
|
||||
|
||||
// All methods of nsMediaDecoder must be called from the main thread only
|
||||
// with the exception of GetImageContainer, SetVideoData and GetStatistics,
|
||||
// which can be called from any thread.
|
||||
|
@ -140,20 +140,23 @@ nsresult nsOggReader::Init(nsBuiltinDecoderReader* aCloneDonor) {
|
||||
|
||||
nsresult nsOggReader::ResetDecode()
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
nsresult res = NS_OK;
|
||||
|
||||
if (NS_FAILED(nsBuiltinDecoderReader::ResetDecode())) {
|
||||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Discard any previously buffered packets/pages.
|
||||
ogg_sync_reset(&mOggState);
|
||||
if (mVorbisState && NS_FAILED(mVorbisState->Reset())) {
|
||||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
if (mTheoraState && NS_FAILED(mTheoraState->Reset())) {
|
||||
res = NS_ERROR_FAILURE;
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
// Discard any previously buffered packets/pages.
|
||||
ogg_sync_reset(&mOggState);
|
||||
if (mVorbisState && NS_FAILED(mVorbisState->Reset())) {
|
||||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
if (mTheoraState && NS_FAILED(mTheoraState->Reset())) {
|
||||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
@ -175,7 +178,8 @@ PRBool nsOggReader::ReadHeaders(nsOggCodecState* aState)
|
||||
|
||||
nsresult nsOggReader::ReadMetadata(nsVideoInfo* aInfo)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on play state machine thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
// We read packets until all bitstreams have read all their header packets.
|
||||
// We record the offset of the first non-header page so that we know
|
||||
@ -314,7 +318,8 @@ nsresult nsOggReader::ReadMetadata(nsVideoInfo* aInfo)
|
||||
}
|
||||
PRInt64 duration = 0;
|
||||
if (NS_SUCCEEDED(mSkeletonState->GetDuration(tracks, duration))) {
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
|
||||
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
|
||||
mDecoder->GetStateMachine()->SetDuration(duration);
|
||||
LOG(PR_LOG_DEBUG, ("Got duration from Skeleton index %lld", duration));
|
||||
}
|
||||
@ -322,7 +327,8 @@ nsresult nsOggReader::ReadMetadata(nsVideoInfo* aInfo)
|
||||
}
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
|
||||
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
nsMediaStream* stream = mDecoder->GetCurrentStream();
|
||||
if (mDecoder->GetStateMachine()->GetDuration() == -1 &&
|
||||
@ -396,7 +402,9 @@ nsresult nsOggReader::DecodeVorbis(ogg_packet* aPacket) {
|
||||
|
||||
PRBool nsOggReader::DecodeAudioData()
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on playback or decode thread.");
|
||||
NS_ASSERTION(mVorbisState!=0, "Need Vorbis state to decode audio");
|
||||
|
||||
// Read the next data packet. Skip any non-data packets we encounter.
|
||||
@ -472,6 +480,9 @@ nsresult nsOggReader::DecodeTheora(ogg_packet* aPacket, PRInt64 aTimeThreshold)
|
||||
b.mPlanes[i].mStride = buffer[i].stride;
|
||||
}
|
||||
|
||||
// Need the monitor to be held to be able to use mInfo. This
|
||||
// is held by our caller.
|
||||
mReentrantMonitor.AssertCurrentThreadIn();
|
||||
VideoData *v = VideoData::Create(mInfo,
|
||||
mDecoder->GetImageContainer(),
|
||||
mPageOffset,
|
||||
@ -495,7 +506,9 @@ nsresult nsOggReader::DecodeTheora(ogg_packet* aPacket, PRInt64 aTimeThreshold)
|
||||
PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
|
||||
PRInt64 aTimeThreshold)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on state machine or AV thread.");
|
||||
|
||||
// Record number of frames decoded and parsed. Automatically update the
|
||||
// stats counters using the AutoNotifyDecoded stack-based class.
|
||||
@ -544,7 +557,9 @@ PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
|
||||
|
||||
PRInt64 nsOggReader::ReadOggPage(ogg_page* aPage)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on play state machine or decode thread.");
|
||||
mReentrantMonitor.AssertCurrentThreadIn();
|
||||
|
||||
int ret = 0;
|
||||
while((ret = ogg_sync_pageseek(&mOggState, aPage)) <= 0) {
|
||||
@ -582,7 +597,9 @@ PRInt64 nsOggReader::ReadOggPage(ogg_page* aPage)
|
||||
|
||||
ogg_packet* nsOggReader::NextOggPacket(nsOggCodecState* aCodecState)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on play state machine or decode thread.");
|
||||
mReentrantMonitor.AssertCurrentThreadIn();
|
||||
|
||||
if (!aCodecState || !aCodecState->mActive) {
|
||||
return nsnull;
|
||||
@ -625,7 +642,8 @@ GetChecksum(ogg_page* page)
|
||||
|
||||
PRInt64 nsOggReader::RangeStartTime(PRInt64 aOffset)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
nsMediaStream* stream = mDecoder->GetCurrentStream();
|
||||
NS_ENSURE_TRUE(stream != nsnull, nsnull);
|
||||
nsresult res = stream->Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
|
||||
@ -647,8 +665,9 @@ struct nsAutoOggSyncState {
|
||||
|
||||
PRInt64 nsOggReader::RangeEndTime(PRInt64 aEndOffset)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on state machine or decode thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
|
||||
nsMediaStream* stream = mDecoder->GetCurrentStream();
|
||||
NS_ENSURE_TRUE(stream != nsnull, -1);
|
||||
@ -778,7 +797,9 @@ PRInt64 nsOggReader::RangeEndTime(PRInt64 aStartOffset,
|
||||
|
||||
nsresult nsOggReader::GetSeekRanges(nsTArray<SeekRange>& aRanges)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
mReentrantMonitor.AssertCurrentThreadIn();
|
||||
nsTArray<nsByteRange> cached;
|
||||
nsresult res = mDecoder->GetCurrentStream()->GetCachedRanges(cached);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
@ -817,7 +838,8 @@ nsOggReader::SelectSeekRange(const nsTArray<SeekRange>& ranges,
|
||||
PRInt64 aEndTime,
|
||||
PRBool aExact)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
PRInt64 so = 0;
|
||||
PRInt64 eo = mDecoder->GetCurrentStream()->GetLength();
|
||||
PRInt64 st = aStartTime;
|
||||
@ -955,7 +977,8 @@ nsresult nsOggReader::SeekInBufferedRange(PRInt64 aTarget,
|
||||
PRBool skip = PR_FALSE;
|
||||
eof = !DecodeVideoFrame(skip, 0);
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
|
||||
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
|
||||
if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -1029,7 +1052,9 @@ nsresult nsOggReader::Seek(PRInt64 aTarget,
|
||||
PRInt64 aEndTime,
|
||||
PRInt64 aCurrentTime)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
LOG(PR_LOG_DEBUG, ("%p About to seek to %lldms", mDecoder, aTarget));
|
||||
nsresult res;
|
||||
nsMediaStream* stream = mDecoder->GetCurrentStream();
|
||||
@ -1047,7 +1072,8 @@ nsresult nsOggReader::Seek(PRInt64 aTarget,
|
||||
|
||||
NS_ASSERTION(aStartTime != -1, "mStartTime should be known");
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
|
||||
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
|
||||
mDecoder->UpdatePlaybackPosition(aStartTime);
|
||||
}
|
||||
} else if (CanDecodeToTarget(aTarget, aCurrentTime)) {
|
||||
@ -1157,7 +1183,8 @@ nsresult nsOggReader::SeekBisection(PRInt64 aTarget,
|
||||
const SeekRange& aRange,
|
||||
PRUint32 aFuzz)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
nsresult res;
|
||||
nsMediaStream* stream = mDecoder->GetCurrentStream();
|
||||
|
||||
|
@ -71,11 +71,15 @@ public:
|
||||
virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip,
|
||||
PRInt64 aTimeThreshold);
|
||||
|
||||
virtual PRBool HasAudio() {
|
||||
virtual PRBool HasAudio()
|
||||
{
|
||||
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mVorbisState != 0 && mVorbisState->mActive;
|
||||
}
|
||||
|
||||
virtual PRBool HasVideo() {
|
||||
virtual PRBool HasVideo()
|
||||
{
|
||||
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mTheoraState != 0 && mTheoraState->mActive;
|
||||
}
|
||||
|
||||
@ -85,7 +89,9 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
PRBool HasSkeleton() {
|
||||
PRBool HasSkeleton()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mSkeletonState != 0 && mSkeletonState->mActive;
|
||||
}
|
||||
|
||||
|
@ -123,6 +123,7 @@ var gPlayTests = [
|
||||
{ name:"spacestorm-1000Hz-100ms.ogg", type:"audio/ogg", duration:0.099 },
|
||||
|
||||
{ name:"bogus.duh", type:"bogus/duh", duration:Number.NaN }
|
||||
|
||||
];
|
||||
|
||||
// Converts a path/filename to a file:// URI which we can load from disk.
|
||||
|
@ -29,8 +29,7 @@ function startTest() {
|
||||
function seekStarted() {
|
||||
if (completed)
|
||||
return false;
|
||||
ok(v.currentTime >= seekTime - 0.1,
|
||||
"Video currentTime should be around " + seekTime + ": " + v.currentTime + " (seeking)");
|
||||
ok(v.currentTime >= seekTime - 0.1, "Video currentTime should be around " + seekTime + ": " + v.currentTime);
|
||||
v.pause();
|
||||
startPassed = true;
|
||||
return false;
|
||||
@ -44,7 +43,7 @@ function seekEnded() {
|
||||
// Since we were playing, and we only paused asynchronously, we can't be
|
||||
// sure that we paused before the seek finished, so we may have played
|
||||
// ahead arbitrarily far.
|
||||
ok(t >= seekTime - 0.1, "Video currentTime should be around " + seekTime + ": " + t + " (seeked)");
|
||||
ok(t >= seekTime - 0.1, "Video currentTime should be around " + seekTime + ": " + t);
|
||||
v.play();
|
||||
endPassed = true;
|
||||
seekFlagEnd = v.seeking;
|
||||
|
@ -41,7 +41,7 @@ function ended(e) {
|
||||
} catch (e) {
|
||||
caught = e.code == DOMException.INDEX_SIZE_ERR;
|
||||
}
|
||||
is(caught, true, v._name + ": Should throw INDEX_SIZE_ERR on under start bounds range");
|
||||
is(caught, true, "Should throw INDEX_SIZE_ERR on under start bounds range");
|
||||
|
||||
caught = false;
|
||||
try {
|
||||
@ -49,7 +49,7 @@ function ended(e) {
|
||||
} catch (e) {
|
||||
caught = e.code == DOMException.INDEX_SIZE_ERR;
|
||||
}
|
||||
is(caught, true, v._name + ": Should throw INDEX_SIZE_ERR on under end bounds range");
|
||||
is(caught, true, "Should throw INDEX_SIZE_ERR on under end bounds range");
|
||||
|
||||
caught = false;
|
||||
try {
|
||||
@ -57,7 +57,7 @@ function ended(e) {
|
||||
} catch (e) {
|
||||
caught = e.code == DOMException.INDEX_SIZE_ERR;
|
||||
}
|
||||
is(caught, true, v._name + ": Should throw INDEX_SIZE_ERR on over start bounds range");
|
||||
is(caught, true, "Should throw INDEX_SIZE_ERR on over start bounds range");
|
||||
|
||||
caught = false;
|
||||
try {
|
||||
@ -65,9 +65,8 @@ function ended(e) {
|
||||
} catch (e) {
|
||||
caught = e.code == DOMException.INDEX_SIZE_ERR;
|
||||
}
|
||||
is(caught, true, v._name + ": Should throw INDEX_SIZE_ERR on over end bounds range");
|
||||
|
||||
v.src = "";
|
||||
is(caught, true, "Should throw INDEX_SIZE_ERR on over end bounds range");
|
||||
|
||||
v.parentNode.removeChild(v);
|
||||
manager.finished(v.token);
|
||||
|
||||
|
@ -33,7 +33,6 @@ function canPlayThrough(e) {
|
||||
ok(true, "Got canplaythrough after seek for " + v._name);
|
||||
v._finished = true;
|
||||
v.parentNode.removeChild(v);
|
||||
v.src = "";
|
||||
manager.finished(v.token);
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,8 @@ nsresult nsWaveReader::Init(nsBuiltinDecoderReader* aCloneDonor)
|
||||
|
||||
nsresult nsWaveReader::ReadMetadata(nsVideoInfo* aInfo)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on state machine thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
PRBool loaded = LoadRIFFChunk() && LoadFormatChunk() && FindDataOffset();
|
||||
if (!loaded) {
|
||||
@ -166,7 +167,8 @@ nsresult nsWaveReader::ReadMetadata(nsVideoInfo* aInfo)
|
||||
|
||||
*aInfo = mInfo;
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
|
||||
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
mDecoder->GetStateMachine()->SetDuration(
|
||||
static_cast<PRInt64>(BytesToTime(GetDataLength()) * USECS_PER_S));
|
||||
@ -176,7 +178,9 @@ nsresult nsWaveReader::ReadMetadata(nsVideoInfo* aInfo)
|
||||
|
||||
PRBool nsWaveReader::DecodeAudioData()
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on state machine thread or decode thread.");
|
||||
|
||||
PRInt64 pos = GetPosition() - mWavePCMOffset;
|
||||
PRInt64 len = GetDataLength();
|
||||
@ -242,14 +246,18 @@ PRBool nsWaveReader::DecodeAudioData()
|
||||
PRBool nsWaveReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
|
||||
PRInt64 aTimeThreshold)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on state machine or decode thread.");
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult nsWaveReader::Seek(PRInt64 aTarget, PRInt64 aStartTime, PRInt64 aEndTime, PRInt64 aCurrentTime)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
LOG(PR_LOG_DEBUG, ("%p About to seek to %lld", mDecoder, aTarget));
|
||||
if (NS_FAILED(ResetDecode())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -210,7 +210,8 @@ void nsWebMReader::Cleanup()
|
||||
|
||||
nsresult nsWebMReader::ReadMetadata(nsVideoInfo* aInfo)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on state machine thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
nestegg_io io;
|
||||
io.read = webm_read;
|
||||
@ -225,7 +226,8 @@ nsresult nsWebMReader::ReadMetadata(nsVideoInfo* aInfo)
|
||||
uint64_t duration = 0;
|
||||
r = nestegg_duration(mContext, &duration);
|
||||
if (r == 0) {
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
|
||||
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
|
||||
mDecoder->GetStateMachine()->SetDuration(duration / NS_PER_USEC);
|
||||
}
|
||||
|
||||
@ -410,7 +412,7 @@ ogg_packet nsWebMReader::InitOggPacket(unsigned char* aData,
|
||||
|
||||
PRBool nsWebMReader::DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
mReentrantMonitor.AssertCurrentThreadIn();
|
||||
|
||||
int r = 0;
|
||||
unsigned int count = 0;
|
||||
@ -588,8 +590,9 @@ nsReturnRef<NesteggPacketHolder> nsWebMReader::NextPacket(TrackType aTrackType)
|
||||
|
||||
PRBool nsWebMReader::DecodeAudioData()
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on state machine thread or decode thread.");
|
||||
nsAutoRef<NesteggPacketHolder> holder(NextPacket(AUDIO));
|
||||
if (!holder) {
|
||||
mAudioQueue.Finish();
|
||||
@ -602,7 +605,9 @@ PRBool nsWebMReader::DecodeAudioData()
|
||||
PRBool nsWebMReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
|
||||
PRInt64 aTimeThreshold)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on state machine or decode thread.");
|
||||
|
||||
// Record number of frames decoded and parsed. Automatically update the
|
||||
// stats counters using the AutoNotifyDecoded stack-based class.
|
||||
@ -648,6 +653,7 @@ PRBool nsWebMReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
|
||||
}
|
||||
mVideoPackets.PushFront(next_holder.disown());
|
||||
} else {
|
||||
ReentrantMonitorAutoExit exitMon(mReentrantMonitor);
|
||||
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
|
||||
nsBuiltinDecoderStateMachine* s =
|
||||
static_cast<nsBuiltinDecoderStateMachine*>(mDecoder->GetStateMachine());
|
||||
@ -761,8 +767,9 @@ PRBool nsWebMReader::CanDecodeToTarget(PRInt64 aTarget,
|
||||
nsresult nsWebMReader::Seek(PRInt64 aTarget, PRInt64 aStartTime, PRInt64 aEndTime,
|
||||
PRInt64 aCurrentTime)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
LOG(PR_LOG_DEBUG, ("%p About to seek to %lldms", mDecoder, aTarget));
|
||||
if (CanDecodeToTarget(aTarget, aCurrentTime)) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Seek target (%lld) is close to current time (%lld), "
|
||||
|
@ -143,13 +143,13 @@ public:
|
||||
|
||||
virtual PRBool HasAudio()
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mHasAudio;
|
||||
}
|
||||
|
||||
virtual PRBool HasVideo()
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mHasVideo;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user