Bug 1269178: P1. Retry InternalSeek if previous attempt failed once more data is available. r?gerald
MozReview-Commit-ID: DtaKBzxRVR8
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -742,16 +742,17 @@ MediaFormatReader::NeedInput(DecoderData
// decoded sample. To account for H.264 streams which may require a longer
// run of input than we input, decoders fire an "input exhausted" callback,
// which overrides our "few more samples" threshold.
return
!aDecoder.mDraining &&
!aDecoder.mError &&
aDecoder.mDecodingRequested &&
!aDecoder.mDemuxRequest.Exists() &&
+ !aDecoder.mSeekRequest.Exists() &&
aDecoder.mOutput.Length() <= aDecoder.mDecodeAhead &&
(aDecoder.mInputExhausted || !aDecoder.mQueuedSamples.IsEmpty() ||
aDecoder.mTimeThreshold.isSome() ||
aDecoder.mNumSamplesInput - aDecoder.mNumSamplesOutput <= aDecoder.mDecodeAhead);
}
void
MediaFormatReader::ScheduleUpdate(TrackType aTrack)
@@ -779,18 +780,32 @@ MediaFormatReader::UpdateReceivedNewData
if (!decoder.mReceivedNewData) {
return false;
}
// Update our cached TimeRange.
decoder.mTimeRanges = decoder.mTrackDemuxer->GetBuffered();
- if (decoder.mDrainComplete || decoder.mDraining ||
- decoder.mDemuxRequest.Exists()) {
+ // We do not want to clear mWaitingForData while there are pending
+ // demuxing or seeking operations that could affect the value of this flag.
+ // This is in order to ensure that we will retry once they complete as we may
+ // now have new data that could potentially allow those operations to
+ // successfully complete if tried again.
+ if (decoder.mSeekRequest.Exists()) {
+ // Nothing more to do until this operation complete.
+ return true;
+ }
+ if (decoder.mDemuxRequest.Exists()) {
+ // We may have pending operations to process, so we want to continue
+ // after UpdateReceivedNewData returns.
+ return false;
+ }
+
+ if (decoder.mDrainComplete || decoder.mDraining) {
// We do not want to clear mWaitingForData or mDemuxEOS while
// a drain is in progress in order to properly complete the operation.
return false;
}
bool hasLastEnd;
media::TimeUnit lastEnd = decoder.mTimeRanges.GetEnd(&hasLastEnd);
if (hasLastEnd) {
@@ -805,20 +820,29 @@ MediaFormatReader::UpdateReceivedNewData
if (decoder.mTimeThreshold) {
decoder.mTimeThreshold.ref().mWaiting = false;
}
decoder.mWaitingForData = false;
if (decoder.mError) {
return false;
}
- if (decoder.HasWaitingPromise()) {
- MOZ_ASSERT(!decoder.HasPromise());
- LOG("We have new data. Resolving WaitingPromise");
- decoder.mWaitingPromise.Resolve(decoder.mType, __func__);
+
+ bool hasPendingSeek =
+ decoder.mTimeThreshold && !decoder.mTimeThreshold.ref().mHasSeeked;
+ if (hasPendingSeek || decoder.HasWaitingPromise()) {
+ if (hasPendingSeek) {
+ LOG("Attempting Internal Seek");
+ InternalSeek(aTrack, decoder.mTimeThreshold.ref());
+ }
+ if (decoder.HasWaitingPromise()) {
+ MOZ_ASSERT(!decoder.HasPromise());
+ LOG("We have new data. Resolving WaitingPromise");
+ decoder.mWaitingPromise.Resolve(decoder.mType, __func__);
+ }
return true;
}
if (!mSeekPromise.IsEmpty()) {
MOZ_ASSERT(!decoder.HasPromise());
if (mVideo.mSeekRequest.Exists() || mAudio.mSeekRequest.Exists()) {
// Already waiting for a seek to complete. Nothing more to do.
return true;
}
@@ -978,36 +1002,40 @@ MediaFormatReader::InternalSeek(TrackTyp
decoder.mTimeThreshold = Some(aTarget);
RefPtr<MediaFormatReader> self = this;
decoder.ResetDemuxer();
decoder.mSeekRequest.Begin(decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().mTime)
->Then(OwnerThread(), __func__,
[self, aTrack] (media::TimeUnit aTime) {
auto& decoder = self->GetDecoderData(aTrack);
decoder.mSeekRequest.Complete();
+ MOZ_ASSERT(decoder.mTimeThreshold);
+ decoder.mTimeThreshold.ref().mHasSeeked = true;
self->NotifyDecodingRequested(aTrack);
},
[self, aTrack] (DemuxerFailureReason aResult) {
auto& decoder = self->GetDecoderData(aTrack);
decoder.mSeekRequest.Complete();
switch (aResult) {
case DemuxerFailureReason::WAITING_FOR_DATA:
self->NotifyWaitingForData(aTrack);
break;
case DemuxerFailureReason::END_OF_STREAM:
+ decoder.mTimeThreshold.reset();
self->NotifyEndOfStream(aTrack);
break;
case DemuxerFailureReason::CANCELED:
case DemuxerFailureReason::SHUTDOWN:
+ decoder.mTimeThreshold.reset();
break;
default:
+ decoder.mTimeThreshold.reset();
self->NotifyError(aTrack);
break;
}
- decoder.mTimeThreshold.reset();
}));
}
void
MediaFormatReader::DrainDecoder(TrackType aTrack)
{
MOZ_ASSERT(OnTaskQueue());
@@ -1120,17 +1148,18 @@ MediaFormatReader::Update(TrackType aTra
if (!decoder.mReceivedNewData) {
LOG("Rejecting %s promise: WAITING_FOR_DATA", TrackTypeToStr(aTrack));
decoder.RejectPromise(WAITING_FOR_DATA, __func__);
}
}
// Now that draining has completed, we check if we have received
// new data again as the result may now be different from the earlier
// run.
- if (UpdateReceivedNewData(aTrack)) {
+ if (UpdateReceivedNewData(aTrack) ||
+ (decoder.mTimeThreshold && decoder.mSeekRequest.Exists())) {
LOGV("Nothing more to do");
return;
}
}
}
if (decoder.mNeedDraining) {
DrainDecoder(aTrack);
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -132,22 +132,25 @@ private:
bool DecodeDemuxedSamples(TrackType aTrack,
MediaRawData* aSample);
struct InternalSeekTarget {
InternalSeekTarget(const media::TimeUnit& aTime, bool aDropTarget)
: mTime(aTime)
, mDropTarget(aDropTarget)
, mWaiting(false)
+ , mHasSeeked(false)
{}
media::TimeUnit mTime;
bool mDropTarget;
bool mWaiting;
+ bool mHasSeeked;
};
+
// Perform an internal seek to aTime. If aDropTarget is true then
// the first sample past the target will be dropped.
void InternalSeek(TrackType aTrack, const InternalSeekTarget& aTarget);
// Drain the current decoder.
void DrainDecoder(TrackType aTrack);
void NotifyNewOutput(TrackType aTrack, MediaData* aSample);
void NotifyInputExhausted(TrackType aTrack);