From 3b48c23ee668c2ddf5da8ddc53ef39878c550eb6 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Wed, 6 Jul 2011 10:03:01 +1200 Subject: [PATCH] Bug 592833 - Split StartDecodeThreads() into StartDecodeThread() and StartAudioThread() for finer control. r=roc --- .../media/nsBuiltinDecoderStateMachine.cpp | 73 +++++++++++++------ content/media/nsBuiltinDecoderStateMachine.h | 26 +++++-- 2 files changed, 70 insertions(+), 29 deletions(-) diff --git a/content/media/nsBuiltinDecoderStateMachine.cpp b/content/media/nsBuiltinDecoderStateMachine.cpp index 25968e3641bc..2a778509edbd 100644 --- a/content/media/nsBuiltinDecoderStateMachine.cpp +++ b/content/media/nsBuiltinDecoderStateMachine.cpp @@ -191,7 +191,8 @@ nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDe mPositionChangeQueued(PR_FALSE), mAudioCompleted(PR_FALSE), mGotDurationFromMetaData(PR_FALSE), - mStopDecodeThreads(PR_TRUE), + mStopDecodeThread(PR_TRUE), + mStopAudioThread(PR_TRUE), mQuickBuffering(PR_FALSE), mEventManager(aDecoder) { @@ -274,7 +275,7 @@ void nsBuiltinDecoderStateMachine::DecodeLoop() // Main decode loop. while (mState != DECODER_STATE_SHUTDOWN && - !mStopDecodeThreads && + !mStopDecodeThread && (videoPlaying || audioPlaying)) { // We don't want to consider skipping to the next keyframe if we've @@ -358,7 +359,7 @@ void nsBuiltinDecoderStateMachine::DecodeLoop() UpdateReadyState(); if (mState != DECODER_STATE_SHUTDOWN && - !mStopDecodeThreads && + !mStopDecodeThread && (videoPlaying || audioPlaying) && (!audioPlaying || (GetDecodedAudioDuration() >= ampleAudioThreshold && audioQueue.GetSize() > 0)) @@ -380,7 +381,7 @@ void nsBuiltinDecoderStateMachine::DecodeLoop() } // End decode loop. - if (!mStopDecodeThreads && + if (!mStopDecodeThread && mState != DECODER_STATE_SHUTDOWN && mState != DECODER_STATE_SEEKING) { @@ -426,7 +427,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop() NS_ASSERTION(mState != DECODER_STATE_DECODING_METADATA, "Should have meta data before audio started playing."); while (mState != DECODER_STATE_SHUTDOWN && - !mStopDecodeThreads && + !mStopAudioThread && (!IsPlaying() || mState == DECODER_STATE_BUFFERING || (mReader->mAudioQueue.GetSize() == 0 && @@ -438,7 +439,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop() // If we're shutting down, break out and exit the audio thread. if (mState == DECODER_STATE_SHUTDOWN || - mStopDecodeThreads || + mStopAudioThread || mReader->mAudioQueue.AtEndOfStream()) { break; @@ -539,7 +540,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop() } if (mReader->mAudioQueue.AtEndOfStream() && mState != DECODER_STATE_SHUTDOWN && - !mStopDecodeThreads) + !mStopAudioThread) { // Last sample pushed to audio hardware, wait for the audio to finish, // before the audio thread terminates. @@ -922,21 +923,32 @@ void nsBuiltinDecoderStateMachine::Seek(double aTime) mState = DECODER_STATE_SEEKING; } -void nsBuiltinDecoderStateMachine::StopDecodeThreads() +void nsBuiltinDecoderStateMachine::StopDecodeThread() { NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread), "Should be on state machine thread."); mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); - mStopDecodeThreads = PR_TRUE; + mStopDecodeThread = PR_TRUE; mDecoder->GetReentrantMonitor().NotifyAll(); if (mDecodeThread) { + LOG(PR_LOG_DEBUG, ("%p Shutdown decode thread", mDecoder)); { ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); mDecodeThread->Shutdown(); } 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) { + LOG(PR_LOG_DEBUG, ("%p Shutdown audio thread", mDecoder)); { ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); mAudioThread->Shutdown(); @@ -946,12 +958,12 @@ void nsBuiltinDecoderStateMachine::StopDecodeThreads() } nsresult -nsBuiltinDecoderStateMachine::StartDecodeThreads() +nsBuiltinDecoderStateMachine::StartDecodeThread() { NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread), "Should be on state machine thread."); mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); - mStopDecodeThreads = PR_FALSE; + mStopDecodeThread = PR_FALSE; if (!mDecodeThread && mState < DECODER_STATE_COMPLETED) { nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread)); if (NS_FAILED(rv)) { @@ -962,6 +974,16 @@ nsBuiltinDecoderStateMachine::StartDecodeThreads() NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeLoop); 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) { nsresult rv = NS_NewThread(getter_AddRefs(mAudioThread)); if (NS_FAILED(rv)) { @@ -1061,7 +1083,8 @@ nsresult nsBuiltinDecoderStateMachine::Run() if (IsPlaying()) { StopPlayback(AUDIO_SHUTDOWN); } - StopDecodeThreads(); + StopAudioThread(); + StopDecodeThread(); NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN, "How did we escape from the shutdown state???"); return NS_OK; @@ -1081,7 +1104,7 @@ nsresult nsBuiltinDecoderStateMachine::Run() // Start the decode threads, so that we can pre buffer the streams. // and calculate the start time in order to determine the duration. - if (NS_FAILED(StartDecodeThreads())) { + if (NS_FAILED(StartDecodeThread())) { continue; } @@ -1121,6 +1144,7 @@ nsresult nsBuiltinDecoderStateMachine::Run() if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING) { if (!IsPlaying()) { StartPlayback(); + StartAudioThread(); } } } @@ -1128,7 +1152,7 @@ nsresult nsBuiltinDecoderStateMachine::Run() case DECODER_STATE_DECODING: { - if (NS_FAILED(StartDecodeThreads())) { + if (NS_FAILED(StartDecodeThread())) { continue; } @@ -1174,7 +1198,8 @@ nsresult nsBuiltinDecoderStateMachine::Run() // we'll need to seek the playback position, so shutdown our decode // and audio threads. StopPlayback(AUDIO_SHUTDOWN); - StopDecodeThreads(); + StopDecodeThread(); + StopAudioThread(); ResetPlayback(); nsresult res; { @@ -1291,10 +1316,11 @@ nsresult nsBuiltinDecoderStateMachine::Run() // Notify to allow blocked decoder thread to continue mDecoder->GetReentrantMonitor().NotifyAll(); UpdateReadyState(); - if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING) { - if (!IsPlaying()) { - StartPlayback(); - } + if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING && + !IsPlaying()) + { + StartPlayback(); + StartAudioThread(); } } break; @@ -1302,7 +1328,9 @@ nsresult nsBuiltinDecoderStateMachine::Run() case DECODER_STATE_COMPLETED: { - if (NS_FAILED(StartDecodeThreads())) { + StopDecodeThread(); + + if (NS_FAILED(StartAudioThread())) { continue; } @@ -1325,8 +1353,7 @@ nsresult nsBuiltinDecoderStateMachine::Run() if (mState != DECODER_STATE_COMPLETED) continue; - LOG(PR_LOG_DEBUG, ("%p Shutting down the state machine thread", mDecoder)); - StopDecodeThreads(); + StopAudioThread(); if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING) { PRInt64 videoTime = HasVideo() ? mVideoFrameEndTime : 0; @@ -1343,6 +1370,7 @@ nsresult nsBuiltinDecoderStateMachine::Run() if (mState == DECODER_STATE_COMPLETED) { // We've finished playback. Shutdown the state machine thread, // in order to save memory on thread stacks, particuarly on Linux. + LOG(PR_LOG_DEBUG, ("%p Shutting down the state machine thread", mDecoder)); nsCOMPtr event = new ShutdownThreadEvent(mDecoder->mStateMachineThread); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); @@ -1473,6 +1501,7 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame() // Start playing now if need be. if (!IsPlaying()) { StartPlayback(); + StartAudioThread(); mDecoder->GetReentrantMonitor().NotifyAll(); } diff --git a/content/media/nsBuiltinDecoderStateMachine.h b/content/media/nsBuiltinDecoderStateMachine.h index e78c79f1bee7..738f9828b181 100644 --- a/content/media/nsBuiltinDecoderStateMachine.h +++ b/content/media/nsBuiltinDecoderStateMachine.h @@ -344,13 +344,21 @@ protected: // queued here. Called on the audio thread. 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. - 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. - 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 // an nsRunnableMethod. This continually does blocking writes to @@ -516,9 +524,13 @@ protected: // the media index/metadata. Accessed on the state machine thread. PRPackedBool mGotDurationFromMetaData; - // PR_FALSE while decode threads should be running. Accessed on audio, - // state machine and decode threads. Syncrhonised by decoder monitor. - PRPackedBool mStopDecodeThreads; + // 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; // 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