зеркало из https://github.com/mozilla/gecko-dev.git
Bug 495156 - Video playback gets stuck forever when pressing End key. r=doublec sr=roc a=blocking1.9.1+
This commit is contained in:
Родитель
73e0202e9d
Коммит
0c2e85ab11
|
@ -377,6 +377,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
// Decodes from the current position until encountering a frame with time
|
||||||
|
// greater or equal to aSeekTime.
|
||||||
|
void DecodeToFrame(nsAutoMonitor& aMonitor,
|
||||||
|
float aSeekTime);
|
||||||
|
|
||||||
// Convert the OggPlay frame information into a format used by Gecko
|
// Convert the OggPlay frame information into a format used by Gecko
|
||||||
// (RGB for video, float for sound, etc).The decoder monitor must be
|
// (RGB for video, float for sound, etc).The decoder monitor must be
|
||||||
// acquired in the scope of calls to these functions. They must be
|
// acquired in the scope of calls to these functions. They must be
|
||||||
|
@ -1212,6 +1218,9 @@ void nsOggDecodeStateMachine::Seek(float aTime)
|
||||||
NS_ASSERTION(mState != DECODER_STATE_SEEKING,
|
NS_ASSERTION(mState != DECODER_STATE_SEEKING,
|
||||||
"We shouldn't already be seeking");
|
"We shouldn't already be seeking");
|
||||||
mSeekTime = aTime + mPlaybackStartTime;
|
mSeekTime = aTime + mPlaybackStartTime;
|
||||||
|
float duration = static_cast<float>(mDuration) / 1000.0;
|
||||||
|
NS_ASSERTION(mSeekTime >= 0 && mSeekTime <= duration,
|
||||||
|
"Can only seek in range [0,duration]");
|
||||||
LOG(PR_LOG_DEBUG, ("Changed state to SEEKING (to %f)", aTime));
|
LOG(PR_LOG_DEBUG, ("Changed state to SEEKING (to %f)", aTime));
|
||||||
mState = DECODER_STATE_SEEKING;
|
mState = DECODER_STATE_SEEKING;
|
||||||
}
|
}
|
||||||
|
@ -1297,6 +1306,71 @@ nsresult nsOggDecodeStateMachine::Seek(float aTime, nsChannelReader* aReader)
|
||||||
return (rv < 0) ? NS_ERROR_FAILURE : NS_OK;
|
return (rv < 0) ? NS_ERROR_FAILURE : NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nsOggDecodeStateMachine::DecodeToFrame(nsAutoMonitor& aMonitor,
|
||||||
|
float aTime)
|
||||||
|
{
|
||||||
|
// Drop frames before the target time.
|
||||||
|
float target = aTime - mCallbackPeriod / 2.0;
|
||||||
|
FrameData* frame = nsnull;
|
||||||
|
OggPlayErrorCode r;
|
||||||
|
mLastFrameTime = 0;
|
||||||
|
// Some of the audio data from previous frames actually belongs
|
||||||
|
// to this frame and later frames. So rescue that data and stuff
|
||||||
|
// it into the first frame.
|
||||||
|
float audioTime = 0;
|
||||||
|
nsTArray<float> audioData;
|
||||||
|
do {
|
||||||
|
do {
|
||||||
|
aMonitor.Exit();
|
||||||
|
r = DecodeFrame();
|
||||||
|
aMonitor.Enter();
|
||||||
|
} while (mState != DECODER_STATE_SHUTDOWN && r == E_OGGPLAY_TIMEOUT);
|
||||||
|
|
||||||
|
HandleDecodeErrors(r);
|
||||||
|
|
||||||
|
if (mState == DECODER_STATE_SHUTDOWN)
|
||||||
|
break;
|
||||||
|
|
||||||
|
FrameData* nextFrame = NextFrame();
|
||||||
|
if (!nextFrame)
|
||||||
|
break;
|
||||||
|
|
||||||
|
delete frame;
|
||||||
|
frame = nextFrame;
|
||||||
|
|
||||||
|
audioData.AppendElements(frame->mAudioData);
|
||||||
|
audioTime += frame->mAudioData.Length() /
|
||||||
|
(float)mAudioRate / (float)mAudioChannels;
|
||||||
|
} while (frame->mDecodedFrameTime < target);
|
||||||
|
|
||||||
|
if (mState == DECODER_STATE_SHUTDOWN) {
|
||||||
|
delete frame;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_ASSERTION(frame != nsnull, "No frame after decode!");
|
||||||
|
if (frame) {
|
||||||
|
if (audioTime > frame->mTime) {
|
||||||
|
// liboggplay gave us more data than expected, we need to prepend
|
||||||
|
// the extra data to the current frame to keep audio in sync.
|
||||||
|
audioTime -= frame->mTime;
|
||||||
|
// numExtraSamples must be evenly divisble by number of channels.
|
||||||
|
size_t numExtraSamples = mAudioChannels *
|
||||||
|
PRInt32(NS_ceil(mAudioRate*audioTime));
|
||||||
|
float* data = audioData.Elements() + audioData.Length() - numExtraSamples;
|
||||||
|
float* dst = frame->mAudioData.InsertElementsAt(0, numExtraSamples);
|
||||||
|
memcpy(dst, data, numExtraSamples * sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastFrameTime = 0;
|
||||||
|
frame->mTime = 0;
|
||||||
|
frame->mState = OGGPLAY_STREAM_JUST_SEEKED;
|
||||||
|
mDecodedFrames.Push(frame);
|
||||||
|
UpdatePlaybackPosition(frame->mDecodedFrameTime);
|
||||||
|
PlayVideo(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void nsOggDecodeStateMachine::StopStepDecodeThread(nsAutoMonitor* aMonitor)
|
void nsOggDecodeStateMachine::StopStepDecodeThread(nsAutoMonitor* aMonitor)
|
||||||
{
|
{
|
||||||
PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mDecoder->GetMonitor());
|
PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mDecoder->GetMonitor());
|
||||||
|
@ -1518,7 +1592,7 @@ nsresult nsOggDecodeStateMachine::Run()
|
||||||
NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, SeekingStarted);
|
NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, SeekingStarted);
|
||||||
NS_DispatchToMainThread(startEvent, NS_DISPATCH_SYNC);
|
NS_DispatchToMainThread(startEvent, NS_DISPATCH_SYNC);
|
||||||
|
|
||||||
Seek(seekTime, reader);
|
nsresult res = Seek(seekTime, reader);
|
||||||
|
|
||||||
// Reactivate all tracks. Liboggplay deactivates tracks when it
|
// Reactivate all tracks. Liboggplay deactivates tracks when it
|
||||||
// reads to the end of stream, but they must be reactivated in order
|
// reads to the end of stream, but they must be reactivated in order
|
||||||
|
@ -1531,75 +1605,21 @@ nsresult nsOggDecodeStateMachine::Run()
|
||||||
if (mState == DECODER_STATE_SHUTDOWN)
|
if (mState == DECODER_STATE_SHUTDOWN)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Drop frames before the target seek time.
|
if (NS_SUCCEEDED(res)) {
|
||||||
float seekTarget = seekTime - mCallbackPeriod / 2.0;
|
DecodeToFrame(mon, seekTime);
|
||||||
FrameData* frame = nsnull;
|
// mSeekTime should not have changed. While we seek, mPlayState
|
||||||
OggPlayErrorCode r;
|
// should always be PLAY_STATE_SEEKING and no-one will call
|
||||||
mLastFrameTime = 0;
|
// nsOggDecoderStateMachine::Seek.
|
||||||
// Some of the audio data from previous frames actually belongs
|
NS_ASSERTION(seekTime == mSeekTime, "No-one should have changed mSeekTime");
|
||||||
// to this frame and later frames. So rescue that data and stuff
|
if (mState == DECODER_STATE_SHUTDOWN) {
|
||||||
// it into the first frame.
|
continue;
|
||||||
float audioTime = 0;
|
|
||||||
nsTArray<float> audioData;
|
|
||||||
do {
|
|
||||||
do {
|
|
||||||
mon.Exit();
|
|
||||||
r = DecodeFrame();
|
|
||||||
mon.Enter();
|
|
||||||
} while (mState != DECODER_STATE_SHUTDOWN && r == E_OGGPLAY_TIMEOUT);
|
|
||||||
|
|
||||||
HandleDecodeErrors(r);
|
|
||||||
|
|
||||||
if (mState == DECODER_STATE_SHUTDOWN)
|
|
||||||
break;
|
|
||||||
|
|
||||||
FrameData* nextFrame = NextFrame();
|
|
||||||
if (!nextFrame)
|
|
||||||
break;
|
|
||||||
|
|
||||||
delete frame;
|
|
||||||
frame = nextFrame;
|
|
||||||
|
|
||||||
audioData.AppendElements(frame->mAudioData);
|
|
||||||
audioTime += frame->mAudioData.Length() /
|
|
||||||
(float)mAudioRate / (float)mAudioChannels;
|
|
||||||
} while (frame->mDecodedFrameTime < seekTarget);
|
|
||||||
|
|
||||||
if (mState == DECODER_STATE_SHUTDOWN) {
|
|
||||||
delete frame;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_ASSERTION(frame != nsnull, "No frame after seek!");
|
|
||||||
if (frame) {
|
|
||||||
if (audioTime > frame->mTime) {
|
|
||||||
// liboggplay gave us more data than expected, we need to prepend
|
|
||||||
// the extra data to the current frame to keep audio in sync.
|
|
||||||
audioTime -= frame->mTime;
|
|
||||||
// numExtraSamples must be evenly divisble by number of channels.
|
|
||||||
size_t numExtraSamples = mAudioChannels *
|
|
||||||
PRInt32(NS_ceil(mAudioRate*audioTime));
|
|
||||||
float* data = audioData.Elements() + audioData.Length() - numExtraSamples;
|
|
||||||
float* dst = frame->mAudioData.InsertElementsAt(0, numExtraSamples);
|
|
||||||
memcpy(dst, data, numExtraSamples * sizeof(float));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mLastFrameTime = 0;
|
|
||||||
frame->mTime = 0;
|
|
||||||
frame->mState = OGGPLAY_STREAM_JUST_SEEKED;
|
|
||||||
mDecodedFrames.Push(frame);
|
|
||||||
UpdatePlaybackPosition(frame->mDecodedFrameTime);
|
|
||||||
PlayVideo(frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change state to DECODING now. SeekingStopped will call
|
// Change state to DECODING now. SeekingStopped will call
|
||||||
// nsOggDecodeStateMachine::Seek to reset our state to SEEKING
|
// nsOggDecodeStateMachine::Seek to reset our state to SEEKING
|
||||||
// if we need to seek again.
|
// if we need to seek again.
|
||||||
LOG(PR_LOG_DEBUG, ("Changed state from SEEKING (to %f) to DECODING", seekTime));
|
LOG(PR_LOG_DEBUG, ("Changed state from SEEKING (to %f) to DECODING", seekTime));
|
||||||
// mSeekTime should not have changed. While we seek, mPlayState
|
|
||||||
// should always be PLAY_STATE_SEEKING and no-one will call
|
|
||||||
// nsOggDecoderStateMachine::Seek.
|
|
||||||
NS_ASSERTION(seekTime == mSeekTime, "No-one should have changed mSeekTime");
|
|
||||||
mState = DECODER_STATE_DECODING;
|
mState = DECODER_STATE_DECODING;
|
||||||
mon.NotifyAll();
|
mon.NotifyAll();
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче