RefPtr<MediaSourceTrackDemuxer::SkipAccessPointPromise> MediaSourceTrackDemuxer::DoSkipToNextRandomAccessPoint( const TimeUnit& aTimeThreadshold) { if (!mManager) { return SkipAccessPointPromise::CreateAndReject( SkipFailureHolder(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, RESULT_DETAIL("manager is detached.")), 0), __func__); } MOZ_ASSERT(OnTaskQueue()); uint32_t parsed = 0; // Ensure that the data we are about to skip to is still available. TimeIntervals buffered = mManager->Buffered(mType); buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2); if (buffered.ContainsWithStrictEnd(aTimeThreadshold)) { bool found; parsed = mManager->SkipToNextRandomAccessPoint(mType, aTimeThreadshold, MediaSourceDemuxer::EOS_FUZZ, found); if (found) { return SkipAccessPointPromise::CreateAndResolve(parsed, __func__); } } SkipFailureHolder holder( mManager->IsEnded() ? NS_ERROR_DOM_MEDIA_END_OF_STREAM : NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, parsed); return SkipAccessPointPromise::CreateAndReject(holder, __func__); }
RefPtr<MediaSourceTrackDemuxer::SeekPromise> MediaSourceTrackDemuxer::DoSeek(media::TimeUnit aTime) { TimeIntervals buffered = mManager->Buffered(mType); buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ); if (!buffered.Contains(aTime)) { // We don't have the data to seek to. return SeekPromise::CreateAndReject(DemuxerFailureReason::WAITING_FOR_DATA, __func__); } TimeUnit seekTime = mManager->Seek(mType, aTime, MediaSourceDemuxer::EOS_FUZZ); bool error; RefPtr<MediaRawData> sample = mManager->GetSample(mType, media::TimeUnit(), error); MOZ_ASSERT(!error && sample); mNextSample = Some(sample); mReset = false; { MonitorAutoLock mon(mMonitor); mNextRandomAccessPoint = mManager->GetNextRandomAccessPoint(mType); } return SeekPromise::CreateAndResolve(seekTime, __func__); }
RefPtr<MediaSourceTrackDemuxer::SamplesPromise> MediaSourceTrackDemuxer::DoGetSamples(int32_t aNumSamples) { if (!mManager) { return SamplesPromise::CreateAndReject( MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, RESULT_DETAIL("manager is detached.")), __func__); } MOZ_ASSERT(OnTaskQueue()); if (mReset) { // If a seek (or reset) was recently performed, we ensure that the data // we are about to retrieve is still available. TimeIntervals buffered = mManager->Buffered(mType); buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2); if (!buffered.Length() && mManager->IsEnded()) { return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__); } if (!buffered.ContainsWithStrictEnd(TimeUnit::Zero())) { return SamplesPromise::CreateAndReject( NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__); } mReset = false; } RefPtr<MediaRawData> sample; if (mNextSample) { sample = mNextSample.ref(); mNextSample.reset(); } else { MediaResult result = NS_OK; sample = mManager->GetSample(mType, MediaSourceDemuxer::EOS_FUZZ, result); if (!sample) { if (result == NS_ERROR_DOM_MEDIA_END_OF_STREAM || result == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) { return SamplesPromise::CreateAndReject( (result == NS_ERROR_DOM_MEDIA_END_OF_STREAM && mManager->IsEnded()) ? NS_ERROR_DOM_MEDIA_END_OF_STREAM : NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__); } return SamplesPromise::CreateAndReject(result, __func__); } } RefPtr<SamplesHolder> samples = new SamplesHolder; samples->mSamples.AppendElement(sample); if (mNextRandomAccessPoint <= sample->mTime) { MonitorAutoLock mon(mMonitor); mNextRandomAccessPoint = mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ); } return SamplesPromise::CreateAndResolve(samples, __func__); }
nsRefPtr<MediaSourceTrackDemuxer::SeekPromise> MediaSourceTrackDemuxer::DoSeek(media::TimeUnit aTime) { TimeIntervals buffered = mManager->Buffered(mType); buffered.SetFuzz(TimeUnit::FromMicroseconds(EOS_FUZZ_US)); if (!buffered.Contains(aTime)) { // We don't have the data to seek to. return SeekPromise::CreateAndReject(DemuxerFailureReason::WAITING_FOR_DATA, __func__); } TimeUnit seekTime = mManager->Seek(mType, aTime, TimeUnit::FromMicroseconds(EOS_FUZZ_US)); { MonitorAutoLock mon(mMonitor); mNextRandomAccessPoint = mManager->GetNextRandomAccessPoint(mType); } return SeekPromise::CreateAndResolve(seekTime, __func__); }
RefPtr<MediaSourceTrackDemuxer::SamplesPromise> MediaSourceTrackDemuxer::DoGetSamples(int32_t aNumSamples) { if (mReset) { // If a seek (or reset) was recently performed, we ensure that the data // we are about to retrieve is still available. TimeIntervals buffered = mManager->Buffered(mType); buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ); if (!buffered.Contains(TimeUnit::FromMicroseconds(0))) { return SamplesPromise::CreateAndReject( mManager->IsEnded() ? DemuxerFailureReason::END_OF_STREAM : DemuxerFailureReason::WAITING_FOR_DATA, __func__); } mReset = false; } bool error = false; RefPtr<MediaRawData> sample; if (mNextSample) { sample = mNextSample.ref(); mNextSample.reset(); } else { sample = mManager->GetSample(mType, MediaSourceDemuxer::EOS_FUZZ, error); if (!sample) { if (error) { return SamplesPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__); } return SamplesPromise::CreateAndReject( mManager->IsEnded() ? DemuxerFailureReason::END_OF_STREAM : DemuxerFailureReason::WAITING_FOR_DATA, __func__); } } RefPtr<SamplesHolder> samples = new SamplesHolder; samples->mSamples.AppendElement(sample); if (mNextRandomAccessPoint.ToMicroseconds() <= sample->mTime) { MonitorAutoLock mon(mMonitor); mNextRandomAccessPoint = mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ); } return SamplesPromise::CreateAndResolve(samples, __func__); }
RefPtr<MediaSourceTrackDemuxer::SkipAccessPointPromise> MediaSourceTrackDemuxer::DoSkipToNextRandomAccessPoint(media::TimeUnit aTimeThreadshold) { uint32_t parsed = 0; // Ensure that the data we are about to skip to is still available. TimeIntervals buffered = mManager->Buffered(mType); buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ); if (buffered.Contains(aTimeThreadshold)) { bool found; parsed = mManager->SkipToNextRandomAccessPoint(mType, aTimeThreadshold, MediaSourceDemuxer::EOS_FUZZ, found); if (found) { return SkipAccessPointPromise::CreateAndResolve(parsed, __func__); } } SkipFailureHolder holder( mManager->IsEnded() ? DemuxerFailureReason::END_OF_STREAM : DemuxerFailureReason::WAITING_FOR_DATA, parsed); return SkipAccessPointPromise::CreateAndReject(holder, __func__); }
RefPtr<MediaSourceTrackDemuxer::SeekPromise> MediaSourceTrackDemuxer::DoSeek(media::TimeUnit aTime) { TimeIntervals buffered = mManager->Buffered(mType); buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ); TimeUnit seekTime = std::max(aTime - mPreRoll, TimeUnit::FromMicroseconds(0)); if (!buffered.Contains(seekTime)) { if (!buffered.Contains(aTime)) { // We don't have the data to seek to. return SeekPromise::CreateAndReject( mManager->IsEnded() ? DemuxerFailureReason::END_OF_STREAM : DemuxerFailureReason::WAITING_FOR_DATA, __func__); } // Theorically we should reject the promise with WAITING_FOR_DATA, // however, to avoid unwanted regressions we assume that if at this time // we don't have the wanted data it won't come later. // Instead of using the pre-rolled time, use the earliest time available in // the interval. TimeIntervals::IndexType index = buffered.Find(aTime); MOZ_ASSERT(index != TimeIntervals::NoIndex); seekTime = buffered[index].mStart; } seekTime = mManager->Seek(mType, seekTime, MediaSourceDemuxer::EOS_FUZZ); bool error; RefPtr<MediaRawData> sample = mManager->GetSample(mType, media::TimeUnit(), error); MOZ_ASSERT(!error && sample); mNextSample = Some(sample); mReset = false; { MonitorAutoLock mon(mMonitor); mNextRandomAccessPoint = mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ); } return SeekPromise::CreateAndResolve(seekTime, __func__); }
RefPtr<MediaSourceTrackDemuxer::SeekPromise> MediaSourceTrackDemuxer::DoSeek(const TimeUnit& aTime) { if (!mManager) { return SeekPromise::CreateAndReject( MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, RESULT_DETAIL("manager is detached.")), __func__); } MOZ_ASSERT(OnTaskQueue()); TimeIntervals buffered = mManager->Buffered(mType); // Fuzz factor represents a +/- threshold. So when seeking it allows the gap // to be twice as big as the fuzz value. We only want to allow EOS_FUZZ gap. buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2); TimeUnit seekTime = std::max(aTime - mPreRoll, TimeUnit::Zero()); if (mManager->IsEnded() && seekTime >= buffered.GetEnd()) { // We're attempting to seek past the end time. Cap seekTime so that we seek // to the last sample instead. seekTime = std::max(mManager->HighestStartTime(mType) - mPreRoll, TimeUnit::Zero()); } if (!buffered.ContainsWithStrictEnd(seekTime)) { if (!buffered.ContainsWithStrictEnd(aTime)) { // We don't have the data to seek to. return SeekPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__); } // Theoretically we should reject the promise with WAITING_FOR_DATA, // however, to avoid unwanted regressions we assume that if at this time // we don't have the wanted data it won't come later. // Instead of using the pre-rolled time, use the earliest time available in // the interval. TimeIntervals::IndexType index = buffered.Find(aTime); MOZ_ASSERT(index != TimeIntervals::NoIndex); seekTime = buffered[index].mStart; } seekTime = mManager->Seek(mType, seekTime, MediaSourceDemuxer::EOS_FUZZ); MediaResult result = NS_OK; RefPtr<MediaRawData> sample = mManager->GetSample(mType, TimeUnit::Zero(), result); MOZ_ASSERT(NS_SUCCEEDED(result) && sample); mNextSample = Some(sample); mReset = false; { MonitorAutoLock mon(mMonitor); mNextRandomAccessPoint = mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ); } return SeekPromise::CreateAndResolve(seekTime, __func__); }