nsRefPtr<MediaDecoderReader::VideoDataPromise> MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold, bool aForceDecodeAhead) { MOZ_ASSERT(OnTaskQueue()); MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking"); MOZ_DIAGNOSTIC_ASSERT(mVideoPromise.IsEmpty(), "No duplicate sample requests"); nsRefPtr<VideoDataPromise> p = mVideoPromise.Ensure(__func__); MSE_DEBUGV("RequestVideoData(%d, %lld), mLastVideoTime=%lld", aSkipToNextKeyframe, aTimeThreshold, mLastVideoTime); if (!mVideoTrack) { MSE_DEBUG("called with no video track"); mVideoPromise.Reject(DECODE_ERROR, __func__); return p; } if (aSkipToNextKeyframe) { mTimeThreshold = aTimeThreshold; mDropAudioBeforeThreshold = true; mDropVideoBeforeThreshold = true; } if (IsSeeking()) { MSE_DEBUG("called mid-seek. Rejecting."); mVideoPromise.Reject(CANCELED, __func__); return p; } MOZ_DIAGNOSTIC_ASSERT(!mVideoSeekRequest.Exists()); mForceVideoDecodeAhead = aForceDecodeAhead; SwitchSourceResult ret = SwitchVideoSource(&mLastVideoTime); switch (ret) { case SOURCE_NEW: GetVideoReader()->ResetDecode(); mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mLastVideoTime), 0) ->Then(OwnerThread(), __func__, this, &MediaSourceReader::CompleteVideoSeekAndDoRequest, &MediaSourceReader::CompleteVideoSeekAndRejectPromise)); break; case SOURCE_NONE: if (!mLastVideoTime) { // This is the first call to RequestVideoData. // Fallback to using decoder with earliest data. mVideoSourceDecoder = FirstDecoder(MediaData::VIDEO_DATA); } if (mLastVideoTime || !mVideoSourceDecoder) { CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime); break; } // Fallback to getting first frame from first decoder. default: DoVideoRequest(); break; } return p; }
void MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason) { MOZ_DIAGNOSTIC_ASSERT(!IsSeeking()); mVideoRequest.Complete(); MSE_DEBUG("aReason=%u IsEnded: %d", aReason, IsEnded()); if (aReason == CANCELED) { mVideoPromise.Reject(CANCELED, __func__); return; } // if End of stream. Force switching past this stream to another reader by // switching to the end of the buffered range. int64_t lastVideoTime = mLastVideoTime; if (aReason == END_OF_STREAM && mVideoSourceDecoder) { AdjustEndTime(&mLastVideoTime, mVideoSourceDecoder); } // See if we can find a different reader that can pick up where we left off. SwitchSourceResult result = SwitchVideoSource(&mLastVideoTime); if (result == SOURCE_NEW) { GetVideoReader()->ResetDecode(); mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mLastVideoTime), 0) ->RefableThen(GetTaskQueue(), __func__, this, &MediaSourceReader::CompleteVideoSeekAndDoRequest, &MediaSourceReader::CompleteVideoSeekAndRejectPromise)); return; } // If we got a DECODE_ERROR and we have buffered data in the requested range // then it must be a genuine decoding error. // Otherwise we can assume that the data was either evicted or explicitely // removed from the source buffer and we should wait for new data. if (aReason == DECODE_ERROR && result != SOURCE_NONE) { mVideoPromise.Reject(DECODE_ERROR, __func__); return; } CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime); if (mLastVideoTime - lastVideoTime >= EOS_FUZZ_US) { // No decoders are available to switch to. We will re-attempt from the last // failing position. mLastVideoTime = lastVideoTime; } }
nsRefPtr<MediaDecoderReader::AudioDataPromise> MediaSourceReader::RequestAudioData() { MOZ_ASSERT(OnTaskQueue()); MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking"); MOZ_DIAGNOSTIC_ASSERT(mAudioPromise.IsEmpty(), "No duplicate sample requests"); nsRefPtr<AudioDataPromise> p = mAudioPromise.Ensure(__func__); MSE_DEBUGV("mLastAudioTime=%lld", mLastAudioTime); if (!mAudioTrack) { MSE_DEBUG("called with no audio track"); mAudioPromise.Reject(DECODE_ERROR, __func__); return p; } if (IsSeeking()) { MSE_DEBUG("called mid-seek. Rejecting."); mAudioPromise.Reject(CANCELED, __func__); return p; } MOZ_DIAGNOSTIC_ASSERT(!mAudioSeekRequest.Exists()); SwitchSourceResult ret = SwitchAudioSource(&mLastAudioTime); switch (ret) { case SOURCE_NEW: GetAudioReader()->ResetDecode(); mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(mLastAudioTime), 0) ->Then(OwnerThread(), __func__, this, &MediaSourceReader::CompleteAudioSeekAndDoRequest, &MediaSourceReader::CompleteAudioSeekAndRejectPromise)); break; case SOURCE_NONE: if (!mLastAudioTime) { // This is the first call to RequestAudioData. // Fallback to using decoder with earliest data. mAudioSourceDecoder = FirstDecoder(MediaData::AUDIO_DATA); } if (mLastAudioTime || !mAudioSourceDecoder) { CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime); break; } // Fallback to getting first frame from first decoder. default: DoAudioRequest(); break; } return p; }