зеркало из https://github.com/mozilla/gecko-dev.git
Bug 973408 - Split DecodeThreadRun() into separate decode tasks. r=kinetik
This commit is contained in:
Родитель
2634dbcd59
Коммит
3c12cc7501
|
@ -270,57 +270,6 @@ int64_t MediaDecoderStateMachine::GetDecodedAudioDuration() {
|
|||
return audioDecoded;
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::DecodeThreadRun()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
if (mReader) {
|
||||
mReader->OnDecodeThreadStart();
|
||||
}
|
||||
|
||||
if (mState == DECODER_STATE_DECODING_METADATA &&
|
||||
NS_FAILED(DecodeMetadata())) {
|
||||
NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
|
||||
"Should be in shutdown state if metadata loading fails.");
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
|
||||
}
|
||||
|
||||
while (mState != DECODER_STATE_SHUTDOWN &&
|
||||
mState != DECODER_STATE_COMPLETED &&
|
||||
mState != DECODER_STATE_DORMANT &&
|
||||
!mStopDecodeThread)
|
||||
{
|
||||
if (mState == DECODER_STATE_DECODING || mState == DECODER_STATE_BUFFERING) {
|
||||
DecodeLoop();
|
||||
} else if (mState == DECODER_STATE_SEEKING) {
|
||||
DecodeSeek();
|
||||
} else if (mState == DECODER_STATE_DECODING_METADATA) {
|
||||
if (NS_FAILED(DecodeMetadata())) {
|
||||
NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
|
||||
"Should be in shutdown state if metadata loading fails.");
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
|
||||
}
|
||||
} else if (mState == DECODER_STATE_WAIT_FOR_RESOURCES) {
|
||||
mDecoder->GetReentrantMonitor().Wait();
|
||||
|
||||
if (!mReader->IsWaitingMediaResources()) {
|
||||
// change state to DECODER_STATE_WAIT_FOR_RESOURCES
|
||||
StartDecodeMetadata();
|
||||
}
|
||||
} else if (mState == DECODER_STATE_DORMANT) {
|
||||
mDecoder->GetReentrantMonitor().Wait();
|
||||
}
|
||||
}
|
||||
|
||||
if (mReader) {
|
||||
mReader->OnDecodeThreadFinish();
|
||||
}
|
||||
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decode thread finished", mDecoder.get()));
|
||||
mDispatchedEventToDecode = false;
|
||||
mon.NotifyAll();
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
|
||||
DecodedStreamData* aStream,
|
||||
AudioSegment* aOutput)
|
||||
|
@ -596,13 +545,18 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
|
|||
|
||||
void MediaDecoderStateMachine::DecodeLoop()
|
||||
{
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Start DecodeLoop()", mDecoder.get()));
|
||||
|
||||
AssertCurrentThreadInMonitor();
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
|
||||
mIsAudioPrerolling = true;
|
||||
mIsVideoPrerolling = true;
|
||||
if ((mState != DECODER_STATE_DECODING && mState != DECODER_STATE_BUFFERING) ||
|
||||
mStopDecodeThread) {
|
||||
return;
|
||||
}
|
||||
|
||||
// At least one of our streams should still need decoding.
|
||||
MOZ_ASSERT(mIsVideoDecoding || mIsAudioDecoding);
|
||||
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Start DecodeLoop()", mDecoder.get()));
|
||||
|
||||
// Main decode loop.
|
||||
while ((mState == DECODER_STATE_DECODING || mState == DECODER_STATE_BUFFERING) &&
|
||||
|
@ -746,6 +700,8 @@ void MediaDecoderStateMachine::DecodeLoop()
|
|||
ScheduleStateMachine();
|
||||
}
|
||||
|
||||
mDispatchedEventToDecode = false;
|
||||
mon.NotifyAll();
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Exiting DecodeLoop", mDecoder.get()));
|
||||
}
|
||||
|
||||
|
@ -1345,17 +1301,22 @@ void MediaDecoderStateMachine::StartDecoding()
|
|||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine or decode thread.");
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (mState != DECODER_STATE_DECODING) {
|
||||
mDecodeStartTime = TimeStamp::Now();
|
||||
if (mState == DECODER_STATE_DECODING) {
|
||||
return;
|
||||
}
|
||||
mState = DECODER_STATE_DECODING;
|
||||
|
||||
mDecodeStartTime = TimeStamp::Now();
|
||||
|
||||
// Reset our "stream finished decoding" flags, so we try to decode all
|
||||
// streams that we have when we start decoding.
|
||||
mIsVideoDecoding = HasVideo();
|
||||
mIsAudioDecoding = HasAudio();
|
||||
|
||||
// Reset other state to pristine values before starting decode.
|
||||
mSkipToNextKeyFrame = false;
|
||||
mIsAudioPrerolling = true;
|
||||
mIsVideoPrerolling = true;
|
||||
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
|
@ -1368,14 +1329,6 @@ void MediaDecoderStateMachine::StartWaitForResources()
|
|||
mState = DECODER_STATE_WAIT_FOR_RESOURCES;
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::StartDecodeMetadata()
|
||||
{
|
||||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine or decode thread.");
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mState = DECODER_STATE_DECODING_METADATA;
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::Play()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
|
@ -1502,7 +1455,42 @@ void MediaDecoderStateMachine::StopAudioThread()
|
|||
}
|
||||
|
||||
nsresult
|
||||
MediaDecoderStateMachine::ScheduleDecodeThread()
|
||||
MediaDecoderStateMachine::EnqueueDecodeMetadataTask()
|
||||
{
|
||||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine or decode thread.");
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
if (mState != DECODER_STATE_DECODING_METADATA) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeMetadata));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaDecoderStateMachine::EnqueueDecodeSeekTask()
|
||||
{
|
||||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine or decode thread.");
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
if (mState != DECODER_STATE_SEEKING) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeSeek));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
MediaDecoderStateMachine::EnqueueDecodeTask()
|
||||
{
|
||||
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
@ -1513,7 +1501,7 @@ MediaDecoderStateMachine::ScheduleDecodeThread()
|
|||
}
|
||||
if (!mDispatchedEventToDecode) {
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeThreadRun));
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeLoop));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mDispatchedEventToDecode = true;
|
||||
}
|
||||
|
@ -1614,14 +1602,43 @@ void MediaDecoderStateMachine::SetFrameBufferLength(uint32_t aLength)
|
|||
mEventManager.SetSignalBufferLength(aLength);
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::CallDecodeMetadata()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
if (mState != DECODER_STATE_DECODING_METADATA) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_FAILED(DecodeMetadata())) {
|
||||
NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
|
||||
"Should be in shutdown state if metadata loading fails.");
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decoder"));
|
||||
|
||||
// Dispatch the event to call DecodeError synchronously. This ensures
|
||||
// we're in shutdown state by the time we exit the decode thread.
|
||||
// If we just moved to shutdown state here on the decode thread, we may
|
||||
// cause the state machine to shutdown/free memory without closing its
|
||||
// media stream properly, and we'll get callbacks from the media stream
|
||||
// causing a crash.
|
||||
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(mDecoder, &MediaDecoder::DecodeError);
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult MediaDecoderStateMachine::DecodeMetadata()
|
||||
{
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
AssertCurrentThreadInMonitor();
|
||||
NS_ASSERTION(mState == DECODER_STATE_DECODING_METADATA,
|
||||
"Only call when in metadata decoding state");
|
||||
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
DECODER_LOG(PR_LOG_DEBUG, ("%p Decoding Media Headers", mDecoder.get()));
|
||||
if (mState != DECODER_STATE_DECODING_METADATA) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult res;
|
||||
MediaInfo info;
|
||||
MetadataTags* tags;
|
||||
|
@ -1629,7 +1646,9 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
|
|||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
res = mReader->ReadMetadata(&info, &tags);
|
||||
}
|
||||
if (NS_SUCCEEDED(res) && (mState == DECODER_STATE_DECODING_METADATA) && (mReader->IsWaitingMediaResources())) {
|
||||
if (NS_SUCCEEDED(res) &&
|
||||
mState == DECODER_STATE_DECODING_METADATA &&
|
||||
mReader->IsWaitingMediaResources()) {
|
||||
// change state to DECODER_STATE_WAIT_FOR_RESOURCES
|
||||
StartWaitForResources();
|
||||
return NS_OK;
|
||||
|
@ -1638,19 +1657,6 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
|
|||
mInfo = info;
|
||||
|
||||
if (NS_FAILED(res) || (!info.HasValidMedia())) {
|
||||
// Dispatch the event to call DecodeError synchronously. This ensures
|
||||
// we're in shutdown state by the time we exit the decode thread.
|
||||
// If we just moved to shutdown state here on the decode thread, we may
|
||||
// cause the state machine to shutdown/free memory without closing its
|
||||
// media stream properly, and we'll get callbacks from the media stream
|
||||
// causing a crash. Note the state machine shutdown joins this decode
|
||||
// thread during shutdown (and other state machines can run on the state
|
||||
// machine thread while the join is waiting), so it's safe to do this
|
||||
// synchronously.
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(mDecoder, &MediaDecoder::DecodeError);
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mDecoder->StartProgressUpdates();
|
||||
|
@ -1716,10 +1722,11 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
|
|||
|
||||
void MediaDecoderStateMachine::DecodeSeek()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
AssertCurrentThreadInMonitor();
|
||||
NS_ASSERTION(mState == DECODER_STATE_SEEKING,
|
||||
"Only call when in seeking state");
|
||||
if (mState != DECODER_STATE_SEEKING) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDidThrottleAudioDecoding = false;
|
||||
mDidThrottleVideoDecoding = false;
|
||||
|
@ -1958,7 +1965,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
|
||||
case DECODER_STATE_DECODING_METADATA: {
|
||||
// Ensure we have a decode thread to decode metadata.
|
||||
return ScheduleDecodeThread();
|
||||
return EnqueueDecodeMetadataTask();
|
||||
}
|
||||
|
||||
case DECODER_STATE_DECODING: {
|
||||
|
@ -1989,7 +1996,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
|
||||
// We're playing and/or our decode buffers aren't full. Ensure we have
|
||||
// an active decode thread.
|
||||
if (NS_FAILED(ScheduleDecodeThread())) {
|
||||
if (NS_FAILED(EnqueueDecodeTask())) {
|
||||
NS_WARNING("Failed to start media decode thread!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -2054,7 +2061,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
|
||||
case DECODER_STATE_SEEKING: {
|
||||
// Ensure we have a decode thread to perform the seek.
|
||||
return ScheduleDecodeThread();
|
||||
return EnqueueDecodeSeekTask();
|
||||
}
|
||||
|
||||
case DECODER_STATE_COMPLETED: {
|
||||
|
|
|
@ -499,12 +499,6 @@ private:
|
|||
// one lock count. Called on the state machine thread.
|
||||
void StopAudioThread();
|
||||
|
||||
// Ensures the decode thread is running if it already exists, or requests
|
||||
// a new decode thread be started if there currently is no decode thread.
|
||||
// The decoder monitor must be held with exactly one lock count. Called on
|
||||
// the state machine thread.
|
||||
nsresult ScheduleDecodeThread();
|
||||
|
||||
// Starts the audio thread. The decoder monitor must be held with exactly
|
||||
// one lock count. Called on the state machine thread.
|
||||
nsresult StartAudioThread();
|
||||
|
@ -528,7 +522,20 @@ private:
|
|||
|
||||
void StartWaitForResources();
|
||||
|
||||
void StartDecodeMetadata();
|
||||
// Dispatches a task to the decode task queue to begin decoding metadata.
|
||||
// This is called on the state machine or decode threads.
|
||||
// The decoder monitor must be held.
|
||||
nsresult EnqueueDecodeMetadataTask();
|
||||
|
||||
// Dispatches a task to the decode task queue to run the decode loop.
|
||||
// This is called on the state machine or decode threads.
|
||||
// The decoder monitor must be held.
|
||||
nsresult EnqueueDecodeTask();
|
||||
|
||||
// Dispatches a task to the decode task queue to seek the decoder.
|
||||
// This is called on the state machine or decode threads.
|
||||
// The decoder monitor must be held.
|
||||
nsresult EnqueueDecodeSeekTask();
|
||||
|
||||
// Returns the "media time". This is the absolute time which the media
|
||||
// playback has reached. i.e. this returns values in the range
|
||||
|
@ -561,9 +568,7 @@ private:
|
|||
// Called on the decode thread.
|
||||
void DecodeLoop();
|
||||
|
||||
// Decode thread run function. Determines which of the Decode*() functions
|
||||
// to call.
|
||||
void DecodeThreadRun();
|
||||
void CallDecodeMetadata();
|
||||
|
||||
// Copy audio from an AudioData packet to aOutput. This may require
|
||||
// inserting silence depending on the timing of the audio packet.
|
||||
|
|
Загрузка…
Ссылка в новой задаче