From de44118d0bf1aaeb2421eb4e4a42b4020d31958e Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Tue, 27 Apr 2010 20:53:45 +1200 Subject: [PATCH] Bug 556893 - Make playback time remaining accurate in media readyState transition calculation. r=doublec --- content/media/nsBuiltinDecoder.cpp | 6 +++ content/media/nsBuiltinDecoder.h | 4 ++ content/media/ogg/nsOggPlayStateMachine.cpp | 2 + content/media/ogg/nsOggReader.cpp | 14 ++++-- content/media/ogg/nsOggReader.h | 54 +++++++++++++-------- 5 files changed, 56 insertions(+), 24 deletions(-) diff --git a/content/media/nsBuiltinDecoder.cpp b/content/media/nsBuiltinDecoder.cpp index d5db6fc52c4b..20c36b473445 100644 --- a/content/media/nsBuiltinDecoder.cpp +++ b/content/media/nsBuiltinDecoder.cpp @@ -815,3 +815,9 @@ void nsBuiltinDecoder::MoveLoadsToBackground() mStream->MoveLoadsToBackground(); } } + +void nsBuiltinDecoder::UpdatePlaybackOffset(PRInt64 aOffset) +{ + MonitorAutoEnter mon(mMonitor); + mPlaybackPosition = NS_MAX(aOffset, mPlaybackPosition); +} diff --git a/content/media/nsBuiltinDecoder.h b/content/media/nsBuiltinDecoder.h index 76810334bb10..086e8fb2ef52 100644 --- a/content/media/nsBuiltinDecoder.h +++ b/content/media/nsBuiltinDecoder.h @@ -405,6 +405,10 @@ class nsBuiltinDecoder : public nsMediaDecoder // position. PRInt64 GetDownloadPosition(); + // Updates the approximate byte offset which playback has reached. This is + // used to calculate the readyState transitions. + void UpdatePlaybackOffset(PRInt64 aOffset); + public: // Notifies the element that decoding has failed. void DecodeError(); diff --git a/content/media/ogg/nsOggPlayStateMachine.cpp b/content/media/ogg/nsOggPlayStateMachine.cpp index 7c038a24c114..41015cabd488 100644 --- a/content/media/ogg/nsOggPlayStateMachine.cpp +++ b/content/media/ogg/nsOggPlayStateMachine.cpp @@ -379,6 +379,7 @@ void nsOggPlayStateMachine::AudioLoop() sound->AudioDataLength(), PR_TRUE); mAudioEndTime = sound->mTime + sound->mDuration; + mDecoder->UpdatePlaybackOffset(sound->mOffset); } else { mReader->mAudioQueue.PushFront(sound); sound.forget(); @@ -1122,6 +1123,7 @@ void nsOggPlayStateMachine::AdvanceFrame() mVideoFrameTime = data->mTime; videoData = data; mReader->mVideoQueue.PopFront(); + mDecoder->UpdatePlaybackOffset(data->mOffset); if (mReader->mVideoQueue.GetSize() == 0) break; data = mReader->mVideoQueue.PeekFront(); diff --git a/content/media/ogg/nsOggReader.cpp b/content/media/ogg/nsOggReader.cpp index 7b0642417cdd..15624c898dfb 100644 --- a/content/media/ogg/nsOggReader.cpp +++ b/content/media/ogg/nsOggReader.cpp @@ -82,12 +82,13 @@ PRBool MulOverflow32(PRUint32 a, PRUint32 b, PRUint32& aResult) { return PR_TRUE; } -VideoData* VideoData::Create(PRInt64 aTime, +VideoData* VideoData::Create(PRInt64 aOffset, + PRInt64 aTime, th_ycbcr_buffer aBuffer, PRBool aKeyframe, PRInt64 aGranulepos) { - nsAutoPtr v(new VideoData(aTime, aKeyframe, aGranulepos)); + nsAutoPtr v(new VideoData(aOffset, aTime, aKeyframe, aGranulepos)); for (PRUint32 i=0; i < 3; ++i) { PRUint32 size = 0; if (!MulOverflow32(PR_ABS(aBuffer[i].height), @@ -199,7 +200,8 @@ nsresult nsOggReader::DecodeVorbis(nsTArray& aChunks, PRInt64 duration = mVorbisState->Time((PRInt64)samples); PRInt64 startTime = (mVorbisGranulepos != -1) ? mVorbisState->Time(mVorbisGranulepos) : -1; - SoundData* s = new SoundData(startTime, + SoundData* s = new SoundData(mPageOffset, + startTime, duration, samples, buffer, @@ -357,14 +359,16 @@ nsresult nsOggReader::DecodeTheora(nsTArray& aFrames, PRInt64 time = (aPacket->granulepos != -1) ? mTheoraState->StartTime(aPacket->granulepos) : -1; if (ret == TH_DUPFRAME) { - aFrames.AppendElement(VideoData::CreateDuplicate(time, + aFrames.AppendElement(VideoData::CreateDuplicate(mPageOffset, + time, aPacket->granulepos)); } else if (ret == 0) { th_ycbcr_buffer buffer; ret = th_decode_ycbcr_out(mTheoraState->mCtx, buffer); NS_ASSERTION(ret == 0, "th_decode_ycbcr_out failed"); PRBool isKeyframe = th_packet_iskeyframe(aPacket) == 1; - VideoData *v = VideoData::Create(time, + VideoData *v = VideoData::Create(mPageOffset, + time, buffer, isKeyframe, aPacket->granulepos); diff --git a/content/media/ogg/nsOggReader.h b/content/media/ogg/nsOggReader.h index b39c8400cad3..97620c3e9b11 100644 --- a/content/media/ogg/nsOggReader.h +++ b/content/media/ogg/nsOggReader.h @@ -61,12 +61,14 @@ using mozilla::TimeStamp; // Holds chunk a decoded sound samples. class SoundData { public: - SoundData(PRInt64 aTime, + SoundData(PRInt64 aOffset, + PRInt64 aTime, PRInt64 aDuration, PRUint32 aSamples, float* aData, PRUint32 aChannels) - : mTime(aTime), + : mOffset(aOffset), + mTime(aTime), mDuration(aDuration), mSamples(aSamples), mChannels(aChannels), @@ -75,11 +77,13 @@ public: MOZ_COUNT_CTOR(SoundData); } - SoundData(PRInt64 aDuration, + SoundData(PRInt64 aOffset, + PRInt64 aDuration, PRUint32 aSamples, float* aData, PRUint32 aChannels) - : mTime(-1), + : mOffset(aOffset), + mTime(-1), mDuration(aDuration), mSamples(aSamples), mChannels(aChannels), @@ -97,6 +101,10 @@ public: return mChannels * mSamples; } + // Approximate byte offset of the end of the page on which this sample + // chunk ends. + const PRInt64 mOffset; + PRInt64 mTime; // Start time of samples in ms. const PRInt64 mDuration; // In ms. const PRUint32 mSamples; @@ -111,7 +119,8 @@ public: // Constructs a VideoData object. Makes a copy of YCbCr data in aBuffer. // This may return nsnull if we run out of memory when allocating buffers // to store the frame. - static VideoData* Create(PRInt64 aTime, + static VideoData* Create(PRInt64 aOffset, + PRInt64 aTime, th_ycbcr_buffer aBuffer, PRBool aKeyframe, PRInt64 aGranulepos); @@ -119,10 +128,11 @@ public: // Constructs a duplicate VideoData object. This intrinsically tells the // player that it does not need to update the displayed frame when this // frame is played; this frame is identical to the previous. - static VideoData* CreateDuplicate(PRInt64 aTime, + static VideoData* CreateDuplicate(PRInt64 aOffset, + PRInt64 aTime, PRInt64 aGranulepos) { - return new VideoData(aTime, aGranulepos); + return new VideoData(aOffset, aTime, aGranulepos); } ~VideoData() @@ -133,6 +143,9 @@ public: } } + // Approximate byte offset of the end of the frame in the media. + PRInt64 mOffset; + // Start time of frame in milliseconds. PRInt64 mTime; PRInt64 mGranulepos; @@ -145,23 +158,26 @@ public: PRPackedBool mKeyframe; private: - VideoData(PRInt64 aTime, PRInt64 aGranulepos) : - mTime(aTime), - mGranulepos(aGranulepos), - mDuplicate(PR_TRUE), - mKeyframe(PR_FALSE) + VideoData(PRInt64 aOffset, PRInt64 aTime, PRInt64 aGranulepos) + : mOffset(aOffset), + mTime(aTime), + mGranulepos(aGranulepos), + mDuplicate(PR_TRUE), + mKeyframe(PR_FALSE) { MOZ_COUNT_CTOR(VideoData); memset(&mBuffer, 0, sizeof(th_ycbcr_buffer)); } - VideoData(PRInt64 aTime, + VideoData(PRInt64 aOffset, + PRInt64 aTime, PRBool aKeyframe, PRInt64 aGranulepos) - : mTime(aTime), - mGranulepos(aGranulepos), - mDuplicate(PR_FALSE), - mKeyframe(aKeyframe) + : mOffset(aOffset), + mTime(aTime), + mGranulepos(aGranulepos), + mDuplicate(PR_FALSE), + mKeyframe(aKeyframe) { MOZ_COUNT_CTOR(VideoData); } @@ -278,8 +294,8 @@ private: // extremities of a range to seek in. class ByteRange { public: - ByteRange() : - mOffsetStart(0), + ByteRange() + : mOffsetStart(0), mOffsetEnd(0), mTimeStart(0), mTimeEnd(0)