Bug 1342913: P2. Terminate draining operations when possible. r=gerald
An interesting intermittent condition not previously handled.
We were incorrectly assuming that we always had a decode promise pending when a drain was requested.
If a change of content occurred when resuming from a waiting for data condition: we would have stalled forever as the waiting promise would never have been resolved even after new data was appended.
MozReview-Commit-ID: BQSRSHYqTSe
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -2139,16 +2139,26 @@ MediaFormatReader::Update(TrackType aTra
return;
}
if (aTrack == TrackType::kVideoTrack && mSkipRequest.Exists()) {
LOGV("Skipping in progress, nothing more to do");
return;
}
+ if (decoder.HasWaitingPromise() && decoder.HasCompletedDrain()) {
+ // This situation will occur when a change of stream ID occurred during
+ // internal seeking following a gap encountered in the data, a drain was
+ // requested and has now completed. We need to complete the draining process
+ // so that the new data can be processed.
+ // We can complete the draining operation now as we have no pending
+ // operation when a waiting promise is pending.
+ decoder.mDrainState = DrainState::None;
+ }
+
if (UpdateReceivedNewData(aTrack)) {
LOGV("Nothing more to do");
return;
}
if (decoder.mSeekRequest.Exists()) {
LOGV("Seeking hasn't completed, nothing more to do");
return;
@@ -2225,18 +2235,17 @@ MediaFormatReader::Update(TrackType aTra
nsCString error;
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.mDrainState == DrainState::DrainCompleted
- || decoder.mDrainState == DrainState::DrainAborted) {
+ } else if (decoder.HasCompletedDrain()) {
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 (decoder.mDrainState == DrainState::DrainCompleted
&& decoder.mLastSampleTime
&& !decoder.mNextStreamSourceID) {
// We have completed draining the decoder following WaitingForData.
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -258,16 +258,21 @@ private:
RefPtr<SharedShutdownPromiseHolder> mShutdownPromise;
MozPromiseRequestHolder<MediaDataDecoder::DecodePromise> mDrainRequest;
DrainState mDrainState;
bool HasPendingDrain() const
{
return mDrainState != DrainState::None;
}
+ bool HasCompletedDrain() const
+ {
+ return mDrainState == DrainState::DrainCompleted ||
+ mDrainState == DrainState::DrainAborted;
+ }
void RequestDrain()
{
MOZ_RELEASE_ASSERT(mDrainState == DrainState::None);
mDrainState = DrainState::DrainRequested;
}
uint32_t mNumOfConsecutiveError;
uint32_t mMaxConsecutiveError;