зеркало из https://github.com/mozilla/pjs.git
Bug 628665 - Resurrect nsBuiltinDecoderStateMachine::HasLowDecodedData(). r=roc
This commit is contained in:
Родитель
f2eab9ebf2
Коммит
f7ab69abdd
|
@ -303,8 +303,6 @@ public:
|
|||
// with the decode monitor held. Called on the state machine thread and
|
||||
// the main thread.
|
||||
virtual void StartBuffering() = 0;
|
||||
|
||||
virtual void NotifyDataExhausted() = 0;
|
||||
};
|
||||
|
||||
class nsBuiltinDecoder : public nsMediaDecoder
|
||||
|
@ -369,10 +367,6 @@ class nsBuiltinDecoder : public nsMediaDecoder
|
|||
// from the resource.
|
||||
void NotifyBytesConsumed(PRInt64 aBytes);
|
||||
|
||||
void NotifyDataExhausted() {
|
||||
mDecoderStateMachine->NotifyDataExhausted();
|
||||
}
|
||||
|
||||
// Called when the video file has completed downloading.
|
||||
// Call on the main thread only.
|
||||
void ResourceLoaded();
|
||||
|
|
|
@ -117,6 +117,17 @@ static const double NORMAL_BUFFER_MARGIN = 100.0;
|
|||
// undecoded data, we'll stop playback and start buffering.
|
||||
static const int LIVE_BUFFER_MARGIN = 100000;
|
||||
|
||||
// Amount of excess ms of data to add in to the "should we buffer" calculation.
|
||||
static const PRUint32 EXHAUSTED_DATA_MARGIN_MS = 60;
|
||||
|
||||
static TimeDuration MsToDuration(PRInt64 aMs) {
|
||||
return TimeDuration::FromMilliseconds(static_cast<double>(aMs));
|
||||
}
|
||||
|
||||
static PRInt64 DurationToMs(TimeDuration aDuration) {
|
||||
return static_cast<PRInt64>(aDuration.ToSeconds() * 1000);
|
||||
}
|
||||
|
||||
class nsAudioMetadataEventRunner : public nsRunnable
|
||||
{
|
||||
private:
|
||||
|
@ -941,19 +952,21 @@ PRBool nsBuiltinDecoderStateMachine::IsDecodeCloseToDownload()
|
|||
return (downloadPos - decodePos) < threshold;
|
||||
}
|
||||
|
||||
void nsBuiltinDecoderStateMachine::NotifyDataExhausted()
|
||||
PRBool nsBuiltinDecoderStateMachine::HasLowDecodedData(PRInt64 aAudioMs) const
|
||||
{
|
||||
MonitorAutoEnter mon(mDecoder->GetMonitor());
|
||||
nsMediaStream* stream = mDecoder->GetCurrentStream();
|
||||
if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING &&
|
||||
mState == DECODER_STATE_DECODING &&
|
||||
!stream->IsDataCachedToEndOfStream(mDecoder->mDecoderPosition) &&
|
||||
!stream->IsSuspended())
|
||||
{
|
||||
// Our decode has caught up with the download. Let's buffer to make sure
|
||||
// we can play a decent amount of video in the future.
|
||||
StartBuffering();
|
||||
}
|
||||
mDecoder->GetMonitor().AssertCurrentThreadIn();
|
||||
// We consider ourselves low on decoded data if we're low on audio,
|
||||
// provided we've not decoded to the end of the audio stream, or
|
||||
// if we're only playing video and we're low on video frames, provided
|
||||
// we've not decoded to the end of the video stream.
|
||||
return ((HasAudio() &&
|
||||
!mReader->mAudioQueue.IsFinished() &&
|
||||
AudioDecodedMs() < aAudioMs)
|
||||
||
|
||||
(!HasAudio() &&
|
||||
HasVideo() &&
|
||||
!mReader->mVideoQueue.IsFinished() &&
|
||||
static_cast<PRUint32>(mReader->mVideoQueue.GetSize()) < LOW_VIDEO_FRAMES));
|
||||
}
|
||||
|
||||
nsresult nsBuiltinDecoderStateMachine::Run()
|
||||
|
@ -1101,7 +1114,7 @@ nsresult nsBuiltinDecoderStateMachine::Run()
|
|||
"Seek target should lie inside the first audio block after seek");
|
||||
PRInt64 startTime = (audio && audio->mTime < seekTime) ? audio->mTime : seekTime;
|
||||
mAudioStartTime = startTime;
|
||||
mPlayDuration = TimeDuration::FromMilliseconds(startTime - mStartTime);
|
||||
mPlayDuration = MsToDuration(startTime - mStartTime);
|
||||
if (HasVideo()) {
|
||||
nsAutoPtr<VideoData> video(mReader->mVideoQueue.PeekFront());
|
||||
if (video) {
|
||||
|
@ -1179,7 +1192,7 @@ nsresult nsBuiltinDecoderStateMachine::Run()
|
|||
PRBool isLiveStream = mDecoder->GetCurrentStream()->GetLength() == -1;
|
||||
if ((isLiveStream || !mDecoder->CanPlayThrough()) &&
|
||||
elapsed < TimeDuration::FromSeconds(BUFFERING_WAIT) &&
|
||||
stream->GetCachedDataEnd(mDecoder->mDecoderPosition) < mBufferingEndOffset &&
|
||||
HasLowDecodedData(1000) &&
|
||||
!stream->IsDataCachedToEndOfStream(mDecoder->mDecoderPosition) &&
|
||||
!stream->IsSuspended())
|
||||
{
|
||||
|
@ -1306,11 +1319,6 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame()
|
|||
|
||||
// When it's time to display a frame, decode the frame and display it.
|
||||
if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING) {
|
||||
if (!IsPlaying()) {
|
||||
StartPlayback();
|
||||
mDecoder->GetMonitor().NotifyAll();
|
||||
}
|
||||
|
||||
if (HasAudio() && mAudioStartTime == -1 && !mAudioCompleted) {
|
||||
// We've got audio (so we should sync off the audio clock), but we've not
|
||||
// played a sample on the audio thread, so we can't get a time from the
|
||||
|
@ -1325,24 +1333,28 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame()
|
|||
// the end of the audio, use the audio clock. However if we've finished
|
||||
// audio, or don't have audio, use the system clock.
|
||||
PRInt64 clock_time = -1;
|
||||
PRInt64 audio_time = GetAudioClock();
|
||||
if (HasAudio() && !mAudioCompleted && audio_time != -1) {
|
||||
clock_time = audio_time;
|
||||
// Resync against the audio clock, while we're trusting the
|
||||
// audio clock. This ensures no "drift", particularly on Linux.
|
||||
mPlayDuration = TimeDuration::FromMilliseconds(clock_time - mStartTime);
|
||||
mPlayStartTime = TimeStamp::Now();
|
||||
if (!IsPlaying()) {
|
||||
clock_time = DurationToMs(mPlayDuration) + mStartTime;
|
||||
} else {
|
||||
// Sound is disabled on this system. Sync to the system clock.
|
||||
TimeDuration t = TimeStamp::Now() - mPlayStartTime + mPlayDuration;
|
||||
clock_time = (PRInt64)(1000 * t.ToSeconds());
|
||||
// Ensure the clock can never go backwards.
|
||||
NS_ASSERTION(mCurrentFrameTime <= clock_time, "Clock should go forwards");
|
||||
clock_time = NS_MAX(mCurrentFrameTime, clock_time) + mStartTime;
|
||||
PRInt64 audio_time = GetAudioClock();
|
||||
if (HasAudio() && !mAudioCompleted && audio_time != -1) {
|
||||
clock_time = audio_time;
|
||||
// Resync against the audio clock, while we're trusting the
|
||||
// audio clock. This ensures no "drift", particularly on Linux.
|
||||
mPlayDuration = MsToDuration(clock_time - mStartTime);
|
||||
mPlayStartTime = TimeStamp::Now();
|
||||
} else {
|
||||
// Sound is disabled on this system. Sync to the system clock.
|
||||
clock_time = DurationToMs(TimeStamp::Now() - mPlayStartTime + mPlayDuration);
|
||||
// Ensure the clock can never go backwards.
|
||||
NS_ASSERTION(mCurrentFrameTime <= clock_time, "Clock should go forwards");
|
||||
clock_time = NS_MAX(mCurrentFrameTime, clock_time) + mStartTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip frames up to the frame at the playback position, and figure out
|
||||
// the time remaining until it's time to display the next frame.
|
||||
PRInt64 remainingTime = AUDIO_DURATION_MS;
|
||||
|
||||
NS_ASSERTION(clock_time >= mStartTime, "Should have positive clock time.");
|
||||
nsAutoPtr<VideoData> currentFrame;
|
||||
if (mReader->mVideoQueue.GetSize() > 0) {
|
||||
|
@ -1359,13 +1371,38 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame()
|
|||
// Current frame has already been presented, wait until it's time to
|
||||
// present the next frame.
|
||||
if (frame && !currentFrame) {
|
||||
PRInt64 now = (TimeStamp::Now() - mPlayStartTime + mPlayDuration).ToMilliseconds();
|
||||
PRInt64 now = IsPlaying()
|
||||
? DurationToMs(TimeStamp::Now() - mPlayStartTime + mPlayDuration)
|
||||
: DurationToMs(mPlayDuration);
|
||||
remainingTime = frame->mTime - mStartTime - now;
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if we don't have enough data to play up to the next frame.
|
||||
// If we don't, switch to buffering mode.
|
||||
nsMediaStream* stream = mDecoder->GetCurrentStream();
|
||||
if (mState == DECODER_STATE_DECODING &&
|
||||
mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING &&
|
||||
HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_MS) &&
|
||||
!stream->IsDataCachedToEndOfStream(mDecoder->mDecoderPosition) &&
|
||||
!stream->IsSuspended())
|
||||
{
|
||||
if (currentFrame) {
|
||||
mReader->mVideoQueue.PushFront(currentFrame.forget());
|
||||
}
|
||||
mState = DECODER_STATE_BUFFERING;
|
||||
return;
|
||||
}
|
||||
|
||||
// We've got enough data to keep playing until at least the next frame.
|
||||
// Start playing now if need be.
|
||||
if (!IsPlaying()) {
|
||||
StartPlayback();
|
||||
mDecoder->GetMonitor().NotifyAll();
|
||||
}
|
||||
|
||||
if (currentFrame) {
|
||||
// Decode one frame and display it
|
||||
// Decode one frame and display it.
|
||||
TimeStamp presTime = mPlayStartTime - mPlayDuration +
|
||||
TimeDuration::FromMilliseconds(currentFrame->mTime - mStartTime);
|
||||
NS_ASSERTION(currentFrame->mTime >= mStartTime, "Should have positive frame time");
|
||||
|
@ -1376,7 +1413,7 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame()
|
|||
RenderVideoFrame(currentFrame, presTime);
|
||||
}
|
||||
mDecoder->GetFrameStatistics().NotifyPresentedFrame();
|
||||
PRInt64 now = (TimeStamp::Now() - mPlayStartTime + mPlayDuration).ToMilliseconds();
|
||||
PRInt64 now = DurationToMs(TimeStamp::Now() - mPlayStartTime + mPlayDuration);
|
||||
remainingTime = currentFrame->mEndTime - mStartTime - now;
|
||||
currentFrame = nsnull;
|
||||
}
|
||||
|
|
|
@ -250,10 +250,12 @@ public:
|
|||
return mEndTime;
|
||||
}
|
||||
|
||||
void NotifyDataExhausted();
|
||||
|
||||
protected:
|
||||
|
||||
// Returns PR_TRUE if we'v got less than aAudioMs ms of decoded and playable
|
||||
// data. The decoder monitor must be held.
|
||||
PRBool HasLowDecodedData(PRInt64 aAudioMs) const;
|
||||
|
||||
// Returns PR_TRUE if the decode is withing an estimated one tenth of a
|
||||
// second's worth of data of the download, i.e. the decode has almost
|
||||
// caught up with the download. If we can't estimate one tenth of a second's
|
||||
|
|
|
@ -382,11 +382,6 @@ public:
|
|||
// to buffer, given the current download and playback rates.
|
||||
PRBool CanPlayThrough();
|
||||
|
||||
// Called by the nsMediaStream when a read on the stream by the decoder
|
||||
// is about to block due to insuffient data. Decoders may want to pause
|
||||
// playback and go into buffering mode when this is called.
|
||||
virtual void NotifyDataExhausted() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
// Start timer to update download progress information.
|
||||
|
|
|
@ -588,15 +588,6 @@ nsresult nsMediaChannelStream::Read(char* aBuffer,
|
|||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
|
||||
|
||||
PRInt64 pos = Tell();
|
||||
PRInt64 endOfRead = pos + aCount;
|
||||
if (endOfRead > mCacheStream.GetCachedDataEnd(pos) &&
|
||||
!IsDataCachedToEndOfStream(pos)) {
|
||||
// Our read will almost certainly block waiting for more data to download.
|
||||
// Notify the decoder, so it can move to buffering state if need be.
|
||||
mDecoder->NotifyDataExhausted();
|
||||
}
|
||||
|
||||
return mCacheStream.Read(aBuffer, aCount, aBytes);
|
||||
}
|
||||
|
||||
|
|
|
@ -244,7 +244,6 @@ class nsWaveDecoder : public nsMediaDecoder
|
|||
|
||||
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) {}
|
||||
|
||||
void NotifyDataExhausted() {}
|
||||
private:
|
||||
// Notifies the element that seeking has started.
|
||||
void SeekingStarted();
|
||||
|
|
Загрузка…
Ссылка в новой задаче