Bug 556893 - Make playback time remaining accurate in media readyState transition calculation. r=doublec

This commit is contained in:
Chris Pearce 2010-04-27 20:53:45 +12:00
parent 6f5d537cbc
commit de44118d0b
5 changed files with 56 additions and 24 deletions

View File

@ -815,3 +815,9 @@ void nsBuiltinDecoder::MoveLoadsToBackground()
mStream->MoveLoadsToBackground();
}
}
void nsBuiltinDecoder::UpdatePlaybackOffset(PRInt64 aOffset)
{
MonitorAutoEnter mon(mMonitor);
mPlaybackPosition = NS_MAX(aOffset, mPlaybackPosition);
}

View File

@ -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();

View File

@ -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();

View File

@ -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<VideoData> v(new VideoData(aTime, aKeyframe, aGranulepos));
nsAutoPtr<VideoData> 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<SoundData*>& 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<VideoData*>& 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);

View File

@ -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)