mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 592833 - Move seeking to the decode thread. r=roc
This commit is contained in:
parent
863da21429
commit
7da896cb74
@ -192,6 +192,7 @@ nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDe
|
||||
mAudioCompleted(PR_FALSE),
|
||||
mGotDurationFromMetaData(PR_FALSE),
|
||||
mStopDecodeThread(PR_TRUE),
|
||||
mDecodeThreadIdle(PR_FALSE),
|
||||
mStopAudioThread(PR_TRUE),
|
||||
mQuickBuffering(PR_FALSE),
|
||||
mEventManager(aDecoder)
|
||||
@ -232,8 +233,36 @@ PRInt64 nsBuiltinDecoderStateMachine::GetDecodedAudioDuration() {
|
||||
return audioDecoded;
|
||||
}
|
||||
|
||||
void nsBuiltinDecoderStateMachine::DecodeThreadRun()
|
||||
{
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
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.");
|
||||
LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
|
||||
}
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
}
|
||||
|
||||
while (mState != DECODER_STATE_SHUTDOWN && mState != DECODER_STATE_COMPLETED) {
|
||||
if (mState == DECODER_STATE_DECODING || mState == DECODER_STATE_BUFFERING) {
|
||||
DecodeLoop();
|
||||
} else if (mState == DECODER_STATE_SEEKING) {
|
||||
DecodeSeek();
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
mDecodeThreadIdle = PR_TRUE;
|
||||
LOG(PR_LOG_DEBUG, ("%p Decode thread finished", mDecoder));
|
||||
}
|
||||
|
||||
void nsBuiltinDecoderStateMachine::DecodeLoop()
|
||||
{
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
|
||||
// We want to "pump" the decode until we've got a few frames/samples decoded
|
||||
@ -268,19 +297,10 @@ void nsBuiltinDecoderStateMachine::DecodeLoop()
|
||||
MediaQueue<VideoData>& videoQueue = mReader->mVideoQueue;
|
||||
MediaQueue<SoundData>& audioQueue = mReader->mAudioQueue;
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
if (mState == DECODER_STATE_DECODING_METADATA) {
|
||||
if (NS_FAILED(DecodeMetadata())) {
|
||||
LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
|
||||
}
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
}
|
||||
|
||||
// Main decode loop.
|
||||
PRBool videoPlaying = HasVideo();
|
||||
PRBool audioPlaying = HasAudio();
|
||||
while (mState != DECODER_STATE_SHUTDOWN &&
|
||||
while ((mState == DECODER_STATE_DECODING || mState == DECODER_STATE_BUFFERING) &&
|
||||
!mStopDecodeThread &&
|
||||
(videoPlaying || audioPlaying))
|
||||
{
|
||||
@ -364,7 +384,7 @@ void nsBuiltinDecoderStateMachine::DecodeLoop()
|
||||
// ready state, so that DOM events can fire.
|
||||
UpdateReadyState();
|
||||
|
||||
if (mState != DECODER_STATE_SHUTDOWN &&
|
||||
if ((mState == DECODER_STATE_DECODING || mState == DECODER_STATE_BUFFERING) &&
|
||||
!mStopDecodeThread &&
|
||||
(videoPlaying || audioPlaying) &&
|
||||
(!audioPlaying || (GetDecodedAudioDuration() >= ampleAudioThreshold &&
|
||||
@ -382,7 +402,7 @@ void nsBuiltinDecoderStateMachine::DecodeLoop()
|
||||
// monitor which will wake us up shortly after we sleep, thus preventing
|
||||
// both the decode and audio push threads waiting at the same time.
|
||||
// See bug 620326.
|
||||
mon.Wait();
|
||||
mDecoder->GetReentrantMonitor().Wait();
|
||||
}
|
||||
|
||||
} // End decode loop.
|
||||
@ -395,7 +415,7 @@ void nsBuiltinDecoderStateMachine::DecodeLoop()
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
}
|
||||
|
||||
LOG(PR_LOG_DEBUG, ("%p Shutting down DecodeLoop this=%p", mDecoder, this));
|
||||
LOG(PR_LOG_DEBUG, ("%p Exiting DecodeLoop", mDecoder));
|
||||
}
|
||||
|
||||
PRBool nsBuiltinDecoderStateMachine::IsPlaying()
|
||||
@ -676,7 +696,7 @@ nsresult nsBuiltinDecoderStateMachine::Init(nsDecoderStateMachine* aCloneDonor)
|
||||
|
||||
void nsBuiltinDecoderStateMachine::StopPlayback(eStopMode aMode)
|
||||
{
|
||||
NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread),
|
||||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine thread.");
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
|
||||
@ -708,7 +728,7 @@ void nsBuiltinDecoderStateMachine::StopPlayback(eStopMode aMode)
|
||||
|
||||
void nsBuiltinDecoderStateMachine::StartPlayback()
|
||||
{
|
||||
NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread),
|
||||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine thread.");
|
||||
NS_ASSERTION(!IsPlaying(), "Shouldn't be playing when StartPlayback() is called");
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
@ -739,7 +759,7 @@ void nsBuiltinDecoderStateMachine::StartPlayback()
|
||||
|
||||
void nsBuiltinDecoderStateMachine::UpdatePlaybackPositionInternal(PRInt64 aTime)
|
||||
{
|
||||
NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread),
|
||||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine thread.");
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
|
||||
@ -892,8 +912,7 @@ void nsBuiltinDecoderStateMachine::Play()
|
||||
|
||||
void nsBuiltinDecoderStateMachine::ResetPlayback()
|
||||
{
|
||||
NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread),
|
||||
"Should be on state machine thread.");
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
mVideoFrameEndTime = -1;
|
||||
mAudioStartTime = -1;
|
||||
mAudioEndTime = -1;
|
||||
@ -931,7 +950,7 @@ void nsBuiltinDecoderStateMachine::Seek(double aTime)
|
||||
|
||||
void nsBuiltinDecoderStateMachine::StopDecodeThread()
|
||||
{
|
||||
NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread),
|
||||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine thread.");
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
mStopDecodeThread = PR_TRUE;
|
||||
@ -943,12 +962,13 @@ void nsBuiltinDecoderStateMachine::StopDecodeThread()
|
||||
mDecodeThread->Shutdown();
|
||||
}
|
||||
mDecodeThread = nsnull;
|
||||
mDecodeThreadIdle = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void nsBuiltinDecoderStateMachine::StopAudioThread()
|
||||
{
|
||||
NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread),
|
||||
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
|
||||
"Should be on state machine thread.");
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
mStopAudioThread = PR_TRUE;
|
||||
@ -970,16 +990,20 @@ nsBuiltinDecoderStateMachine::StartDecodeThread()
|
||||
"Should be on state machine thread.");
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
mStopDecodeThread = PR_FALSE;
|
||||
if (!mDecodeThread && mState < DECODER_STATE_COMPLETED) {
|
||||
if ((mDecodeThread && !mDecodeThreadIdle) || mState >= DECODER_STATE_COMPLETED)
|
||||
return NS_OK;
|
||||
|
||||
if (!mDecodeThread) {
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread));
|
||||
if (NS_FAILED(rv)) {
|
||||
mState = DECODER_STATE_SHUTDOWN;
|
||||
return rv;
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeLoop);
|
||||
mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeThreadRun);
|
||||
mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
mDecodeThreadIdle = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1079,6 +1103,8 @@ nsresult nsBuiltinDecoderStateMachine::DecodeMetadata()
|
||||
{
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
NS_ASSERTION(mState == DECODER_STATE_DECODING_METADATA,
|
||||
"Only call when in metadata decoding state");
|
||||
|
||||
LOG(PR_LOG_DEBUG, ("%p Decoding Media Headers", mDecoder));
|
||||
nsresult res;
|
||||
@ -1141,6 +1167,119 @@ nsresult nsBuiltinDecoderStateMachine::DecodeMetadata()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsBuiltinDecoderStateMachine::DecodeSeek()
|
||||
{
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
NS_ASSERTION(mState == DECODER_STATE_SEEKING,
|
||||
"Only call when in seeking state");
|
||||
|
||||
// During the seek, don't have a lock on the decoder state,
|
||||
// otherwise long seek operations can block the main thread.
|
||||
// The events dispatched to the main thread are SYNC calls.
|
||||
// These calls are made outside of the decode monitor lock so
|
||||
// it is safe for the main thread to makes calls that acquire
|
||||
// the lock since it won't deadlock. We check the state when
|
||||
// acquiring the lock again in case shutdown has occurred
|
||||
// during the time when we didn't have the lock.
|
||||
PRInt64 seekTime = mSeekTime;
|
||||
mDecoder->StopProgressUpdates();
|
||||
|
||||
PRBool currentTimeChanged = false;
|
||||
PRInt64 mediaTime = GetMediaTime();
|
||||
if (mediaTime != seekTime) {
|
||||
currentTimeChanged = true;
|
||||
UpdatePlaybackPositionInternal(seekTime);
|
||||
}
|
||||
|
||||
// SeekingStarted will do a UpdateReadyStateForData which will
|
||||
// inform the element and its users that we have no frames
|
||||
// to display
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
nsCOMPtr<nsIRunnable> startEvent =
|
||||
NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::SeekingStarted);
|
||||
NS_DispatchToMainThread(startEvent, NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
if (currentTimeChanged) {
|
||||
// The seek target is different than the current playback position,
|
||||
// we'll need to seek the playback position, so shutdown our decode
|
||||
// and audio threads.
|
||||
StopPlayback(AUDIO_SHUTDOWN);
|
||||
StopAudioThread();
|
||||
ResetPlayback();
|
||||
nsresult res;
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
// Now perform the seek. We must not hold the state machine monitor
|
||||
// while we seek, since the seek decodes.
|
||||
res = mReader->Seek(seekTime,
|
||||
mStartTime,
|
||||
mEndTime,
|
||||
mediaTime);
|
||||
}
|
||||
if (NS_SUCCEEDED(res)){
|
||||
SoundData* audio = HasAudio() ? mReader->mAudioQueue.PeekFront() : nsnull;
|
||||
NS_ASSERTION(!audio || (audio->mTime <= seekTime &&
|
||||
seekTime <= audio->mTime + audio->mDuration),
|
||||
"Seek target should lie inside the first audio block after seek");
|
||||
PRInt64 startTime = (audio && audio->mTime < seekTime) ? audio->mTime : seekTime;
|
||||
mAudioStartTime = startTime;
|
||||
mPlayDuration = startTime - mStartTime;
|
||||
if (HasVideo()) {
|
||||
nsAutoPtr<VideoData> video(mReader->mVideoQueue.PeekFront());
|
||||
if (video) {
|
||||
NS_ASSERTION(video->mTime <= seekTime && seekTime <= video->mEndTime,
|
||||
"Seek target should lie inside the first frame after seek");
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
RenderVideoFrame(video, TimeStamp::Now());
|
||||
}
|
||||
mReader->mVideoQueue.PopFront();
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::Invalidate);
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mDecoder->StartProgressUpdates();
|
||||
if (mState == DECODER_STATE_SHUTDOWN)
|
||||
return;
|
||||
|
||||
// Try to decode another frame to detect if we're at the end...
|
||||
LOG(PR_LOG_DEBUG, ("Seek completed, mCurrentFrameTime=%lld\n", mCurrentFrameTime));
|
||||
|
||||
// Change state to DECODING or COMPLETED now. SeekingStopped will
|
||||
// call nsBuiltinDecoderStateMachine::Seek to reset our state to SEEKING
|
||||
// if we need to seek again.
|
||||
|
||||
nsCOMPtr<nsIRunnable> stopEvent;
|
||||
if (GetMediaTime() == mEndTime) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to COMPLETED",
|
||||
mDecoder, seekTime));
|
||||
stopEvent = NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::SeekingStoppedAtEnd);
|
||||
mState = DECODER_STATE_COMPLETED;
|
||||
} else {
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to DECODING",
|
||||
mDecoder, seekTime));
|
||||
stopEvent = NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::SeekingStopped);
|
||||
StartDecoding();
|
||||
}
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
NS_DispatchToMainThread(stopEvent, NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
// Reset quick buffering status. This ensures that if we began the
|
||||
// seek while quick-buffering, we won't bypass quick buffering mode
|
||||
// if we need to buffer after the seek.
|
||||
mQuickBuffering = PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult nsBuiltinDecoderStateMachine::Run()
|
||||
{
|
||||
NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread),
|
||||
@ -1198,111 +1337,15 @@ nsresult nsBuiltinDecoderStateMachine::Run()
|
||||
|
||||
case DECODER_STATE_SEEKING:
|
||||
{
|
||||
// During the seek, don't have a lock on the decoder state,
|
||||
// otherwise long seek operations can block the main thread.
|
||||
// The events dispatched to the main thread are SYNC calls.
|
||||
// These calls are made outside of the decode monitor lock so
|
||||
// it is safe for the main thread to makes calls that acquire
|
||||
// the lock since it won't deadlock. We check the state when
|
||||
// acquiring the lock again in case shutdown has occurred
|
||||
// during the time when we didn't have the lock.
|
||||
PRInt64 seekTime = mSeekTime;
|
||||
mDecoder->StopProgressUpdates();
|
||||
|
||||
PRBool currentTimeChanged = false;
|
||||
PRInt64 mediaTime = GetMediaTime();
|
||||
if (mediaTime != seekTime) {
|
||||
currentTimeChanged = true;
|
||||
UpdatePlaybackPositionInternal(seekTime);
|
||||
}
|
||||
|
||||
// SeekingStarted will do a UpdateReadyStateForData which will
|
||||
// inform the element and its users that we have no frames
|
||||
// to display
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
nsCOMPtr<nsIRunnable> startEvent =
|
||||
NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::SeekingStarted);
|
||||
NS_DispatchToMainThread(startEvent, NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
if (currentTimeChanged) {
|
||||
// The seek target is different than the current playback position,
|
||||
// we'll need to seek the playback position, so shutdown our decode
|
||||
// and audio threads.
|
||||
StopPlayback(AUDIO_SHUTDOWN);
|
||||
StopDecodeThread();
|
||||
StopAudioThread();
|
||||
ResetPlayback();
|
||||
nsresult res;
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
// Now perform the seek. We must not hold the state machine monitor
|
||||
// while we seek, since the seek decodes.
|
||||
res = mReader->Seek(seekTime,
|
||||
mStartTime,
|
||||
mEndTime,
|
||||
mediaTime);
|
||||
}
|
||||
if (NS_SUCCEEDED(res)){
|
||||
SoundData* audio = HasAudio() ? mReader->mAudioQueue.PeekFront() : nsnull;
|
||||
NS_ASSERTION(!audio || (audio->mTime <= seekTime &&
|
||||
seekTime <= audio->mTime + audio->mDuration),
|
||||
"Seek target should lie inside the first audio block after seek");
|
||||
PRInt64 startTime = (audio && audio->mTime < seekTime) ? audio->mTime : seekTime;
|
||||
mAudioStartTime = startTime;
|
||||
mPlayDuration = startTime - mStartTime;
|
||||
if (HasVideo()) {
|
||||
nsAutoPtr<VideoData> video(mReader->mVideoQueue.PeekFront());
|
||||
if (video) {
|
||||
NS_ASSERTION(video->mTime <= seekTime && seekTime <= video->mEndTime,
|
||||
"Seek target should lie inside the first frame after seek");
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
RenderVideoFrame(video, TimeStamp::Now());
|
||||
}
|
||||
mReader->mVideoQueue.PopFront();
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::Invalidate);
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mDecoder->StartProgressUpdates();
|
||||
if (mState == DECODER_STATE_SHUTDOWN)
|
||||
// Ensure decode thread is alive and well...
|
||||
if (NS_FAILED(StartDecodeThread())) {
|
||||
continue;
|
||||
|
||||
// Try to decode another frame to detect if we're at the end...
|
||||
LOG(PR_LOG_DEBUG, ("%p Seek completed, mCurrentFrameTime=%lld\n", mDecoder, mCurrentFrameTime));
|
||||
|
||||
// Change state to DECODING or COMPLETED now. SeekingStopped will
|
||||
// call nsBuiltinDecoderStateMachine::Seek to reset our state to SEEKING
|
||||
// if we need to seek again.
|
||||
|
||||
nsCOMPtr<nsIRunnable> stopEvent;
|
||||
if (GetMediaTime() == mEndTime) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to COMPLETED",
|
||||
mDecoder, seekTime));
|
||||
stopEvent = NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::SeekingStoppedAtEnd);
|
||||
mState = DECODER_STATE_COMPLETED;
|
||||
} else {
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to DECODING",
|
||||
mDecoder, seekTime));
|
||||
stopEvent = NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::SeekingStopped);
|
||||
StartDecoding();
|
||||
}
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
NS_DispatchToMainThread(stopEvent, NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
// Reset quick buffering status. This ensures that if we began the
|
||||
// seek while quick-buffering, we won't bypass quick buffering mode
|
||||
// if we need to buffer after the seek.
|
||||
mQuickBuffering = PR_FALSE;
|
||||
// Wait until seeking finishes...
|
||||
while (mState == DECODER_STATE_SEEKING) {
|
||||
mon.Wait();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -217,9 +217,6 @@ public:
|
||||
return mDecoder->OnStateMachineThread();
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -291,8 +288,7 @@ protected:
|
||||
// Dispatches an asynchronous event to update the media element's ready state.
|
||||
void UpdateReadyState();
|
||||
|
||||
// Resets playback timing data. Called when we seek, on the state machine
|
||||
// thread.
|
||||
// Resets playback timing data. Called when we seek, on the decode thread.
|
||||
void ResetPlayback();
|
||||
|
||||
// Returns the audio clock, if we have audio, or -1 if we don't.
|
||||
@ -410,6 +406,18 @@ protected:
|
||||
// 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();
|
||||
|
||||
// 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
|
||||
@ -527,6 +535,13 @@ protected:
|
||||
// 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;
|
||||
|
@ -403,8 +403,7 @@ nsresult nsOggReader::DecodeVorbis(ogg_packet* aPacket) {
|
||||
PRBool nsOggReader::DecodeAudioData()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on playback or decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
NS_ASSERTION(mVorbisState!=0, "Need Vorbis state to decode audio");
|
||||
|
||||
// Read the next data packet. Skip any non-data packets we encounter.
|
||||
@ -507,8 +506,7 @@ PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
|
||||
PRInt64 aTimeThreshold)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on state machine or AV thread.");
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
|
||||
// Record number of frames decoded and parsed. Automatically update the
|
||||
// stats counters using the AutoNotifyDecoded stack-based class.
|
||||
@ -557,8 +555,7 @@ PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
|
||||
|
||||
PRInt64 nsOggReader::ReadOggPage(ogg_page* aPage)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on play state machine or decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
mReentrantMonitor.AssertCurrentThreadIn();
|
||||
|
||||
int ret = 0;
|
||||
@ -597,8 +594,7 @@ PRInt64 nsOggReader::ReadOggPage(ogg_page* aPage)
|
||||
|
||||
ogg_packet* nsOggReader::NextOggPacket(nsOggCodecState* aCodecState)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
|
||||
"Should be on play state machine or decode thread.");
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
mReentrantMonitor.AssertCurrentThreadIn();
|
||||
|
||||
if (!aCodecState || !aCodecState->mActive) {
|
||||
@ -797,8 +793,7 @@ PRInt64 nsOggReader::RangeEndTime(PRInt64 aStartOffset,
|
||||
|
||||
nsresult nsOggReader::GetSeekRanges(nsTArray<SeekRange>& aRanges)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
mReentrantMonitor.AssertCurrentThreadIn();
|
||||
nsTArray<nsByteRange> cached;
|
||||
nsresult res = mDecoder->GetCurrentStream()->GetCachedRanges(cached);
|
||||
@ -838,8 +833,7 @@ nsOggReader::SelectSeekRange(const nsTArray<SeekRange>& ranges,
|
||||
PRInt64 aEndTime,
|
||||
PRBool aExact)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
PRInt64 so = 0;
|
||||
PRInt64 eo = mDecoder->GetCurrentStream()->GetLength();
|
||||
PRInt64 st = aStartTime;
|
||||
@ -1053,8 +1047,7 @@ nsresult nsOggReader::Seek(PRInt64 aTarget,
|
||||
PRInt64 aCurrentTime)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
LOG(PR_LOG_DEBUG, ("%p About to seek to %lldms", mDecoder, aTarget));
|
||||
nsresult res;
|
||||
nsMediaStream* stream = mDecoder->GetCurrentStream();
|
||||
@ -1183,8 +1176,7 @@ nsresult nsOggReader::SeekBisection(PRInt64 aTarget,
|
||||
const SeekRange& aRange,
|
||||
PRUint32 aFuzz)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
nsresult res;
|
||||
nsMediaStream* stream = mDecoder->GetCurrentStream();
|
||||
|
||||
|
@ -123,7 +123,6 @@ 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.
|
||||
|
@ -256,8 +256,7 @@ PRBool nsWaveReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
|
||||
nsresult nsWaveReader::Seek(PRInt64 aTarget, PRInt64 aStartTime, PRInt64 aEndTime, PRInt64 aCurrentTime)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
"Should be on state machine thread.");
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
LOG(PR_LOG_DEBUG, ("%p About to seek to %lld", mDecoder, aTarget));
|
||||
if (NS_FAILED(ResetDecode())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -768,7 +768,7 @@ nsresult nsWebMReader::Seek(PRInt64 aTarget, PRInt64 aStartTime, PRInt64 aEndTim
|
||||
PRInt64 aCurrentTime)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoder->OnStateMachineThread(),
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(),
|
||||
"Should be on state machine thread.");
|
||||
LOG(PR_LOG_DEBUG, ("%p About to seek to %lldms", mDecoder, aTarget));
|
||||
if (CanDecodeToTarget(aTarget, aCurrentTime)) {
|
||||
|
Loading…
Reference in New Issue
Block a user