bool MediaSourceDecoder::CanPlayThrough() { MOZ_ASSERT(NS_IsMainThread()); if (NextFrameBufferedStatus() == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE) { return false; } if (IsNaN(mMediaSource->Duration())) { // Don't have any data yet. return false; } TimeUnit duration = TimeUnit::FromSeconds(mMediaSource->Duration()); TimeUnit currentPosition = TimeUnit::FromMicroseconds(CurrentPosition()); if (duration.IsInfinite()) { // We can't make an informed decision and just assume that it's a live stream return true; } else if (duration <= currentPosition) { return true; } // If we have data up to the mediasource's duration or 30s ahead, we can // assume that we can play without interruption. TimeUnit timeAhead = std::min(duration, currentPosition + TimeUnit::FromSeconds(30)); TimeInterval interval(currentPosition, timeAhead, MediaSourceDemuxer::EOS_FUZZ); return GetBuffered().Contains(ClampIntervalToEnd(interval)); }
media::TimeIntervals MediaSourceDecoder::GetSeekable() { MOZ_ASSERT(NS_IsMainThread()); if (!mMediaSource) { NS_WARNING("MediaSource element isn't attached"); return media::TimeIntervals::Invalid(); } media::TimeIntervals seekable; double duration = mMediaSource->Duration(); if (IsNaN(duration)) { // Return empty range. } else if (duration > 0 && mozilla::IsInfinite(duration)) { media::TimeIntervals buffered = GetBuffered(); if (buffered.Length()) { seekable += media::TimeInterval(media::TimeUnit::FromSeconds(0), buffered.GetEnd()); } } else { seekable += media::TimeInterval(media::TimeUnit::FromSeconds(0), media::TimeUnit::FromSeconds(duration)); } MSE_DEBUG("ranges=%s", DumpTimeRanges(seekable).get()); return seekable; }
void MediaDecoderReader::UpdateBuffered() { MOZ_ASSERT(OnTaskQueue()); NS_ENSURE_TRUE_VOID(!mShutdown); mBuffered = GetBuffered(); }
double SourceBuffer::GetBufferedEnd() { MOZ_ASSERT(NS_IsMainThread()); ErrorResult dummy; nsRefPtr<TimeRanges> ranges = GetBuffered(dummy); return ranges->Length() > 0 ? ranges->GetEndTime() : 0; }
bool SourceBufferDecoder::ContainsTime(double aTime) { ErrorResult dummy; nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges(); nsresult rv = GetBuffered(ranges); if (NS_FAILED(rv) || ranges->Length() == 0) { return false; } return ranges->Find(aTime) != dom::TimeRanges::NoIndex; }
void SourceBuffer::GetBufferedStartEndTime(double* aStart, double* aEnd) { ErrorResult dummy; nsRefPtr<TimeRanges> ranges = GetBuffered(dummy); if (!ranges || ranges->Length() == 0) { *aStart = *aEnd = 0.0; return; } *aStart = ranges->Start(0, dummy); *aEnd = ranges->End(ranges->Length() - 1, dummy); }
bool SourceBuffer::ContainsTime(double aTime) { ErrorResult dummy; nsRefPtr<TimeRanges> ranges = GetBuffered(dummy); if (!ranges || ranges->Length() == 0) { return false; } for (uint32_t i = 0; i < ranges->Length(); ++i) { if (aTime >= ranges->Start(i, dummy) && aTime <= ranges->End(i, dummy)) { return true; } } return false; }
MediaDecoderOwner::NextFrameStatus MediaSourceDecoder::NextFrameBufferedStatus() { MOZ_ASSERT(NS_IsMainThread()); if (!mMediaSource || mMediaSource->ReadyState() == dom::MediaSourceReadyState::Closed) { return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE; } // Next frame hasn't been decoded yet. // Use the buffered range to consider if we have the next frame available. TimeUnit currentPosition = TimeUnit::FromMicroseconds(CurrentPosition()); TimeInterval interval(currentPosition, currentPosition + media::TimeUnit::FromMicroseconds(DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED), MediaSourceDemuxer::EOS_FUZZ); return GetBuffered().Contains(ClampIntervalToEnd(interval)) ? MediaDecoderOwner::NEXT_FRAME_AVAILABLE : MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE; }
media::TimeIntervals MediaSourceDecoder::GetSeekable() { MOZ_ASSERT(NS_IsMainThread()); if (!mMediaSource) { NS_WARNING("MediaSource element isn't attached"); return media::TimeIntervals::Invalid(); } media::TimeIntervals seekable; double duration = mMediaSource->Duration(); if (IsNaN(duration)) { // Return empty range. } else if (duration > 0 && mozilla::IsInfinite(duration)) { media::TimeIntervals buffered = GetBuffered(); // 1. If live seekable range is not empty: if (mMediaSource->HasLiveSeekableRange()) { // 1. Let union ranges be the union of live seekable range and the // HTMLMediaElement.buffered attribute. media::TimeIntervals unionRanges = buffered + mMediaSource->LiveSeekableRange(); // 2. Return a single range with a start time equal to the earliest start // time in union ranges and an end time equal to the highest end time in // union ranges and abort these steps. seekable += media::TimeInterval(unionRanges.GetStart(), unionRanges.GetEnd()); return seekable; } if (buffered.Length()) { seekable += media::TimeInterval(media::TimeUnit::FromSeconds(0), buffered.GetEnd()); } } else { seekable += media::TimeInterval(media::TimeUnit::FromSeconds(0), media::TimeUnit::FromSeconds(duration)); } MSE_DEBUG("ranges=%s", DumpTimeRanges(seekable).get()); return seekable; }