Bug 1275538: P2. Drop decoded frames that we know are already too late. r?kamidphish
MozReview-Commit-ID: EZ2Ql2DtTKa
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -1418,38 +1418,68 @@ MediaFormatReader::Reset(TrackType aTrac
decoder.ResetState();
decoder.Flush();
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)
{
MOZ_ASSERT(OnTaskQueue());
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,
&MediaFormatReader::OnVideoSkipFailed));
return;
}
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());
}
// Cancel any pending demux request and pending demuxed samples.
mVideo.mDemuxRequest.DisconnectIfExists();
Reset(TrackType::kVideoTrack);
@@ -1478,16 +1508,19 @@ MediaFormatReader::OnVideoSkipFailed(Med
MOZ_ASSERT(OnTaskQueue());
LOG("Skipping failed, skipped %u frames", aFailure.mSkipped);
mSkipRequest.Complete();
MOZ_ASSERT(mVideo.HasPromise());
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);
break;
case DemuxerFailureReason::CANCELED: MOZ_FALLTHROUGH;
case DemuxerFailureReason::SHUTDOWN:
if (mVideo.HasPromise()) {
mVideo.RejectPromise(CANCELED, __func__);
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -174,16 +174,17 @@ private:
// DecoderCallback proxies the MediaDataDecoderCallback calls to these
// functions.
void Output(TrackType aType, MediaData* aSample);
void InputExhausted(TrackType aTrack);
void Error(TrackType aTrack);
void Reset(TrackType aTrack);
void DrainComplete(TrackType aTrack);
+ void DropDecodedSamples(TrackType aTrack);
bool ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold);
size_t SizeOfQueue(TrackType aTrack);
RefPtr<PDMFactory> mPlatform;
class DecoderCallback : public MediaDataDecoderCallback {