Bug 499874 - If decoding finishes when seeking to end of media, don't attempt to decode additional frames. Fixes a hang caused by violating oggplay's assumptions. r=roc

--HG--
extra : rebase_source : b8510182821e4babf667b0ff7d63060a82535c7c
This commit is contained in:
Matthew Gregan 2009-10-20 16:18:18 +13:00
Родитель e346510322
Коммит 8bd8cb870d
1 изменённых файлов: 32 добавлений и 24 удалений

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

@ -397,8 +397,8 @@ protected:
// Decodes from the current position until encountering a frame with time
// greater or equal to aSeekTime.
void DecodeToFrame(nsAutoMonitor& aMonitor,
float aSeekTime);
PRBool DecodeToFrame(nsAutoMonitor& aMonitor,
float aSeekTime);
// Convert the OggPlay frame information into a format used by Gecko
// (RGB for video, float for sound, etc).The decoder monitor must be
@ -1315,8 +1315,8 @@ nsresult nsOggDecodeStateMachine::Seek(float aTime, nsChannelReader* aReader)
return (rv < 0) ? NS_ERROR_FAILURE : NS_OK;
}
void nsOggDecodeStateMachine::DecodeToFrame(nsAutoMonitor& aMonitor,
float aTime)
PRBool nsOggDecodeStateMachine::DecodeToFrame(nsAutoMonitor& aMonitor,
float aTime)
{
// Drop frames before the target time.
float target = aTime - mCallbackPeriod / 2.0;
@ -1356,7 +1356,7 @@ void nsOggDecodeStateMachine::DecodeToFrame(nsAutoMonitor& aMonitor,
if (mState == DECODER_STATE_SHUTDOWN) {
delete frame;
return;
return PR_TRUE;
}
NS_ASSERTION(frame != nsnull, "No frame after decode!");
@ -1380,6 +1380,8 @@ void nsOggDecodeStateMachine::DecodeToFrame(nsAutoMonitor& aMonitor,
UpdatePlaybackPosition(frame->mDecodedFrameTime);
PlayVideo(frame);
}
return r == E_OGGPLAY_OK;
}
void nsOggDecodeStateMachine::StopStepDecodeThread(nsAutoMonitor* aMonitor)
@ -1411,8 +1413,8 @@ nsresult nsOggDecodeStateMachine::Run()
nsChannelReader* reader = mDecoder->GetReader();
NS_ENSURE_TRUE(reader, NS_ERROR_NULL_POINTER);
while (PR_TRUE) {
nsAutoMonitor mon(mDecoder->GetMonitor());
switch(mState) {
nsAutoMonitor mon(mDecoder->GetMonitor());
switch(mState) {
case DECODER_STATE_SHUTDOWN:
if (mPlaying) {
StopPlayback();
@ -1557,7 +1559,7 @@ nsresult nsOggDecodeStateMachine::Run()
PRPackedBool reliable;
double playbackRate = mDecoder->ComputePlaybackRate(&reliable);
mBufferingEndOffset = mDecoder->mDecoderPosition +
BUFFERING_RATE(playbackRate) * BUFFERING_WAIT;
BUFFERING_RATE(playbackRate) * BUFFERING_WAIT;
mState = DECODER_STATE_BUFFERING;
if (mPlaying) {
PausePlayback();
@ -1621,8 +1623,9 @@ nsresult nsOggDecodeStateMachine::Run()
if (mState == DECODER_STATE_SHUTDOWN)
continue;
PRBool atEnd = PR_FALSE;
if (NS_SUCCEEDED(res)) {
DecodeToFrame(mon, seekTime);
atEnd = DecodeToFrame(mon, seekTime);
// mSeekTime should not have changed. While we seek, mPlayState
// should always be PLAY_STATE_SEEKING and no-one will call
// nsOggDecoderStateMachine::Seek.
@ -1631,29 +1634,34 @@ nsresult nsOggDecodeStateMachine::Run()
continue;
}
OggPlayErrorCode r;
// Now try to decode another frame to see if we're at the end.
do {
mon.Exit();
r = DecodeFrame();
mon.Enter();
} while (mState != DECODER_STATE_SHUTDOWN && r == E_OGGPLAY_TIMEOUT);
HandleDecodeErrors(r);
if (mState == DECODER_STATE_SHUTDOWN)
continue;
if (!atEnd) {
OggPlayErrorCode r;
// Now try to decode another frame to see if we're at the end.
do {
mon.Exit();
r = DecodeFrame();
mon.Enter();
} while (mState != DECODER_STATE_SHUTDOWN && r == E_OGGPLAY_TIMEOUT);
HandleDecodeErrors(r);
if (mState == DECODER_STATE_SHUTDOWN)
continue;
atEnd = r == E_OGGPLAY_OK;
}
QueueDecodedFrames();
}
// Change state to DECODING now. SeekingStopped will call
// nsOggDecodeStateMachine::Seek to reset our state to SEEKING
// Change state to DECODING or COMPLETED now. SeekingStopped will
// call nsOggDecodeStateMachine::Seek to reset our state to SEEKING
// if we need to seek again.
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %f) to DECODING", mDecoder, seekTime));
mState = DECODER_STATE_DECODING;
nsCOMPtr<nsIRunnable> stopEvent;
if (mDecodedFrames.GetCount() > 1) {
if (!atEnd && mDecodedFrames.GetCount() > 1) {
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %f) to DECODING",
mDecoder, seekTime));
stopEvent = NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, SeekingStopped);
mState = DECODER_STATE_DECODING;
} else {
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %f) to COMPLETED",
mDecoder, seekTime));
stopEvent = NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, SeekingStoppedAtEnd);
mState = DECODER_STATE_COMPLETED;
}