Bug 506061 - Calculate frame time based on frame number and frame rate. p=j@oil21.org r=chris.double

Fixes sync problem caused by FP error accumulation in the old frame time
calculation.

--HG--
extra : rebase_source : 3a59eafe1a3fd91760ffb1e336c31ec431dfffc2
This commit is contained in:
Matthew Gregan 2009-09-07 15:30:03 +12:00
parent 658839d732
commit 34d676d624

View File

@ -228,7 +228,7 @@ public:
return mCount == 0;
}
PRInt32 GetCount() const
PRUint32 GetCount() const
{
return mCount;
}
@ -238,27 +238,27 @@ public:
return mCount == OGGPLAY_BUFFER_SIZE;
}
float ResetTimes(float aPeriod)
PRUint32 ResetTimes(float aPeriod)
{
float time = 0.0;
PRUint32 frames = 0;
if (mCount > 0) {
PRInt32 current = mHead;
PRUint32 current = mHead;
do {
mQueue[current]->mTime = time;
time += aPeriod;
mQueue[current]->mTime = frames * aPeriod;
frames += 1;
current = (current + 1) % OGGPLAY_BUFFER_SIZE;
} while (current != mTail);
}
return time;
return frames;
}
private:
FrameData* mQueue[OGGPLAY_BUFFER_SIZE];
PRInt32 mHead;
PRInt32 mTail;
PRUint32 mHead;
PRUint32 mTail;
// This isn't redundant with mHead/mTail, since when mHead == mTail
// it's ambiguous whether the queue is full or empty
PRInt32 mCount;
PRUint32 mCount;
};
// Enumeration for the valid states
@ -493,7 +493,7 @@ private:
// Number of seconds of data video/audio data held in a frame.
// Accessed only via the decoder thread.
float mCallbackPeriod;
double mCallbackPeriod;
// Video data. These are initially set when the metadata is loaded.
// They are only accessed from the decoder thread.
@ -515,10 +515,9 @@ private:
// accessed in the decoder thread.
PRInt64 mBufferingEndOffset;
// The time value of the last decoded video frame. Used for
// computing the sleep period between frames for a/v sync.
// Read/Write from the decode thread only.
float mLastFrameTime;
// The last decoded video frame. Used for computing the sleep period
// between frames for a/v sync. Read/Write from the decode thread only.
PRUint64 mLastFrame;
// The decoder position of the end of the last decoded video frame.
// Read/Write from the decode thread only.
@ -702,7 +701,7 @@ nsOggDecodeStateMachine::nsOggDecodeStateMachine(nsOggDecoder* aDecoder) :
mAudioTrack(-1),
mBufferingStart(),
mBufferingEndOffset(0),
mLastFrameTime(0),
mLastFrame(0),
mLastFramePosition(-1),
mState(DECODER_STATE_DECODING_METADATA),
mSeekTime(0.0),
@ -760,9 +759,9 @@ nsOggDecodeStateMachine::FrameData* nsOggDecodeStateMachine::NextFrame()
return nsnull;
}
frame->mTime = mLastFrameTime;
frame->mTime = mCallbackPeriod * mLastFrame;
frame->mEndStreamPosition = mDecoder->mDecoderPosition;
mLastFrameTime += mCallbackPeriod;
mLastFrame += 1;
if (mLastFramePosition >= 0) {
NS_ASSERTION(frame->mEndStreamPosition >= mLastFramePosition,
@ -777,7 +776,7 @@ nsOggDecodeStateMachine::FrameData* nsOggDecodeStateMachine::NextFrame()
base + TimeDuration::FromMilliseconds(NS_round(frame->mTime*1000)));
mDecoder->mPlaybackStatistics.AddBytes(frame->mEndStreamPosition - mLastFramePosition);
mDecoder->mPlaybackStatistics.Stop(
base + TimeDuration::FromMilliseconds(NS_round(mLastFrameTime*1000)));
base + TimeDuration::FromMilliseconds(NS_round(mCallbackPeriod*mLastFrame*1000)));
mDecoder->UpdatePlaybackRate();
}
mLastFramePosition = frame->mEndStreamPosition;
@ -1073,7 +1072,7 @@ void nsOggDecodeStateMachine::StartPlayback()
void nsOggDecodeStateMachine::StopPlayback()
{
// NS_ASSERTION(PR_InMonitor(mDecoder->GetMonitor()), "StopPlayback() called without acquiring decoder monitor");
mLastFrameTime = mDecodedFrames.ResetTimes(mCallbackPeriod);
mLastFrame = mDecodedFrames.ResetTimes(mCallbackPeriod);
StopAudio();
mPlaying = PR_FALSE;
mPauseStartTime = TimeStamp::Now();
@ -1089,7 +1088,7 @@ void nsOggDecodeStateMachine::PausePlayback()
mPlaying = PR_FALSE;
mPauseStartTime = TimeStamp::Now();
if (mAudioStream->GetPosition() < 0) {
mLastFrameTime = mDecodedFrames.ResetTimes(mCallbackPeriod);
mLastFrame = mDecodedFrames.ResetTimes(mCallbackPeriod);
}
}
@ -1320,7 +1319,8 @@ void nsOggDecodeStateMachine::DecodeToFrame(nsAutoMonitor& aMonitor,
float target = aTime - mCallbackPeriod / 2.0;
FrameData* frame = nsnull;
OggPlayErrorCode r;
mLastFrameTime = 0;
mLastFrame = 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.
@ -1370,7 +1370,7 @@ void nsOggDecodeStateMachine::DecodeToFrame(nsAutoMonitor& aMonitor,
memcpy(dst, data, numExtraSamples * sizeof(float));
}
mLastFrameTime = 0;
mLastFrame = 0;
frame->mTime = 0;
frame->mState = OGGPLAY_STREAM_JUST_SEEKED;
mDecodedFrames.Push(frame);
@ -1437,7 +1437,7 @@ nsresult nsOggDecodeStateMachine::Run()
if (mState == DECODER_STATE_SHUTDOWN)
continue;
mLastFrameTime = 0;
mLastFrame = 0;
FrameData* frame = NextFrame();
if (frame) {
mDecodedFrames.Push(frame);