Bug 592833 - Split StartDecodeThreads() into StartDecodeThread() and StartAudioThread() for finer control. r=roc

This commit is contained in:
Chris Pearce 2011-07-06 10:03:01 +12:00
Родитель 553ac96cf1
Коммит 3b48c23ee6
2 изменённых файлов: 70 добавлений и 29 удалений

Просмотреть файл

@ -191,7 +191,8 @@ nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDe
mPositionChangeQueued(PR_FALSE), mPositionChangeQueued(PR_FALSE),
mAudioCompleted(PR_FALSE), mAudioCompleted(PR_FALSE),
mGotDurationFromMetaData(PR_FALSE), mGotDurationFromMetaData(PR_FALSE),
mStopDecodeThreads(PR_TRUE), mStopDecodeThread(PR_TRUE),
mStopAudioThread(PR_TRUE),
mQuickBuffering(PR_FALSE), mQuickBuffering(PR_FALSE),
mEventManager(aDecoder) mEventManager(aDecoder)
{ {
@ -274,7 +275,7 @@ void nsBuiltinDecoderStateMachine::DecodeLoop()
// Main decode loop. // Main decode loop.
while (mState != DECODER_STATE_SHUTDOWN && while (mState != DECODER_STATE_SHUTDOWN &&
!mStopDecodeThreads && !mStopDecodeThread &&
(videoPlaying || audioPlaying)) (videoPlaying || audioPlaying))
{ {
// We don't want to consider skipping to the next keyframe if we've // We don't want to consider skipping to the next keyframe if we've
@ -358,7 +359,7 @@ void nsBuiltinDecoderStateMachine::DecodeLoop()
UpdateReadyState(); UpdateReadyState();
if (mState != DECODER_STATE_SHUTDOWN && if (mState != DECODER_STATE_SHUTDOWN &&
!mStopDecodeThreads && !mStopDecodeThread &&
(videoPlaying || audioPlaying) && (videoPlaying || audioPlaying) &&
(!audioPlaying || (GetDecodedAudioDuration() >= ampleAudioThreshold && (!audioPlaying || (GetDecodedAudioDuration() >= ampleAudioThreshold &&
audioQueue.GetSize() > 0)) audioQueue.GetSize() > 0))
@ -380,7 +381,7 @@ void nsBuiltinDecoderStateMachine::DecodeLoop()
} // End decode loop. } // End decode loop.
if (!mStopDecodeThreads && if (!mStopDecodeThread &&
mState != DECODER_STATE_SHUTDOWN && mState != DECODER_STATE_SHUTDOWN &&
mState != DECODER_STATE_SEEKING) mState != DECODER_STATE_SEEKING)
{ {
@ -426,7 +427,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop()
NS_ASSERTION(mState != DECODER_STATE_DECODING_METADATA, NS_ASSERTION(mState != DECODER_STATE_DECODING_METADATA,
"Should have meta data before audio started playing."); "Should have meta data before audio started playing.");
while (mState != DECODER_STATE_SHUTDOWN && while (mState != DECODER_STATE_SHUTDOWN &&
!mStopDecodeThreads && !mStopAudioThread &&
(!IsPlaying() || (!IsPlaying() ||
mState == DECODER_STATE_BUFFERING || mState == DECODER_STATE_BUFFERING ||
(mReader->mAudioQueue.GetSize() == 0 && (mReader->mAudioQueue.GetSize() == 0 &&
@ -438,7 +439,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop()
// If we're shutting down, break out and exit the audio thread. // If we're shutting down, break out and exit the audio thread.
if (mState == DECODER_STATE_SHUTDOWN || if (mState == DECODER_STATE_SHUTDOWN ||
mStopDecodeThreads || mStopAudioThread ||
mReader->mAudioQueue.AtEndOfStream()) mReader->mAudioQueue.AtEndOfStream())
{ {
break; break;
@ -539,7 +540,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop()
} }
if (mReader->mAudioQueue.AtEndOfStream() && if (mReader->mAudioQueue.AtEndOfStream() &&
mState != DECODER_STATE_SHUTDOWN && mState != DECODER_STATE_SHUTDOWN &&
!mStopDecodeThreads) !mStopAudioThread)
{ {
// Last sample pushed to audio hardware, wait for the audio to finish, // Last sample pushed to audio hardware, wait for the audio to finish,
// before the audio thread terminates. // before the audio thread terminates.
@ -922,21 +923,32 @@ void nsBuiltinDecoderStateMachine::Seek(double aTime)
mState = DECODER_STATE_SEEKING; mState = DECODER_STATE_SEEKING;
} }
void nsBuiltinDecoderStateMachine::StopDecodeThreads() void nsBuiltinDecoderStateMachine::StopDecodeThread()
{ {
NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread), NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread),
"Should be on state machine thread."); "Should be on state machine thread.");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
mStopDecodeThreads = PR_TRUE; mStopDecodeThread = PR_TRUE;
mDecoder->GetReentrantMonitor().NotifyAll(); mDecoder->GetReentrantMonitor().NotifyAll();
if (mDecodeThread) { if (mDecodeThread) {
LOG(PR_LOG_DEBUG, ("%p Shutdown decode thread", mDecoder));
{ {
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
mDecodeThread->Shutdown(); mDecodeThread->Shutdown();
} }
mDecodeThread = nsnull; mDecodeThread = nsnull;
} }
}
void nsBuiltinDecoderStateMachine::StopAudioThread()
{
NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread),
"Should be on state machine thread.");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
mStopAudioThread = PR_TRUE;
mDecoder->GetReentrantMonitor().NotifyAll();
if (mAudioThread) { if (mAudioThread) {
LOG(PR_LOG_DEBUG, ("%p Shutdown audio thread", mDecoder));
{ {
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
mAudioThread->Shutdown(); mAudioThread->Shutdown();
@ -946,12 +958,12 @@ void nsBuiltinDecoderStateMachine::StopDecodeThreads()
} }
nsresult nsresult
nsBuiltinDecoderStateMachine::StartDecodeThreads() nsBuiltinDecoderStateMachine::StartDecodeThread()
{ {
NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread), NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread),
"Should be on state machine thread."); "Should be on state machine thread.");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
mStopDecodeThreads = PR_FALSE; mStopDecodeThread = PR_FALSE;
if (!mDecodeThread && mState < DECODER_STATE_COMPLETED) { if (!mDecodeThread && mState < DECODER_STATE_COMPLETED) {
nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread)); nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
@ -962,6 +974,16 @@ nsBuiltinDecoderStateMachine::StartDecodeThreads()
NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeLoop); NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeLoop);
mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL); mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
} }
return NS_OK;
}
nsresult
nsBuiltinDecoderStateMachine::StartAudioThread()
{
NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread),
"Should be on state machine thread.");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
mStopAudioThread = PR_FALSE;
if (HasAudio() && !mAudioThread) { if (HasAudio() && !mAudioThread) {
nsresult rv = NS_NewThread(getter_AddRefs(mAudioThread)); nsresult rv = NS_NewThread(getter_AddRefs(mAudioThread));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
@ -1061,7 +1083,8 @@ nsresult nsBuiltinDecoderStateMachine::Run()
if (IsPlaying()) { if (IsPlaying()) {
StopPlayback(AUDIO_SHUTDOWN); StopPlayback(AUDIO_SHUTDOWN);
} }
StopDecodeThreads(); StopAudioThread();
StopDecodeThread();
NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN, NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
"How did we escape from the shutdown state???"); "How did we escape from the shutdown state???");
return NS_OK; return NS_OK;
@ -1081,7 +1104,7 @@ nsresult nsBuiltinDecoderStateMachine::Run()
// Start the decode threads, so that we can pre buffer the streams. // Start the decode threads, so that we can pre buffer the streams.
// and calculate the start time in order to determine the duration. // and calculate the start time in order to determine the duration.
if (NS_FAILED(StartDecodeThreads())) { if (NS_FAILED(StartDecodeThread())) {
continue; continue;
} }
@ -1121,6 +1144,7 @@ nsresult nsBuiltinDecoderStateMachine::Run()
if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING) { if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING) {
if (!IsPlaying()) { if (!IsPlaying()) {
StartPlayback(); StartPlayback();
StartAudioThread();
} }
} }
} }
@ -1128,7 +1152,7 @@ nsresult nsBuiltinDecoderStateMachine::Run()
case DECODER_STATE_DECODING: case DECODER_STATE_DECODING:
{ {
if (NS_FAILED(StartDecodeThreads())) { if (NS_FAILED(StartDecodeThread())) {
continue; continue;
} }
@ -1174,7 +1198,8 @@ nsresult nsBuiltinDecoderStateMachine::Run()
// we'll need to seek the playback position, so shutdown our decode // we'll need to seek the playback position, so shutdown our decode
// and audio threads. // and audio threads.
StopPlayback(AUDIO_SHUTDOWN); StopPlayback(AUDIO_SHUTDOWN);
StopDecodeThreads(); StopDecodeThread();
StopAudioThread();
ResetPlayback(); ResetPlayback();
nsresult res; nsresult res;
{ {
@ -1291,10 +1316,11 @@ nsresult nsBuiltinDecoderStateMachine::Run()
// Notify to allow blocked decoder thread to continue // Notify to allow blocked decoder thread to continue
mDecoder->GetReentrantMonitor().NotifyAll(); mDecoder->GetReentrantMonitor().NotifyAll();
UpdateReadyState(); UpdateReadyState();
if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING) { if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING &&
if (!IsPlaying()) { !IsPlaying())
{
StartPlayback(); StartPlayback();
} StartAudioThread();
} }
} }
break; break;
@ -1302,7 +1328,9 @@ nsresult nsBuiltinDecoderStateMachine::Run()
case DECODER_STATE_COMPLETED: case DECODER_STATE_COMPLETED:
{ {
if (NS_FAILED(StartDecodeThreads())) { StopDecodeThread();
if (NS_FAILED(StartAudioThread())) {
continue; continue;
} }
@ -1325,8 +1353,7 @@ nsresult nsBuiltinDecoderStateMachine::Run()
if (mState != DECODER_STATE_COMPLETED) if (mState != DECODER_STATE_COMPLETED)
continue; continue;
LOG(PR_LOG_DEBUG, ("%p Shutting down the state machine thread", mDecoder)); StopAudioThread();
StopDecodeThreads();
if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING) { if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING) {
PRInt64 videoTime = HasVideo() ? mVideoFrameEndTime : 0; PRInt64 videoTime = HasVideo() ? mVideoFrameEndTime : 0;
@ -1343,6 +1370,7 @@ nsresult nsBuiltinDecoderStateMachine::Run()
if (mState == DECODER_STATE_COMPLETED) { if (mState == DECODER_STATE_COMPLETED) {
// We've finished playback. Shutdown the state machine thread, // We've finished playback. Shutdown the state machine thread,
// in order to save memory on thread stacks, particuarly on Linux. // in order to save memory on thread stacks, particuarly on Linux.
LOG(PR_LOG_DEBUG, ("%p Shutting down the state machine thread", mDecoder));
nsCOMPtr<nsIRunnable> event = nsCOMPtr<nsIRunnable> event =
new ShutdownThreadEvent(mDecoder->mStateMachineThread); new ShutdownThreadEvent(mDecoder->mStateMachineThread);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
@ -1473,6 +1501,7 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame()
// Start playing now if need be. // Start playing now if need be.
if (!IsPlaying()) { if (!IsPlaying()) {
StartPlayback(); StartPlayback();
StartAudioThread();
mDecoder->GetReentrantMonitor().NotifyAll(); mDecoder->GetReentrantMonitor().NotifyAll();
} }

Просмотреть файл

@ -344,13 +344,21 @@ protected:
// queued here. Called on the audio thread. // queued here. Called on the audio thread.
PRUint32 PlayFromAudioQueue(PRUint64 aSampleOffset, PRUint32 aChannels); PRUint32 PlayFromAudioQueue(PRUint64 aSampleOffset, PRUint32 aChannels);
// Stops the decode threads. The decoder monitor must be held with exactly // Stops the decode thread. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread. // one lock count. Called on the state machine thread.
void StopDecodeThreads(); void StopDecodeThread();
// Starts the decode threads. The decoder monitor must be held with exactly // Stops the audio thread. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread. // one lock count. Called on the state machine thread.
nsresult StartDecodeThreads(); 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();
// The main loop for the audio thread. Sent to the thread as // The main loop for the audio thread. Sent to the thread as
// an nsRunnableMethod. This continually does blocking writes to // an nsRunnableMethod. This continually does blocking writes to
@ -516,9 +524,13 @@ protected:
// the media index/metadata. Accessed on the state machine thread. // the media index/metadata. Accessed on the state machine thread.
PRPackedBool mGotDurationFromMetaData; PRPackedBool mGotDurationFromMetaData;
// PR_FALSE while decode threads should be running. Accessed on audio, // PR_FALSE while decode thread should be running. Accessed state machine
// state machine and decode threads. Syncrhonised by decoder monitor. // and decode threads. Syncrhonised by decoder monitor.
PRPackedBool mStopDecodeThreads; PRPackedBool mStopDecodeThread;
// PR_FALSE while audio thread should be running. Accessed state machine
// and audio threads. Syncrhonised by decoder monitor.
PRPackedBool mStopAudioThread;
// If this is PR_TRUE while we're in buffering mode, we can exit early, // 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 // as it's likely we may be able to playback. This happens when we enter