Bug 1096089: Only return end of stream if we're near the known duration. r=mattwoodrow

YouTube will call endOfStream once the video has been entirely buffered.
When changing video quality, it will clear the entire source buffer,
following which it will append data once again which will reopen
the mediasource.
We don't want to consider a mediasource in ended state as not ever going to
receive more data in the future unless we're actually reached the end.
This commit is contained in:
Jean-Yves Avenard 2015-01-24 21:46:21 +11:00
parent 0e5360359f
commit f1129bf869
3 changed files with 30 additions and 7 deletions

View File

@ -240,6 +240,9 @@ MediaSourceDecoder::DoSetMediaSourceDuration(double aDuration)
mDecoderStateMachine->SetDuration(INT64_MAX);
mMediaSourceDuration = PositiveInfinity<double>();
}
if (mReader) {
mReader->SetMediaSourceDuration(mMediaSourceDuration);
}
}
void

View File

@ -56,6 +56,7 @@ MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
, mDropAudioBeforeThreshold(false)
, mDropVideoBeforeThreshold(false)
, mEnded(false)
, mMediaSourceDuration(0)
, mHasEssentialTrackBuffers(false)
#ifdef MOZ_FMP4
, mSharedDecoderManager(new SharedDecoderManager())
@ -133,7 +134,7 @@ MediaSourceReader::RequestAudioData()
break;
case READER_ERROR:
if (mLastAudioTime) {
CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA);
CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
break;
}
// Fallback to using current reader
@ -238,7 +239,7 @@ MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
return;
}
CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA);
CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
}
@ -273,7 +274,7 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
break;
case READER_ERROR:
if (mLastVideoTime) {
CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA);
CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
break;
}
// Fallback to using current reader.
@ -355,14 +356,14 @@ MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
return;
}
CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA);
CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
}
void
MediaSourceReader::CheckForWaitOrEndOfStream(MediaData::Type aType)
MediaSourceReader::CheckForWaitOrEndOfStream(MediaData::Type aType, int64_t aTime)
{
// If the entire MediaSource is done, generate an EndOfStream.
if (IsEnded()) {
if (IsNearEnd(aTime)) {
if (aType == MediaData::AUDIO_DATA) {
mAudioPromise.Reject(END_OF_STREAM, __func__);
} else {
@ -946,6 +947,20 @@ MediaSourceReader::IsEnded()
return mEnded;
}
bool
MediaSourceReader::IsNearEnd(int64_t aTime)
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
return mEnded && aTime >= (mMediaSourceDuration * USECS_PER_S - EOS_FUZZ_US);
}
void
MediaSourceReader::SetMediaSourceDuration(double aDuration)
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mMediaSourceDuration = aDuration;
}
#ifdef MOZ_EME
nsresult
MediaSourceReader::SetCDMProxy(CDMProxy* aProxy)

View File

@ -129,6 +129,10 @@ public:
// Return true if the Ended method has been called
bool IsEnded();
bool IsNearEnd(int64_t aTime /* microseconds */);
// Set the duration of the attached mediasource element.
void SetMediaSourceDuration(double aDuration /* seconds */);
#ifdef MOZ_EME
nsresult SetCDMProxy(CDMProxy* aProxy);
@ -159,7 +163,7 @@ private:
void RequestVideoDataFailed(nsresult aResult);
// Will reject the MediaPromise with END_OF_STREAM if mediasource has ended
// or with WAIT_FOR_DATA otherwise.
void CheckForWaitOrEndOfStream(MediaData::Type aType);
void CheckForWaitOrEndOfStream(MediaData::Type aType, int64_t aTime /* microseconds */);
// Return a reader from the set available in aTrackDecoders that has data
// available in the range requested by aTarget.
@ -210,6 +214,7 @@ private:
bool mDropVideoBeforeThreshold;
bool mEnded;
double mMediaSourceDuration;
bool mHasEssentialTrackBuffers;