Bug 1336947: P1. Drain decoder until no more data is returned. r?gerald
It may not be possible for a decoder to return all drained samples in one go. This is particularly a problem on android where there's a limited amount of memory buffers available.
So we no longer expect the operation to complete in one go, we call Drain until there are no more samples returned.
MozReview-Commit-ID: GbfntKNBDaW
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -1886,32 +1886,38 @@ MediaFormatReader::DrainDecoder(TrackTyp
{
MOZ_ASSERT(OnTaskQueue());
auto& decoder = GetDecoderData(aTrack);
if (!decoder.mNeedDraining || decoder.mDraining) {
return;
}
decoder.mNeedDraining = false;
+ decoder.mDraining = true;
if (!decoder.mDecoder ||
decoder.mNumSamplesInput == decoder.mNumSamplesOutput) {
// No frames to drain.
LOGV("Draining %s with nothing to drain", TrackTypeToStr(aTrack));
NotifyDrainComplete(aTrack);
return;
}
- decoder.mDraining = true;
RefPtr<MediaFormatReader> self = this;
decoder.mDecoder->Drain()
->Then(mTaskQueue, __func__,
[self, this, aTrack, &decoder]
(const MediaDataDecoder::DecodedData& aResults) {
decoder.mDrainRequest.Complete();
- NotifyNewOutput(aTrack, aResults);
- NotifyDrainComplete(aTrack);
+ if (aResults.IsEmpty()) {
+ NotifyDrainComplete(aTrack);
+ } else {
+ NotifyNewOutput(aTrack, aResults);
+ // Let's see if we have any more data available to drain.
+ decoder.mNeedDraining = true;
+ decoder.mDraining = false;
+ }
},
[self, this, aTrack, &decoder](const MediaResult& aError) {
decoder.mDrainRequest.Complete();
NotifyError(aTrack, aError);
})
->Track(decoder.mDrainRequest);
LOG("Requesting %s decoder to drain", TrackTypeToStr(aTrack));
}
@@ -2022,25 +2028,23 @@ MediaFormatReader::Update(TrackType aTra
mVideo.mIsHardwareAccelerated =
mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(error);
}
} else if (decoder.HasFatalError()) {
LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack));
decoder.RejectPromise(decoder.mError.ref(), __func__);
return;
} else if (decoder.mDrainComplete) {
- bool wasDraining = decoder.mDraining;
decoder.mDrainComplete = false;
decoder.mDraining = false;
if (decoder.mDemuxEOS) {
LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
} else if (decoder.mWaitingForData) {
- if (wasDraining && decoder.mLastSampleTime &&
- !decoder.mNextStreamSourceID) {
+ if (decoder.mLastSampleTime && !decoder.mNextStreamSourceID) {
// We have completed draining the decoder following WaitingForData.
// Set up the internal seek machinery to be able to resume from the
// last sample decoded.
LOG("Seeking to last sample time: %lld",
decoder.mLastSampleTime.ref().mStart.ToMicroseconds());
InternalSeek(aTrack,
InternalSeekTarget(decoder.mLastSampleTime.ref(), true));
}
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -246,18 +246,21 @@ public:
// indicate that Decode should be called again before a MediaData is returned.
virtual RefPtr<DecodePromise> Decode(MediaRawData* aSample) = 0;
// Causes all complete samples in the pipeline that can be decoded to be
// output. If the decoder can't produce samples from the current output,
// it drops the input samples. The decoder may be holding onto samples
// that are required to decode samples that it expects to get in future.
// This is called when the demuxer reaches end of stream.
- // This function is asynchronous. The MediaDataDecoder shall resolve the
- // pending DecodePromise will all drained samples.
+ // This function is asynchronous.
+ // The MediaDataDecoder shall resolve the pending DecodePromise with drained
+ // samples. Drain will be called multiple times until the resolved
+ // DecodePromise is empty which indicates that there are no more samples to
+ // drain.
virtual RefPtr<DecodePromise> Drain() = 0;
// Causes all samples in the decoding pipeline to be discarded. When this
// promise resolves, the decoder must be ready to accept new data for
// decoding. This function is called when the demuxer seeks, before decoding
// resumes after the seek. The current DecodePromise if any shall be rejected
// with NS_ERROR_DOM_MEDIA_CANCELED
virtual RefPtr<FlushPromise> Flush() = 0;