зеркало из 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:
|
||||
|
||||
// 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
|
||||
// (RGB for video, float for sound, etc).The decoder monitor 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,
|
||||
"We shouldn't already be seeking");
|
||||
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));
|
||||
mState = DECODER_STATE_SEEKING;
|
||||
}
|
||||
|
@ -1297,6 +1306,71 @@ nsresult nsOggDecodeStateMachine::Seek(float aTime, nsChannelReader* aReader)
|
|||
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)
|
||||
{
|
||||
PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mDecoder->GetMonitor());
|
||||
|
@ -1518,7 +1592,7 @@ nsresult nsOggDecodeStateMachine::Run()
|
|||
NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, SeekingStarted);
|
||||
NS_DispatchToMainThread(startEvent, NS_DISPATCH_SYNC);
|
||||
|
||||
Seek(seekTime, reader);
|
||||
nsresult res = Seek(seekTime, reader);
|
||||
|
||||
// Reactivate all tracks. Liboggplay deactivates tracks when it
|
||||
// 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)
|
||||
continue;
|
||||
|
||||
// Drop frames before the target seek time.
|
||||
float seekTarget = seekTime - 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 {
|
||||
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));
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
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.
|
||||
NS_ASSERTION(seekTime == mSeekTime, "No-one should have changed mSeekTime");
|
||||
if (mState == DECODER_STATE_SHUTDOWN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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
|
||||
// nsOggDecodeStateMachine::Seek to reset our state to SEEKING
|
||||
// if we need to seek again.
|
||||
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;
|
||||
mon.NotifyAll();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче