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::OnVideoDecoded(VideoData* aSample) { MOZ_DIAGNOSTIC_ASSERT(!IsSeeking()); mVideoRequest.Complete(); // Adjust the sample time into our reference. int64_t ourTime = aSample->mTime + mVideoSourceDecoder->GetTimestampOffset(); if (aSample->mDiscontinuity) { mVideoDiscontinuity = true; } MSE_DEBUGV("[mTime=%lld mDuration=%lld mDiscontinuity=%d]", ourTime, aSample->mDuration, aSample->mDiscontinuity); if (mDropVideoBeforeThreshold) { if (ourTime < mTimeThreshold) { MSE_DEBUG("mTime=%lld < mTimeThreshold=%lld", ourTime, mTimeThreshold); DoVideoRequest(); return; } mDropVideoBeforeThreshold = false; mTimeThreshold = 0; } // Adjust the sample time into our reference. nsRefPtr<VideoData> newSample = VideoData::ShallowCopyUpdateTimestampAndDuration(aSample, ourTime, aSample->mDuration); mLastVideoTime = newSample->GetEndTime(); if (mVideoDiscontinuity) { newSample->mDiscontinuity = true; mVideoDiscontinuity = false; } mVideoPromise.Resolve(newSample, __func__); }