diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index a0bf73e6f219..f7d56ead4e1d 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -1422,6 +1422,27 @@ MediaFormatReader::Reset(TrackType aTrack) LOG("Reset(%s) END", TrackTypeToStr(aTrack)); } +void +MediaFormatReader::DropDecodedSamples(TrackType aTrack) +{ + MOZ_ASSERT(OnTaskQueue()); + auto& decoder = GetDecoderData(aTrack); + size_t lengthDecodedQueue = decoder.mOutput.Length(); + if (lengthDecodedQueue && decoder.mTimeThreshold.isSome()) { + TimeUnit time = + TimeUnit::FromMicroseconds(decoder.mOutput.LastElement()->mTime); + if (time >= decoder.mTimeThreshold.ref().Time()) { + // We would have reached our internal seek target. + decoder.mTimeThreshold.reset(); + } + } + decoder.mOutput.Clear(); + decoder.mSizeOfQueue -= lengthDecodedQueue; + if (aTrack == TrackInfo::kVideoTrack && mDecoder) { + mDecoder->NotifyDecodedFrames(0, 0, lengthDecodedQueue); + } +} + void MediaFormatReader::SkipVideoDemuxToNextKeyFrame(media::TimeUnit aTimeThreshold) { @@ -1429,6 +1450,15 @@ MediaFormatReader::SkipVideoDemuxToNextKeyFrame(media::TimeUnit aTimeThreshold) MOZ_ASSERT(mVideo.HasPromise()); LOG("Skipping up to %lld", aTimeThreshold.ToMicroseconds()); + // We've reached SkipVideoDemuxToNextKeyFrame when our decoding is late. + // As such we can drop all already decoded samples and discard all pending + // samples. + // TODO: Ideally we should set mOutputRequested to false so that all pending + // frames are dropped too. However, we can't do such thing as the code assumes + // that the decoder just got flushed. Once bug 1257107 land, we could set the + // decoder threshold to the value of currentTime. + DropDecodedSamples(TrackInfo::kVideoTrack); + mSkipRequest.Begin(mVideo.mTrackDemuxer->SkipToNextRandomAccessPoint(aTimeThreshold) ->Then(OwnerThread(), __func__, this, &MediaFormatReader::OnVideoSkipCompleted, @@ -1440,11 +1470,11 @@ void MediaFormatReader::VideoSkipReset(uint32_t aSkipped) { MOZ_ASSERT(OnTaskQueue()); - // I think it's still possible for an output to have been sent from the decoder - // and is currently sitting in our event queue waiting to be processed. The following - // flush won't clear it, and when we return to the event loop it'll be added to our - // output queue and be used. - // This code will count that as dropped, which was the intent, but not quite true. + + // Some frames may have been output by the decoder since we initiated the + // videoskip process and we know they would be late. + DropDecodedSamples(TrackInfo::kVideoTrack); + // Report the pending frames as dropped. if (mDecoder) { mDecoder->NotifyDecodedFrames(0, 0, SizeOfVideoQueueInFrames()); } @@ -1483,6 +1513,9 @@ MediaFormatReader::OnVideoSkipFailed(MediaTrackDemuxer::SkipFailureHolder aFailu switch (aFailure.mFailure) { case DemuxerFailureReason::END_OF_STREAM: MOZ_FALLTHROUGH; case DemuxerFailureReason::WAITING_FOR_DATA: + // Some frames may have been output by the decoder since we initiated the + // videoskip process and we know they would be late. + DropDecodedSamples(TrackInfo::kVideoTrack); // We can't complete the skip operation, will just service a video frame // normally. NotifyDecodingRequested(TrackInfo::kVideoTrack); diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index be24ae1d8760..c3cdc83b5e0d 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -179,6 +179,7 @@ private: void Error(TrackType aTrack); void Reset(TrackType aTrack); void DrainComplete(TrackType aTrack); + void DropDecodedSamples(TrackType aTrack); bool ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold);