diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 94f343f00f..1fbb2af62c 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -1467,10 +1467,12 @@ HTMLMediaElement::Seek(double aTime, // Clamp the seek target to inside the seekable ranges. nsRefPtr seekable = new dom::TimeRanges(); - if (NS_FAILED(mDecoder->GetSeekable(seekable))) { + media::TimeIntervals seekableIntervals = mDecoder->GetSeekable(); + if (seekableIntervals.IsInvalid()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } + seekableIntervals.ToTimeRanges(seekable); uint32_t length = 0; seekable->GetLength(&length); if (!length) { @@ -1590,9 +1592,8 @@ HTMLMediaElement::Seekable() const { nsRefPtr ranges = new TimeRanges(); if (mDecoder && mReadyState > nsIDOMHTMLMediaElement::HAVE_NOTHING) { - mDecoder->GetSeekable(ranges); + mDecoder->GetSeekable().ToTimeRanges(ranges); } - ranges->Normalize(); return ranges.forget(); } @@ -4127,12 +4128,12 @@ HTMLMediaElement::Buffered() const nsRefPtr ranges = new TimeRanges(); if (mReadyState > nsIDOMHTMLMediaElement::HAVE_NOTHING) { if (mDecoder) { - // If GetBuffered fails we ignore the error result and just return the - // time ranges we found up till the error. - mDecoder->GetBuffered(ranges); + media::TimeIntervals buffered = mDecoder->GetBuffered(); + if (!buffered.IsInvalid()) { + buffered.ToTimeRanges(ranges); + } } } - ranges->Normalize(); return ranges.forget(); } diff --git a/dom/media/Intervals.h b/dom/media/Intervals.h index ad0263f5eb..ccf2930066 100644 --- a/dom/media/Intervals.h +++ b/dom/media/Intervals.h @@ -514,8 +514,8 @@ public: void Shift(const T& aOffset) { for (auto& interval : mIntervals) { - interval.mStart += aOffset; - interval.mEnd += aOffset; + interval.mStart = interval.mStart + aOffset; + interval.mEnd = interval.mEnd + aOffset; } } diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 3694c88f25..92f6235530 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -12,7 +12,6 @@ #include "nsTArray.h" #include "VideoUtils.h" #include "MediaDecoderStateMachine.h" -#include "mozilla/dom/TimeRanges.h" #include "ImageContainer.h" #include "MediaResource.h" #include "nsError.h" @@ -1466,22 +1465,21 @@ bool MediaDecoder::IsMediaSeekable() return mMediaSeekable; } -nsresult MediaDecoder::GetSeekable(dom::TimeRanges* aSeekable) +media::TimeIntervals MediaDecoder::GetSeekable() { - double initialTime = 0.0; - // We can seek in buffered range if the media is seekable. Also, we can seek // in unbuffered ranges if the transport level is seekable (local file or the // server supports range requests, etc.) if (!IsMediaSeekable()) { - return NS_OK; + return media::TimeIntervals(); } else if (!IsTransportSeekable()) { - return GetBuffered(aSeekable); + return GetBuffered(); } else { - double end = IsInfinite() ? std::numeric_limits::infinity() - : initialTime + GetDuration(); - aSeekable->Add(initialTime, end); - return NS_OK; + return media::TimeIntervals( + media::TimeInterval(media::TimeUnit::FromMicroseconds(0), + IsInfinite() ? + media::TimeUnit::FromInfinity() : + media::TimeUnit::FromSeconds(GetDuration()))); } } @@ -1623,9 +1621,9 @@ void MediaDecoder::Invalidate() // Constructs the time ranges representing what segments of the media // are buffered and playable. -nsresult MediaDecoder::GetBuffered(dom::TimeRanges* aBuffered) { - NS_ENSURE_TRUE(mDecoderStateMachine && !mShuttingDown, NS_ERROR_FAILURE); - return mDecoderStateMachine->GetBuffered(aBuffered); +media::TimeIntervals MediaDecoder::GetBuffered() { + NS_ENSURE_TRUE(mDecoderStateMachine && !mShuttingDown, media::TimeIntervals::Invalid()); + return mDecoderStateMachine->GetBuffered(); } size_t MediaDecoder::SizeOfVideoQueue() { diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h index 85a2e070e6..365f9fb5f5 100644 --- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -197,16 +197,11 @@ destroying the MediaDecoder object. #include "MediaStreamGraph.h" #include "AbstractMediaDecoder.h" #include "necko-config.h" +#include "TimeUnits.h" class nsIStreamListener; class nsIPrincipal; -namespace mozilla { -namespace dom { -class TimeRanges; -} -} - namespace mozilla { namespace layers { class Image; @@ -625,7 +620,7 @@ public: virtual bool IsTransportSeekable() override; // Return the time ranges that can be seeked into. - virtual nsresult GetSeekable(dom::TimeRanges* aSeekable); + virtual media::TimeIntervals GetSeekable(); // Set the end time of the media resource. When playback reaches // this point the media pauses. aTime is in seconds. @@ -680,7 +675,7 @@ public: // Constructs the time ranges representing what segments of the media // are buffered and playable. - virtual nsresult GetBuffered(dom::TimeRanges* aBuffered); + virtual media::TimeIntervals GetBuffered(); // Returns the size, in bytes, of the heap memory used by the currently // queued decoded video and audio data. diff --git a/dom/media/MediaDecoderReader.cpp b/dom/media/MediaDecoderReader.cpp index 8a7dcf6cd2..67ae9b0f93 100644 --- a/dom/media/MediaDecoderReader.cpp +++ b/dom/media/MediaDecoderReader.cpp @@ -162,8 +162,8 @@ MediaDecoderReader::SetStartTime(int64_t aStartTime) mStartTime = aStartTime; } -nsresult -MediaDecoderReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered) +media::TimeIntervals +MediaDecoderReader::GetBuffered() { AutoPinned stream(mDecoder->GetResource()); int64_t durationUs = 0; @@ -171,8 +171,7 @@ MediaDecoderReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered) ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); durationUs = mDecoder->GetMediaDuration(); } - GetEstimatedBufferedTimeRanges(stream, durationUs, aBuffered); - return NS_OK; + return GetEstimatedBufferedTimeRanges(stream, durationUs); } int64_t diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h index f63cda624e..11b1a17ad4 100644 --- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -12,13 +12,10 @@ #include "MediaPromise.h" #include "MediaQueue.h" #include "AudioCompactor.h" +#include "TimeUnits.h" namespace mozilla { -namespace dom { -class TimeRanges; -} - class MediaDecoderReader; class SharedDecoderManager; @@ -226,7 +223,7 @@ public: // The OggReader relies on this base implementation not performing I/O, // since in FirefoxOS we can't do I/O on the main thread, where this is // called. - virtual nsresult GetBuffered(dom::TimeRanges* aBuffered); + virtual media::TimeIntervals GetBuffered(); virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio); diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index bea2af9e66..79602bddee 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -21,7 +21,7 @@ #include "mozilla/MathAlgorithms.h" #include "mozilla/mozalloc.h" #include "VideoUtils.h" -#include "mozilla/dom/TimeRanges.h" +#include "TimeUnits.h" #include "nsDeque.h" #include "AudioSegment.h" #include "VideoSegment.h" @@ -1686,17 +1686,13 @@ void MediaDecoderStateMachine::NotifyDataArrived(const char* aBuffer, // // Make sure to only do this if we have a start time, otherwise the reader // doesn't know how to compute GetBuffered. - nsRefPtr buffered = new dom::TimeRanges(); - if (mDecoder->IsInfinite() && (mStartTime != -1) && - NS_SUCCEEDED(mDecoder->GetBuffered(buffered))) - { - uint32_t length = 0; - buffered->GetLength(&length); - if (length) { - double end = 0; - buffered->End(length - 1, &end); + media::TimeIntervals buffered{mDecoder->GetBuffered()}; + if (mDecoder->IsInfinite() && (mStartTime != -1) && !buffered.IsInvalid()) { + bool exists; + media::TimeUnit end{buffered.GetEnd(&exists)}; + if (exists) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - mEndTime = std::max(mEndTime, end * USECS_PER_S); + mEndTime = std::max(mEndTime, end.ToMicroseconds()); } } } @@ -2117,9 +2113,10 @@ bool MediaDecoderStateMachine::HasLowUndecodedData(int64_t aUsecs) return false; } - nsRefPtr buffered = new dom::TimeRanges(); - nsresult rv = mReader->GetBuffered(buffered.get()); - NS_ENSURE_SUCCESS(rv, false); + media::TimeIntervals buffered{mReader->GetBuffered()}; + if (buffered.IsInvalid()) { + return false; + } int64_t endOfDecodedVideoData = INT64_MAX; if (HasVideo() && !VideoQueue().AtEndOfStream()) { @@ -2134,9 +2131,13 @@ bool MediaDecoderStateMachine::HasLowUndecodedData(int64_t aUsecs) } int64_t endOfDecodedData = std::min(endOfDecodedVideoData, endOfDecodedAudioData); - return endOfDecodedData != INT64_MAX && - !buffered->Contains(static_cast(endOfDecodedData) / USECS_PER_S, - static_cast(std::min(endOfDecodedData + aUsecs, GetDuration())) / USECS_PER_S); + if (GetDuration() < endOfDecodedData) { + // Our duration is not up to date. No point buffering. + return false; + } + media::TimeInterval interval(media::TimeUnit::FromMicroseconds(endOfDecodedData), + media::TimeUnit::FromMicroseconds(std::min(endOfDecodedData + aUsecs, GetDuration()))); + return endOfDecodedData != INT64_MAX && !buffered.Contains(interval); } void diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index 7cf45e78be..325bf793dc 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -297,16 +297,16 @@ public: return mState == DECODER_STATE_SEEKING; } - nsresult GetBuffered(dom::TimeRanges* aBuffered) { + media::TimeIntervals GetBuffered() { // It's possible for JS to query .buffered before we've determined the start // time from metadata, in which case the reader isn't ready to be asked this // question. ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); if (mStartTime < 0) { - return NS_OK; + return media::TimeIntervals(); } - return mReader->GetBuffered(aBuffered); + return mReader->GetBuffered(); } void SetPlaybackRate(double aPlaybackRate); diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 6a87db7a86..c4281e73be 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -5,7 +5,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/HTMLMediaElement.h" -#include "mozilla/dom/TimeRanges.h" #include "mozilla/Preferences.h" #include "nsPrintfCString.h" #include "nsSize.h" @@ -1177,8 +1176,8 @@ MediaFormatReader::GetEvictionOffset(double aTime) return std::min(audioOffset, videoOffset); } -nsresult -MediaFormatReader::GetBuffered(dom::TimeRanges* aBuffered) +media::TimeIntervals +MediaFormatReader::GetBuffered() { media::TimeIntervals videoti; media::TimeIntervals audioti; @@ -1202,14 +1201,14 @@ MediaFormatReader::GetBuffered(dom::TimeRanges* aBuffered) } if (HasAudio() && HasVideo()) { videoti.Intersection(audioti); - videoti.ToTimeRanges(aBuffered); + return videoti; } else if (HasAudio()) { - audioti.ToTimeRanges(aBuffered); + return audioti; } else if (HasVideo()) { - videoti.ToTimeRanges(aBuffered); + return videoti; } - return NS_OK; + return media::TimeIntervals(); } bool MediaFormatReader::IsDormantNeeded() diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index a5b862cdb6..c34c5acacb 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -17,10 +17,6 @@ namespace mozilla { -namespace dom { -class TimeRanges; -} - #if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) || defined(MOZ_APPLEMEDIA) || defined(MOZ_FFMPEG) #define READER_DORMANT_HEURISTIC #else @@ -81,7 +77,7 @@ public: uint32_t aLength, int64_t aOffset) override; - virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) override; + virtual media::TimeIntervals GetBuffered() override; // For Media Resource Management virtual void SetIdle() override; diff --git a/dom/media/TimeUnits.h b/dom/media/TimeUnits.h index 693092dc2c..f478481415 100644 --- a/dom/media/TimeUnits.h +++ b/dom/media/TimeUnits.h @@ -8,7 +8,6 @@ #define TIME_UNITS_H #include "Intervals.h" -#include "VideoUtils.h" #include "mozilla/CheckedInt.h" #include "mozilla/FloatingPoint.h" #include "mozilla/dom/TimeRanges.h" @@ -16,6 +15,15 @@ namespace mozilla { namespace media { +// Number of microseconds per second. 1e6. +static const int64_t USECS_PER_S = 1000000; + +// Number of microseconds per millisecond. +static const int64_t USECS_PER_MS = 1000; + +// Number of nanoseconds per second. 1e9. +static const int64_t NSECS_PER_S = 1000000000; + struct Microseconds { Microseconds() : mValue(0) @@ -89,6 +97,10 @@ public: return TimeUnit(aValue.mValue); } + static TimeUnit FromNanoseconds(int64_t aValue) { + return TimeUnit(aValue / 1000); + } + static TimeUnit FromInfinity() { return TimeUnit(INT64_MAX); } @@ -97,6 +109,10 @@ public: return mValue.value(); } + int64_t ToNanoseconds() const { + return mValue.value() * 1000; + } + double ToSeconds() const { if (IsInfinite()) { return PositiveInfinity(); @@ -198,6 +214,17 @@ public: : BaseType(Move(aOther)) {} + static TimeIntervals Invalid() + { + return TimeIntervals(TimeInterval(TimeUnit::FromMicroseconds(INT64_MIN), + TimeUnit::FromMicroseconds(INT64_MIN))); + } + bool IsInvalid() + { + return Length() == 1 && Start(0).ToMicroseconds() == INT64_MIN && + End(0).ToMicroseconds() == INT64_MIN; + } + TimeIntervals() = default; // Make TimeIntervals interchangeable with dom::TimeRanges. diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp index 22424d155e..d16a505ad7 100644 --- a/dom/media/VideoUtils.cpp +++ b/dom/media/VideoUtils.cpp @@ -4,7 +4,7 @@ #include "VideoUtils.h" #include "MediaResource.h" -#include "mozilla/dom/TimeRanges.h" +#include "TimeUnits.h" #include "nsMathUtils.h" #include "nsSize.h" #include "VorbisUtils.h" @@ -70,18 +70,20 @@ static int64_t BytesToTime(int64_t offset, int64_t length, int64_t durationUs) { return int64_t(double(durationUs) * r); } -void GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream, - int64_t aDurationUsecs, - mozilla::dom::TimeRanges* aOutBuffered) +media::TimeIntervals GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream, + int64_t aDurationUsecs) { + media::TimeIntervals buffered; // Nothing to cache if the media takes 0us to play. - if (aDurationUsecs <= 0 || !aStream || !aOutBuffered) - return; + if (aDurationUsecs <= 0 || !aStream) + return buffered; // Special case completely cached files. This also handles local files. if (aStream->IsDataCachedToEndOfResource(0)) { - aOutBuffered->Add(0, double(aDurationUsecs) / USECS_PER_S); - return; + buffered += + media::TimeInterval(media::TimeUnit::FromMicroseconds(0), + media::TimeUnit::FromMicroseconds(aDurationUsecs)); + return buffered; } int64_t totalBytes = aStream->GetLength(); @@ -90,7 +92,7 @@ void GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream, // buffered. This will put us in a state of eternally-low-on-undecoded-data // which is not great, but about the best we can do. if (totalBytes <= 0) - return; + return buffered; int64_t startOffset = aStream->GetNextCachedData(0); while (startOffset >= 0) { @@ -102,12 +104,14 @@ void GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream, int64_t startUs = BytesToTime(startOffset, totalBytes, aDurationUsecs); int64_t endUs = BytesToTime(endOffset, totalBytes, aDurationUsecs); if (startUs != endUs) { - aOutBuffered->Add(double(startUs) / USECS_PER_S, - double(endUs) / USECS_PER_S); + buffered += + media::TimeInterval(media::TimeUnit::FromMicroseconds(startUs), + + media::TimeUnit::FromMicroseconds(endUs)); } startOffset = aStream->GetNextCachedData(endOffset); } - return; + return buffered; } int DownmixAudioToStereo(mozilla::AudioDataValue* buffer, diff --git a/dom/media/VideoUtils.h b/dom/media/VideoUtils.h index e11087f6c6..950cf85536 100644 --- a/dom/media/VideoUtils.h +++ b/dom/media/VideoUtils.h @@ -21,6 +21,7 @@ #include "prtime.h" #include "AudioSampleFormat.h" #include "mozilla/RefPtr.h" +#include "TimeUnits.h" using mozilla::CheckedInt64; using mozilla::CheckedUint64; @@ -116,19 +117,14 @@ void DeleteOnMainThread(nsAutoPtr& aObject) { class MediaResource; -namespace dom { -class TimeRanges; -} - // Estimates the buffered ranges of a MediaResource using a simple // (byteOffset/length)*duration method. Probably inaccurate, but won't // do file I/O, and can be used when we don't have detailed knowledge // of the byte->time mapping of a resource. aDurationUsecs is the duration // of the media in microseconds. Estimated buffered ranges are stored in // aOutBuffered. Ranges are 0-normalized, i.e. in the range of (0,duration]. -void GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream, - int64_t aDurationUsecs, - mozilla::dom::TimeRanges* aOutBuffered); +media::TimeIntervals GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream, + int64_t aDurationUsecs); // Converts from number of audio frames (aFrames) to microseconds, given // the specified audio rate (aRate). Stores result in aOutUsecs. Returns true diff --git a/dom/media/android/AndroidMediaPluginHost.cpp b/dom/media/android/AndroidMediaPluginHost.cpp index 2d95f59bfd..5e390ce73c 100644 --- a/dom/media/android/AndroidMediaPluginHost.cpp +++ b/dom/media/android/AndroidMediaPluginHost.cpp @@ -4,7 +4,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/Preferences.h" -#include "mozilla/dom/TimeRanges.h" #include "MediaResource.h" #include "mozilla/dom/HTMLMediaElement.h" #include "AndroidMediaPluginHost.h" diff --git a/dom/media/android/AndroidMediaReader.cpp b/dom/media/android/AndroidMediaReader.cpp index 90be487b6e..847da8db5b 100644 --- a/dom/media/android/AndroidMediaReader.cpp +++ b/dom/media/android/AndroidMediaReader.cpp @@ -5,7 +5,6 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AndroidMediaReader.h" #include "mozilla/TimeStamp.h" -#include "mozilla/dom/TimeRanges.h" #include "mozilla/gfx/Point.h" #include "MediaResource.h" #include "VideoUtils.h" diff --git a/dom/media/fmp4/MP4Reader.cpp b/dom/media/fmp4/MP4Reader.cpp index 3e38c7d710..bd02743012 100644 --- a/dom/media/fmp4/MP4Reader.cpp +++ b/dom/media/fmp4/MP4Reader.cpp @@ -18,7 +18,6 @@ #include "SharedThreadPool.h" #include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" -#include "mozilla/dom/TimeRanges.h" #include "mp4_demuxer/AnnexB.h" #include "mp4_demuxer/H264.h" #include "SharedDecoderManager.h" @@ -1017,12 +1016,13 @@ MP4Reader::GetEvictionOffset(double aTime) return mDemuxer->GetEvictionOffset(aTime * 1000000.0); } -nsresult -MP4Reader::GetBuffered(dom::TimeRanges* aBuffered) +media::TimeIntervals +MP4Reader::GetBuffered() { MonitorAutoLock mon(mDemuxerMonitor); + media::TimeIntervals buffered; if (!mIndexReady) { - return NS_OK; + return buffered; } UpdateIndex(); MOZ_ASSERT(mStartTime != -1, "Need to finish metadata decode first"); @@ -1035,12 +1035,13 @@ MP4Reader::GetBuffered(dom::TimeRanges* aBuffered) nsTArray> timeRanges; mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges); for (size_t i = 0; i < timeRanges.Length(); i++) { - aBuffered->Add((timeRanges[i].start - mStartTime) / 1000000.0, - (timeRanges[i].end - mStartTime) / 1000000.0); + buffered += media::TimeInterval( + media::TimeUnit::FromMicroseconds(timeRanges[i].start - mStartTime), + media::TimeUnit::FromMicroseconds(timeRanges[i].end - mStartTime)); } } - return NS_OK; + return buffered; } bool MP4Reader::IsDormantNeeded() diff --git a/dom/media/fmp4/MP4Reader.h b/dom/media/fmp4/MP4Reader.h index 0bca2da881..413f24d4f8 100644 --- a/dom/media/fmp4/MP4Reader.h +++ b/dom/media/fmp4/MP4Reader.h @@ -19,10 +19,6 @@ namespace mozilla { -namespace dom { -class TimeRanges; -} - typedef std::deque> MediaSampleQueue; class MP4Stream; @@ -68,7 +64,7 @@ public: virtual int64_t GetEvictionOffset(double aTime) override; virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) override; - virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) override; + virtual media::TimeIntervals GetBuffered() override; // For Media Resource Management virtual void SetIdle() override; diff --git a/dom/media/gstreamer/GStreamerReader.cpp b/dom/media/gstreamer/GStreamerReader.cpp index 27b1eafb2d..2104cb83c7 100644 --- a/dom/media/gstreamer/GStreamerReader.cpp +++ b/dom/media/gstreamer/GStreamerReader.cpp @@ -13,7 +13,6 @@ #include "GStreamerAllocator.h" #include "GStreamerFormatHelper.h" #include "VideoUtils.h" -#include "mozilla/dom/TimeRanges.h" #include "mozilla/Endian.h" #include "mozilla/Preferences.h" #include "mozilla/unused.h" @@ -804,10 +803,11 @@ GStreamerReader::Seek(int64_t aTarget, int64_t aEndTime) return SeekPromise::CreateAndResolve(aTarget, __func__); } -nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered) +media::TimeIntervals GStreamerReader::GetBuffered() { + media::TimeIntervals buffered; if (!mInfo.HasValidMedia()) { - return NS_OK; + return buffered; } AutoPinned resource(mDecoder->GetResource()); @@ -823,11 +823,12 @@ nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered) duration = mDecoder->GetMediaDuration(); } - double end = (double) duration / GST_MSECOND; LOG(PR_LOG_DEBUG, "complete range [0, %f] for [0, %li]", - end, GetDataLength()); - aBuffered->Add(0, end); - return NS_OK; + (double) duration / GST_MSECOND, GetDataLength()); + buffered += + media::TimeInterval(media::TimeUnit::FromMicroseconds(0), + media::TimeUnit::FromMicroseconds(duration)); + return buffered; } for(uint32_t index = 0; index < ranges.Length(); index++) { @@ -842,14 +843,16 @@ nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered) endOffset, GST_FORMAT_TIME, &endTime)) continue; - double start = (double) GST_TIME_AS_USECONDS (startTime) / GST_MSECOND; - double end = (double) GST_TIME_AS_USECONDS (endTime) / GST_MSECOND; LOG(PR_LOG_DEBUG, "adding range [%f, %f] for [%li %li] size %li", - start, end, startOffset, endOffset, GetDataLength()); - aBuffered->Add(start, end); + (double) GST_TIME_AS_USECONDS (startTime) / GST_MSECOND, + (double) GST_TIME_AS_USECONDS (endTime) / GST_MSECOND, + startOffset, endOffset, GetDataLength()); + buffered += + media::TimeInterval(media::TimeUnit::FromMicroseconds(GST_TIME_AS_USECONDS(startTime)), + media::TimeUnit::FromMicroseconds(GST_TIME_AS_USECONDS(endTime))); } - return NS_OK; + return buffered; } void GStreamerReader::ReadAndPushData(guint aLength) diff --git a/dom/media/gstreamer/GStreamerReader.h b/dom/media/gstreamer/GStreamerReader.h index 4e430d9ae5..fd6bfc3122 100644 --- a/dom/media/gstreamer/GStreamerReader.h +++ b/dom/media/gstreamer/GStreamerReader.h @@ -29,10 +29,6 @@ struct GstURIDecodeBin; namespace mozilla { -namespace dom { -class TimeRanges; -} - class AbstractMediaDecoder; typedef enum { @@ -59,7 +55,7 @@ public: MetadataTags** aTags) override; virtual nsRefPtr Seek(int64_t aTime, int64_t aEndTime) override; - virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) override; + virtual media::TimeIntervals GetBuffered() override; virtual void NotifyDataArrived(const char *aBuffer, uint32_t aLength, diff --git a/dom/media/gtest/TestMP4Reader.cpp b/dom/media/gtest/TestMP4Reader.cpp index c2cde8fb68..9959ddd0b8 100644 --- a/dom/media/gtest/TestMP4Reader.cpp +++ b/dom/media/gtest/TestMP4Reader.cpp @@ -10,7 +10,7 @@ #include "MockMediaResource.h" #include "MockMediaDecoderOwner.h" #include "mozilla/Preferences.h" -#include "mozilla/dom/TimeRanges.h" +#include "TimeUnits.h" using namespace mozilla; using namespace mozilla::dom; @@ -83,15 +83,10 @@ TEST(MP4Reader, BufferedRange) // Video 3-4 sec, audio 2.986666-4.010666 sec b->resource->MockAddBufferedRange(248400, 327455); - nsRefPtr ranges = new TimeRanges(); - EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges)); - EXPECT_EQ(1U, ranges->Length()); - double start = 0; - EXPECT_EQ(NS_OK, ranges->Start(0, &start)); - EXPECT_NEAR(270000 / 90000.0, start, 0.000001); - double end = 0; - EXPECT_EQ(NS_OK, ranges->End(0, &end)); - EXPECT_NEAR(360000 / 90000.0, end, 0.000001); + media::TimeIntervals ranges = b->reader->GetBuffered(); + EXPECT_EQ(1U, ranges.Length()); + EXPECT_NEAR(270000 / 90000.0, ranges.Start(0).ToSeconds(), 0.000001); + EXPECT_NEAR(360000 / 90000.0, ranges.End(0).ToSeconds(), 0.000001); } TEST(MP4Reader, BufferedRangeMissingLastByte) @@ -104,15 +99,10 @@ TEST(MP4Reader, BufferedRangeMissingLastByte) b->resource->MockAddBufferedRange(248400, 324912); b->resource->MockAddBufferedRange(324913, 327455); - nsRefPtr ranges = new TimeRanges(); - EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges)); - EXPECT_EQ(1U, ranges->Length()); - double start = 0; - EXPECT_EQ(NS_OK, ranges->Start(0, &start)); - EXPECT_NEAR(270000.0 / 90000.0, start, 0.000001); - double end = 0; - EXPECT_EQ(NS_OK, ranges->End(0, &end)); - EXPECT_NEAR(357000 / 90000.0, end, 0.000001); + media::TimeIntervals ranges = b->reader->GetBuffered(); + EXPECT_EQ(1U, ranges.Length()); + EXPECT_NEAR(270000.0 / 90000.0, ranges.Start(0).ToSeconds(), 0.000001); + EXPECT_NEAR(357000 / 90000.0, ranges.End(0).ToSeconds(), 0.000001); } TEST(MP4Reader, BufferedRangeSyncFrame) @@ -125,15 +115,10 @@ TEST(MP4Reader, BufferedRangeSyncFrame) b->resource->MockClearBufferedRanges(); b->resource->MockAddBufferedRange(146336, 327455); - nsRefPtr ranges = new TimeRanges(); - EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges)); - EXPECT_EQ(1U, ranges->Length()); - double start = 0; - EXPECT_EQ(NS_OK, ranges->Start(0, &start)); - EXPECT_NEAR(270000.0 / 90000.0, start, 0.000001); - double end = 0; - EXPECT_EQ(NS_OK, ranges->End(0, &end)); - EXPECT_NEAR(360000 / 90000.0, end, 0.000001); + media::TimeIntervals ranges = b->reader->GetBuffered(); + EXPECT_EQ(1U, ranges.Length()); + EXPECT_NEAR(270000.0 / 90000.0, ranges.Start(0).ToSeconds(), 0.000001); + EXPECT_NEAR(360000 / 90000.0, ranges.End(0).ToSeconds(), 0.000001); } TEST(MP4Reader, CompositionOrder) @@ -183,23 +168,14 @@ TEST(MP4Reader, CompositionOrder) b->resource->MockAddBufferedRange(12616, 13196); b->resource->MockAddBufferedRange(13220, 13901); - nsRefPtr ranges = new TimeRanges(); - EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges)); - EXPECT_EQ(2U, ranges->Length()); + media::TimeIntervals ranges = b->reader->GetBuffered(); + EXPECT_EQ(2U, ranges.Length()); - double start = 0; - EXPECT_EQ(NS_OK, ranges->Start(0, &start)); - EXPECT_NEAR(166.0 / 2500.0, start, 0.000001); - double end = 0; - EXPECT_EQ(NS_OK, ranges->End(0, &end)); - EXPECT_NEAR(332.0 / 2500.0, end, 0.000001); + EXPECT_NEAR(166.0 / 2500.0, ranges.Start(0).ToSeconds(), 0.000001); + EXPECT_NEAR(332.0 / 2500.0, ranges.End(0).ToSeconds(), 0.000001); - start = 0; - EXPECT_EQ(NS_OK, ranges->Start(1, &start)); - EXPECT_NEAR(581.0 / 2500.0, start, 0.000001); - end = 0; - EXPECT_EQ(NS_OK, ranges->End(1, &end)); - EXPECT_NEAR(11255.0 / 44100.0, end, 0.000001); + EXPECT_NEAR(581.0 / 2500.0, ranges.Start(1).ToSeconds(), 0.000001); + EXPECT_NEAR(11255.0 / 44100.0, ranges.End(1).ToSeconds(), 0.000001); } TEST(MP4Reader, Normalised) @@ -233,14 +209,9 @@ TEST(MP4Reader, Normalised) b->resource->MockClearBufferedRanges(); b->resource->MockAddBufferedRange(48, 13901); - nsRefPtr ranges = new TimeRanges(); - EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges)); - EXPECT_EQ(1U, ranges->Length()); + media::TimeIntervals ranges = b->reader->GetBuffered(); + EXPECT_EQ(1U, ranges.Length()); - double start = 0; - EXPECT_EQ(NS_OK, ranges->Start(0, &start)); - EXPECT_NEAR(166.0 / 2500.0, start, 0.000001); - double end = 0; - EXPECT_EQ(NS_OK, ranges->End(0, &end)); - EXPECT_NEAR(11255.0 / 44100.0, end, 0.000001); + EXPECT_NEAR(166.0 / 2500.0, ranges.Start(0).ToSeconds(), 0.000001); + EXPECT_NEAR(11255.0 / 44100.0, ranges.End(0).ToSeconds(), 0.000001); } diff --git a/dom/media/mediasource/MediaSource.cpp b/dom/media/mediasource/MediaSource.cpp index ef5e9a2c74..3831b83eee 100644 --- a/dom/media/mediasource/MediaSource.cpp +++ b/dom/media/mediasource/MediaSource.cpp @@ -16,7 +16,6 @@ #include "mozilla/Preferences.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/HTMLMediaElement.h" -#include "mozilla/dom/TimeRanges.h" #include "mozilla/mozalloc.h" #include "nsContentTypeParser.h" #include "nsDebug.h" diff --git a/dom/media/mediasource/MediaSourceDecoder.cpp b/dom/media/mediasource/MediaSourceDecoder.cpp index 4ed1edc84d..d52fedcdf1 100644 --- a/dom/media/mediasource/MediaSourceDecoder.cpp +++ b/dom/media/mediasource/MediaSourceDecoder.cpp @@ -7,7 +7,6 @@ #include "prlog.h" #include "mozilla/dom/HTMLMediaElement.h" -#include "mozilla/dom/TimeRanges.h" #include "MediaDecoderStateMachine.h" #include "MediaSource.h" #include "MediaSourceReader.h" @@ -68,26 +67,30 @@ MediaSourceDecoder::Load(nsIStreamListener**, MediaDecoder*) return ScheduleStateMachineThread(); } -nsresult -MediaSourceDecoder::GetSeekable(dom::TimeRanges* aSeekable) +media::TimeIntervals +MMediaSourceDecoder::GetSeekable() { MOZ_ASSERT(NS_IsMainThread()); if (!mMediaSource) { - return NS_ERROR_FAILURE; + 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)) { - nsRefPtr bufferedRanges = new dom::TimeRanges(); - mReader->GetBuffered(bufferedRanges); - aSeekable->Add(bufferedRanges->GetStartTime(), bufferedRanges->GetEndTime()); + media::TimeIntervals buffered = mReader->GetBuffered(); + if (buffered.Length()) { + seekable += media::TimeInterval(buffered.GetStart(), buffered.GetEnd()); + } } else { - aSeekable->Add(0, duration); + seekable += media::TimeInterval(media::TimeUnit::FromSeconds(0), + media::TimeUnit::FromSeconds(duration)); } - MSE_DEBUG("ranges=%s", DumpTimeRanges(aSeekable).get()); - return NS_OK; + MSE_DEBUG("ranges=%s", DumpTimeRanges(seekable).get()); + return seekable; } void @@ -316,22 +319,25 @@ MediaSourceDecoder::SelectDecoder(int64_t aTarget, { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); + media::TimeUnit target{media::TimeUnit::FromMicroseconds(aTarget)}; + media::TimeUnit tolerance{media::TimeUnit::FromMicroseconds(aTolerance + aTarget)}; + + // aTolerance gives a slight bias toward the start of a range only. // Consider decoders in order of newest to oldest, as a newer decoder // providing a given buffered range is expected to replace an older one. for (int32_t i = aTrackDecoders.Length() - 1; i >= 0; --i) { nsRefPtr newDecoder = aTrackDecoders[i]; - nsRefPtr ranges = new dom::TimeRanges(); - newDecoder->GetBuffered(ranges); - if (ranges->Find(double(aTarget) / USECS_PER_S, - double(aTolerance) / USECS_PER_S) == dom::TimeRanges::NoIndex) { - MSE_DEBUGV("SelectDecoder(%lld fuzz:%lld) newDecoder=%p (%d/%d) target not in ranges=%s", - aTarget, aTolerance, newDecoder.get(), i+1, - aTrackDecoders.Length(), DumpTimeRanges(ranges).get()); - continue; + media::TimeIntervals ranges = newDecoder->GetBuffered(); + for (uint32_t j = 0; j < ranges.Length(); j++) { + if (target < ranges.End(j) && tolerance >= ranges.Start(j)) { + return newDecoder.forget(); + } } - return newDecoder.forget(); + MSE_DEBUGV("SelectDecoder(%lld fuzz:%lld) newDecoder=%p (%d/%d) target not in ranges=%s", + aTarget, aTolerance, newDecoder.get(), i+1, + aTrackDecoders.Length(), DumpTimeRanges(ranges).get()); } return nullptr; diff --git a/dom/media/mediasource/MediaSourceDecoder.h b/dom/media/mediasource/MediaSourceDecoder.h index eae671581a..287fd06065 100644 --- a/dom/media/mediasource/MediaSourceDecoder.h +++ b/dom/media/mediasource/MediaSourceDecoder.h @@ -38,7 +38,7 @@ public: virtual MediaDecoder* Clone() override; virtual MediaDecoderStateMachine* CreateStateMachine() override; virtual nsresult Load(nsIStreamListener**, MediaDecoder*) override; - virtual nsresult GetSeekable(dom::TimeRanges* aSeekable) override; + virtual media::TimeIntervals GetSeekable() override; virtual void Shutdown() override; diff --git a/dom/media/mediasource/MediaSourceReader.cpp b/dom/media/mediasource/MediaSourceReader.cpp index c1ae4a462c..385bdb051c 100644 --- a/dom/media/mediasource/MediaSourceReader.cpp +++ b/dom/media/mediasource/MediaSourceReader.cpp @@ -7,7 +7,6 @@ #include #include "prlog.h" -#include "mozilla/dom/TimeRanges.h" #include "DecoderTraits.h" #include "MediaDecoderOwner.h" #include "MediaFormatReader.h" @@ -41,8 +40,6 @@ extern PRLogModuleInfo* GetMediaSourceLog(); // default value used in Blink, kDefaultBufferDurationInMs. #define EOS_FUZZ_US 125000 -using mozilla::dom::TimeRanges; - namespace mozilla { MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder) @@ -230,10 +227,9 @@ static void AdjustEndTime(int64_t* aEndTime, SourceBufferDecoder* aDecoder) { if (aDecoder) { - nsRefPtr ranges = new dom::TimeRanges(); - aDecoder->GetBuffered(ranges); - if (ranges->Length() > 0) { - int64_t end = std::ceil(ranges->GetEndTime() * USECS_PER_S); + media::TimeIntervals ranges = aDecoder->GetBuffered(); + if (ranges.Length()) { + int64_t end = ranges.GetEnd().ToMicroseconds(); *aEndTime = std::max(*aEndTime, end); } } @@ -585,9 +581,8 @@ MediaSourceReader::SwitchAudioSource(int64_t* aTarget) // A decoder buffered range is continuous. We would have failed the exact // search but succeeded the fuzzy one if our target was shortly before // start time. - nsRefPtr ranges = new dom::TimeRanges(); - newDecoder->GetBuffered(ranges); - int64_t startTime = ranges->GetStartTime() * USECS_PER_S; + media::TimeIntervals ranges = newDecoder->GetBuffered(); + int64_t startTime = ranges.GetStart().ToMicroseconds(); if (*aTarget < startTime) { *aTarget = startTime; } @@ -631,9 +626,8 @@ MediaSourceReader::SwitchVideoSource(int64_t* aTarget) // A decoder buffered range is continuous. We would have failed the exact // search but succeeded the fuzzy one if our target was shortly before // start time. - nsRefPtr ranges = new dom::TimeRanges(); - newDecoder->GetBuffered(ranges); - int64_t startTime = ranges->GetStartTime() * USECS_PER_S; + media::TimeIntervals ranges = newDecoder->GetBuffered(); + int64_t startTime = ranges.GetStart().ToMicroseconds(); if (*aTarget < startTime) { *aTarget = startTime; } @@ -982,44 +976,39 @@ MediaSourceReader::DoVideoSeek() MSE_DEBUG("reader=%p", GetVideoReader()); } -nsresult -MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered) +media::TimeIntervals +MediaSourceReader::GetBuffered() { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - MOZ_ASSERT(aBuffered->Length() == 0); - if (mTrackBuffers.IsEmpty()) { - return NS_OK; + media::TimeIntervals buffered; + + media::TimeUnit highestEndTime; + nsTArray activeRanges; + // Must set the capacity of the nsTArray first: bug #1164444 + activeRanges.SetCapacity(mTrackBuffers.Length()); + + for (const auto& trackBuffer : mTrackBuffers) { + activeRanges.AppendElement(trackBuffer->Buffered()); + highestEndTime = std::max(highestEndTime, activeRanges.LastElement().GetEnd()); } - double highestEndTime = 0; + buffered += + media::TimeInterval(media::TimeUnit::FromMicroseconds(0), highestEndTime); - nsTArray> activeRanges; - for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) { - nsRefPtr r = new TimeRanges(); - mTrackBuffers[i]->Buffered(r); - activeRanges.AppendElement(r); - highestEndTime = std::max(highestEndTime, activeRanges.LastElement()->GetEndTime()); - } - - TimeRanges* intersectionRanges = aBuffered; - intersectionRanges->Add(0, highestEndTime); - - for (uint32_t i = 0; i < activeRanges.Length(); ++i) { - TimeRanges* sourceRanges = activeRanges[i]; - - if (IsEnded()) { + for (auto& range : activeRanges) { + if (IsEnded() && range.Length()) { // Set the end time on the last range to highestEndTime by adding a // new range spanning the current end time to highestEndTime, which // Normalize() will then merge with the old last range. - sourceRanges->Add(sourceRanges->GetEndTime(), highestEndTime); - sourceRanges->Normalize(); + range += + media::TimeInterval(range.GetEnd(), highestEndTime); } - intersectionRanges->Intersection(sourceRanges); + buffered.Intersection(range); } - MSE_DEBUG("ranges=%s", DumpTimeRanges(intersectionRanges).get()); - return NS_OK; + MSE_DEBUG("ranges=%s", DumpTimeRanges(buffered).get()); + return buffered; } already_AddRefed @@ -1035,15 +1024,14 @@ MediaSourceReader::FirstDecoder(MediaData::Type aType) } nsRefPtr firstDecoder; - double lowestStartTime = PositiveInfinity(); + media::TimeUnit lowestStartTime{media::TimeUnit::FromInfinity()}; for (uint32_t i = 0; i < decoders.Length(); ++i) { - nsRefPtr r = new TimeRanges(); - decoders[i]->GetBuffered(r); - double start = r->GetStartTime(); - if (start < 0) { + media::TimeIntervals r = decoders[i]->GetBuffered(); + if (!r.Length()) { continue; } + media::TimeUnit start = r.GetStart(); if (start < lowestStartTime) { firstDecoder = decoders[i]; lowestStartTime = start; @@ -1203,9 +1191,8 @@ MediaSourceReader::IsNearEnd(MediaData::Type aType, int64_t aTime) } TrackBuffer* trackBuffer = aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack; - nsRefPtr buffered = new dom::TimeRanges(); - trackBuffer->Buffered(buffered); - return aTime >= (buffered->GetEndTime() * USECS_PER_S - EOS_FUZZ_US); + media::TimeIntervals buffered = trackBuffer->Buffered(); + return aTime >= buffered.GetEnd().ToMicroseconds() - EOS_FUZZ_US; } int64_t @@ -1214,10 +1201,9 @@ MediaSourceReader::LastSampleTime(MediaData::Type aType) ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); TrackBuffer* trackBuffer = - aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack; - nsRefPtr buffered = new dom::TimeRanges(); - trackBuffer->Buffered(buffered); - return buffered->GetEndTime() * USECS_PER_S - 1; + aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack; + media::TimeIntervals buffered = trackBuffer->Buffered(); + return buffered.GetEnd().ToMicroseconds() - 1; } void @@ -1238,8 +1224,7 @@ MediaSourceReader::GetMozDebugReaderData(nsAString& aString) for (int32_t i = mAudioTrack->Decoders().Length() - 1; i >= 0; --i) { nsRefPtr newReader = mAudioTrack->Decoders()[i]->GetReader(); - nsRefPtr ranges = new dom::TimeRanges(); - mAudioTrack->Decoders()[i]->GetBuffered(ranges); + media::TimeIntervals ranges = mAudioTrack->Decoders()[i]->GetBuffered(); result += nsPrintfCString("\t\tReader %d: %p ranges=%s active=%s size=%lld\n", i, newReader.get(), DumpTimeRanges(ranges).get(), newReader.get() == GetAudioReader() ? "true" : "false", @@ -1252,8 +1237,7 @@ MediaSourceReader::GetMozDebugReaderData(nsAString& aString) for (int32_t i = mVideoTrack->Decoders().Length() - 1; i >= 0; --i) { nsRefPtr newReader = mVideoTrack->Decoders()[i]->GetReader(); - nsRefPtr ranges = new dom::TimeRanges(); - mVideoTrack->Decoders()[i]->GetBuffered(ranges); + media::TimeIntervals ranges = mVideoTrack->Decoders()[i]->GetBuffered(); result += nsPrintfCString("\t\tReader %d: %p ranges=%s active=%s size=%lld\n", i, newReader.get(), DumpTimeRanges(ranges).get(), newReader.get() == GetVideoReader() ? "true" : "false", diff --git a/dom/media/mediasource/MediaSourceReader.h b/dom/media/mediasource/MediaSourceReader.h index 9bddc341a9..981e503cc3 100644 --- a/dom/media/mediasource/MediaSourceReader.h +++ b/dom/media/mediasource/MediaSourceReader.h @@ -112,7 +112,7 @@ public: nsresult ResetDecode() override; // Acquires the decoder monitor, and is thus callable on any thread. - nsresult GetBuffered(dom::TimeRanges* aBuffered) override; + media::TimeIntervals GetBuffered() override; already_AddRefed CreateSubDecoder(const nsACString& aType, int64_t aTimestampOffset /* microseconds */); diff --git a/dom/media/mediasource/MediaSourceUtils.cpp b/dom/media/mediasource/MediaSourceUtils.cpp index 83bba60011..ec88728aba 100644 --- a/dom/media/mediasource/MediaSourceUtils.cpp +++ b/dom/media/mediasource/MediaSourceUtils.cpp @@ -6,24 +6,24 @@ #include "MediaSourceUtils.h" #include "prlog.h" -#include "mozilla/dom/TimeRanges.h" #include "nsPrintfCString.h" namespace mozilla { nsCString -DumpTimeRanges(dom::TimeRanges* aRanges) +DumpTimeRanges(const media::TimeIntervals& aRanges) { nsCString dump; dump = "["; - for (uint32_t i = 0; i < aRanges->Length(); ++i) { + for (uint32_t i = 0; i < aRanges.Length(); ++i) { if (i > 0) { dump += ", "; } - ErrorResult dummy; - dump += nsPrintfCString("(%f, %f)", aRanges->Start(i, dummy), aRanges->End(i, dummy)); + dump += nsPrintfCString("(%f, %f)", + aRanges.Start(i).ToSeconds(), + aRanges.End(i).ToSeconds()); } dump += "]"; diff --git a/dom/media/mediasource/MediaSourceUtils.h b/dom/media/mediasource/MediaSourceUtils.h index 35365eb1a6..2bda99f1b9 100644 --- a/dom/media/mediasource/MediaSourceUtils.h +++ b/dom/media/mediasource/MediaSourceUtils.h @@ -8,14 +8,11 @@ #define MOZILLA_MEDIASOURCEUTILS_H_ #include "nsString.h" +#include "TimeUnits.h" namespace mozilla { -namespace dom { - class TimeRanges; -} // namespace dom - -nsCString DumpTimeRanges(dom::TimeRanges* aRanges); +nsCString DumpTimeRanges(const media::TimeIntervals& aRanges); } // namespace mozilla diff --git a/dom/media/mediasource/SourceBuffer.cpp b/dom/media/mediasource/SourceBuffer.cpp index eaa9bf2945..c05b9ea02c 100644 --- a/dom/media/mediasource/SourceBuffer.cpp +++ b/dom/media/mediasource/SourceBuffer.cpp @@ -146,17 +146,14 @@ SourceBuffer::GetBuffered(ErrorResult& aRv) aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } - nsRefPtr ranges = new TimeRanges(); - double highestEndTime = mTrackBuffer->Buffered(ranges); - if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) { - // Set the end time on the last range to highestEndTime by adding a - // new range spanning the current end time to highestEndTime, which - // Normalize() will then merge with the old last range. - ranges->Add(ranges->GetEndTime(), highestEndTime); - ranges->Normalize(); - } + // We only manage a single trackbuffer in our source buffer. + // As such, there's no need to adjust the end of the trackbuffers as per + // Step 4: http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered + media::TimeIntervals ranges = mTrackBuffer->Buffered(); MSE_DEBUGV("ranges=%s", DumpTimeRanges(ranges).get()); - return ranges.forget(); + nsRefPtr tr = new dom::TimeRanges(); + ranges.ToTimeRanges(tr); + return tr.forget(); } void @@ -287,8 +284,8 @@ SourceBuffer::DoRangeRemoval(double aStart, double aEnd) { MSE_DEBUG("DoRangeRemoval(%f, %f)", aStart, aEnd); if (mTrackBuffer && !IsInfinite(aStart)) { - mTrackBuffer->RangeRemoval(media::Microseconds::FromSeconds(aStart), - media::Microseconds::FromSeconds(aEnd)); + mTrackBuffer->RangeRemoval(media::TimeUnit::FromSeconds(aStart), + media::TimeUnit::FromSeconds(aEnd)); } } diff --git a/dom/media/mediasource/SourceBufferDecoder.cpp b/dom/media/mediasource/SourceBufferDecoder.cpp index b511a30925..878cefeeb6 100644 --- a/dom/media/mediasource/SourceBufferDecoder.cpp +++ b/dom/media/mediasource/SourceBufferDecoder.cpp @@ -9,7 +9,6 @@ #include "prlog.h" #include "AbstractMediaDecoder.h" #include "MediaDecoderReader.h" -#include "mozilla/dom/TimeRanges.h" #ifdef PR_LOGGING extern PRLogModuleInfo* GetMediaSourceLog(); @@ -238,24 +237,23 @@ SourceBufferDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, in mParentDecoder->NotifyDataArrived(nullptr, 0, 0); } -nsresult -SourceBufferDecoder::GetBuffered(dom::TimeRanges* aBuffered) +media::TimeIntervals +SourceBufferDecoder::GetBuffered() { - nsresult rv = mReader->GetBuffered(aBuffered); - if (NS_FAILED(rv)) { - return rv; + media::TimeIntervals buffered = mReader->GetBuffered(); + if (buffered.IsInvalid()) { + return buffered; } // Adjust buffered range according to timestamp offset. - aBuffered->Shift((double)mTimestampOffset / USECS_PER_S); + buffered.Shift(media::TimeUnit::FromMicroseconds(mTimestampOffset)); if (!WasTrimmed()) { - return NS_OK; + return buffered; } - nsRefPtr tr = new dom::TimeRanges(); - tr->Add(0, mTrimmedOffset); - aBuffered->Intersection(tr); - return NS_OK; + media::TimeInterval filter(media::TimeUnit::FromSeconds(0), + media::TimeUnit::FromSeconds(mTrimmedOffset)); + return buffered.Intersection(filter); } int64_t diff --git a/dom/media/mediasource/SourceBufferDecoder.h b/dom/media/mediasource/SourceBufferDecoder.h index 5bf0791ec8..e52f694c72 100644 --- a/dom/media/mediasource/SourceBufferDecoder.h +++ b/dom/media/mediasource/SourceBufferDecoder.h @@ -18,12 +18,6 @@ namespace mozilla { class MediaResource; class MediaDecoderReader; -namespace dom { - -class TimeRanges; - -} // namespace dom - class SourceBufferDecoder final : public AbstractMediaDecoder { public: @@ -69,7 +63,7 @@ public: // Warning: this mirrors GetBuffered in MediaDecoder, but this class's base is // AbstractMediaDecoder, which does not supply this interface. - nsresult GetBuffered(dom::TimeRanges* aBuffered); + media::TimeIntervals GetBuffered(); void SetReader(MediaDecoderReader* aReader) { diff --git a/dom/media/mediasource/TrackBuffer.cpp b/dom/media/mediasource/TrackBuffer.cpp index 3c23d97bcf..1234bf4c0f 100644 --- a/dom/media/mediasource/TrackBuffer.cpp +++ b/dom/media/mediasource/TrackBuffer.cpp @@ -276,24 +276,18 @@ class DecoderSorter public: bool LessThan(SourceBufferDecoder* aFirst, SourceBufferDecoder* aSecond) const { - nsRefPtr first = new dom::TimeRanges(); - aFirst->GetBuffered(first); + media::TimeIntervals first = aFirst->GetBuffered(); + media::TimeIntervals second = aSecond->GetBuffered(); - nsRefPtr second = new dom::TimeRanges(); - aSecond->GetBuffered(second); - - return first->GetStartTime() < second->GetStartTime(); + return first.GetStart() < second.GetStart(); } bool Equals(SourceBufferDecoder* aFirst, SourceBufferDecoder* aSecond) const { - nsRefPtr first = new dom::TimeRanges(); - aFirst->GetBuffered(first); + media::TimeIntervals first = aFirst->GetBuffered(); + media::TimeIntervals second = aSecond->GetBuffered(); - nsRefPtr second = new dom::TimeRanges(); - aSecond->GetBuffered(second); - - return first->GetStartTime() == second->GetStartTime(); + return first.GetStart() == second.GetStart(); } }; @@ -323,8 +317,7 @@ TrackBuffer::EvictData(double aPlaybackTime, // First try to evict data before the current play position, starting // with the oldest decoder. for (uint32_t i = 0; i < decoders.Length() && toEvict > 0; ++i) { - nsRefPtr buffered = new dom::TimeRanges(); - decoders[i]->GetBuffered(buffered); + media::TimeIntervals buffered = decoders[i]->GetBuffered(); MSE_DEBUG("Step1. decoder=%u/%u threshold=%u toEvict=%lld", i, decoders.Length(), aThreshold, toEvict); @@ -333,22 +326,24 @@ TrackBuffer::EvictData(double aPlaybackTime, // we apply a threshold of a few seconds back and evict data up to // that point. if (aPlaybackTime > MSE_EVICT_THRESHOLD_TIME) { - double time = aPlaybackTime - MSE_EVICT_THRESHOLD_TIME; + media::TimeUnit time = media::TimeUnit::FromSeconds(aPlaybackTime) - + media::TimeUnit::FromSeconds(MSE_EVICT_THRESHOLD_TIME); bool isActive = decoders[i] == mCurrentDecoder || mParentDecoder->IsActiveReader(decoders[i]->GetReader()); - if (!isActive && buffered->GetEndTime() < time) { + if (!isActive && buffered.GetEnd() < time) { // The entire decoder is contained before our current playback time. // It can be fully evicted. MSE_DEBUG("evicting all bufferedEnd=%f " "aPlaybackTime=%f time=%f, size=%lld", - buffered->GetEndTime(), aPlaybackTime, time, + buffered.GetEnd().ToSeconds(), aPlaybackTime, time, decoders[i]->GetResource()->GetSize()); toEvict -= decoders[i]->GetResource()->EvictAll(); } else { - int64_t playbackOffset = decoders[i]->ConvertToByteOffset(time); + int64_t playbackOffset = + decoders[i]->ConvertToByteOffset(time.ToMicroseconds()); MSE_DEBUG("evicting some bufferedEnd=%f " "aPlaybackTime=%f time=%f, playbackOffset=%lld size=%lld", - buffered->GetEndTime(), aPlaybackTime, time, + buffered.GetEnd().ToSeconds(), aPlaybackTime, time, playbackOffset, decoders[i]->GetResource()->GetSize()); if (playbackOffset > 0) { toEvict -= decoders[i]->GetResource()->EvictData(playbackOffset, @@ -368,13 +363,12 @@ TrackBuffer::EvictData(double aPlaybackTime, if (decoders[i] == mCurrentDecoder) { continue; } - nsRefPtr buffered = new dom::TimeRanges(); - decoders[i]->GetBuffered(buffered); + media::TimeIntervals buffered = decoders[i]->GetBuffered(); // Remove data from older decoders than the current one. MSE_DEBUG("evicting all " "bufferedStart=%f bufferedEnd=%f aPlaybackTime=%f size=%lld", - buffered->GetStartTime(), buffered->GetEndTime(), + buffered.GetStart().ToSeconds(), buffered.GetEnd().ToSeconds(), aPlaybackTime, decoders[i]->GetResource()->GetSize()); toEvict -= decoders[i]->GetResource()->EvictAll(); } @@ -398,10 +392,9 @@ TrackBuffer::EvictData(double aPlaybackTime, // Find the next decoder we're likely going to play with. nsRefPtr nextPlayingDecoder = nullptr; if (playingDecoder) { - nsRefPtr buffered = new dom::TimeRanges(); - playingDecoder->GetBuffered(buffered); + media::TimeIntervals buffered = playingDecoder->GetBuffered(); nextPlayingDecoder = - mParentDecoder->SelectDecoder(buffered->GetEndTime() * USECS_PER_S + 1, + mParentDecoder->SelectDecoder(buffered.GetEnd().ToMicroseconds() + 1, EOS_FUZZ_US, mInitializedDecoders); } @@ -416,12 +409,11 @@ TrackBuffer::EvictData(double aPlaybackTime, decoders[i] == mCurrentDecoder) { continue; } - nsRefPtr buffered = new dom::TimeRanges(); - decoders[i]->GetBuffered(buffered); + media::TimeIntervals buffered = decoders[i]->GetBuffered(); MSE_DEBUG("evicting all " "bufferedStart=%f bufferedEnd=%f aPlaybackTime=%f size=%lld", - buffered->GetStartTime(), buffered->GetEndTime(), + buffered.GetStart().ToSeconds(), buffered.GetEnd().ToSeconds(), aPlaybackTime, decoders[i]->GetResource()->GetSize()); toEvict -= decoders[i]->GetResource()->EvictAll(); } @@ -431,9 +423,8 @@ TrackBuffer::EvictData(double aPlaybackTime, bool evicted = toEvict < (totalSize - aThreshold); if (evicted) { if (playingDecoder) { - nsRefPtr ranges = new dom::TimeRanges(); - playingDecoder->GetBuffered(ranges); - *aBufferStartTime = std::max(0.0, ranges->GetStartTime()); + media::TimeIntervals ranges = playingDecoder->GetBuffered(); + *aBufferStartTime = std::max(0.0, ranges.GetStart().ToSeconds()); } else { // We do not currently have data to play yet. // Avoid evicting anymore data to minimize rebuffering time. @@ -451,20 +442,18 @@ TrackBuffer::RemoveEmptyDecoders(nsTArray& aDecod // Remove decoders that have no data in them for (uint32_t i = 0; i < aDecoders.Length(); ++i) { - nsRefPtr buffered = new dom::TimeRanges(); - aDecoders[i]->GetBuffered(buffered); + media::TimeIntervals buffered = aDecoders[i]->GetBuffered(); MSE_DEBUG("maybe remove empty decoders=%d " "size=%lld start=%f end=%f", i, aDecoders[i]->GetResource()->GetSize(), - buffered->GetStartTime(), buffered->GetEndTime()); + buffered.GetStart().ToSeconds(), buffered.GetEnd().ToSeconds()); if (aDecoders[i] == mCurrentDecoder || mParentDecoder->IsActiveReader(aDecoders[i]->GetReader())) { continue; } - if (aDecoders[i]->GetResource()->GetSize() == 0 || - buffered->GetStartTime() < 0.0 || - buffered->GetEndTime() < 0.0) { + if (aDecoders[i]->GetResource()->GetSize() == 0 || !buffered.Length() || + buffered[0].IsEmpty()) { MSE_DEBUG("remove empty decoders=%d", i); RemoveDecoder(aDecoders[i]); } @@ -487,12 +476,11 @@ TrackBuffer::HasOnlyIncompleteMedia() if (!mCurrentDecoder) { return false; } - nsRefPtr buffered = new dom::TimeRanges(); - mCurrentDecoder->GetBuffered(buffered); + media::TimeIntervals buffered = mCurrentDecoder->GetBuffered(); MSE_DEBUG("mCurrentDecoder.size=%lld, start=%f end=%f", mCurrentDecoder->GetResource()->GetSize(), - buffered->GetStartTime(), buffered->GetEndTime()); - return mCurrentDecoder->GetResource()->GetSize() && !buffered->Length(); + buffered.GetStart(), buffered.GetEnd()); + return mCurrentDecoder->GetResource()->GetSize() && !buffered.Length(); } void @@ -510,23 +498,23 @@ TrackBuffer::EvictBefore(double aTime) } } -double -TrackBuffer::Buffered(dom::TimeRanges* aRanges) +media::TimeIntervals +TrackBuffer::Buffered() { ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); - double highestEndTime = 0; + media::TimeIntervals buffered; - for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) { - nsRefPtr r = new dom::TimeRanges(); - mInitializedDecoders[i]->GetBuffered(r); - if (r->Length() > 0) { - highestEndTime = std::max(highestEndTime, r->GetEndTime()); - aRanges->Union(r, double(mParser->GetRoundingError()) / USECS_PER_S); - } + for (auto& decoder : mInitializedDecoders) { + buffered += decoder->GetBuffered(); + } + // mParser may not be initialized yet, and will only be so if we have a + // buffered range. + if (buffered.Length()) { + buffered.SetFuzz(media::TimeUnit::FromMicroseconds(mParser->GetRoundingError())); } - return highestEndTime; + return buffered; } already_AddRefed @@ -883,10 +871,11 @@ TrackBuffer::ContainsTime(int64_t aTime, int64_t aTolerance) { ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) { - nsRefPtr r = new dom::TimeRanges(); - mInitializedDecoders[i]->GetBuffered(r); - if (r->Find(double(aTime) / USECS_PER_S, - double(aTolerance) / USECS_PER_S) != dom::TimeRanges::NoIndex) { + media::TimeUnit time{media::TimeUnit::FromMicroseconds(aTime)}; + for (auto& decoder : mInitializedDecoders) { + media::TimeIntervals r = decoder->GetBuffered(); + r.SetFuzz(media::TimeUnit::FromMicroseconds(aTolerance)); + if (r.Contains(time)) { return true; } } @@ -1026,17 +1015,17 @@ TrackBuffer::RemoveDecoder(SourceBufferDecoder* aDecoder) } bool -TrackBuffer::RangeRemoval(media::Microseconds aStart, - media::Microseconds aEnd) +TrackBuffer::RangeRemoval(media::TimeUnit aStart, + media::TimeUnit aEnd) { MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); - nsRefPtr buffered = new dom::TimeRanges(); - media::Microseconds bufferedEnd = media::Microseconds::FromSeconds(Buffered(buffered)); - media::Microseconds bufferedStart = media::Microseconds::FromSeconds(buffered->GetStartTime()); + media::TimeIntervals buffered = Buffered(); + media::TimeUnit bufferedStart = buffered.GetStart(); + media::TimeUnit bufferedEnd = buffered.GetEnd(); - if (bufferedStart < media::Microseconds(0) || aStart > bufferedEnd || aEnd < bufferedStart) { + if (!buffered.Length() || aStart > bufferedEnd || aEnd < bufferedStart) { // Nothing to remove. return false; } @@ -1054,18 +1043,17 @@ TrackBuffer::RangeRemoval(media::Microseconds aStart, if (aStart <= bufferedStart && aEnd < bufferedEnd) { // Evict data from beginning. for (size_t i = 0; i < decoders.Length(); ++i) { - nsRefPtr buffered = new dom::TimeRanges(); - decoders[i]->GetBuffered(buffered); - if (media::Microseconds::FromSeconds(buffered->GetEndTime()) < aEnd) { + media::TimeIntervals buffered = decoders[i]->GetBuffered(); + if (buffered.GetEnd() < aEnd) { // Can be fully removed. MSE_DEBUG("remove all bufferedEnd=%f size=%lld", - buffered->GetEndTime(), + buffered.GetEnd().ToSeconds(), decoders[i]->GetResource()->GetSize()); decoders[i]->GetResource()->EvictAll(); } else { int64_t offset = decoders[i]->ConvertToByteOffset(aEnd.ToSeconds()); MSE_DEBUG("removing some bufferedEnd=%f offset=%lld size=%lld", - buffered->GetEndTime(), offset, + buffered.GetEnd().ToSeconds(), offset, decoders[i]->GetResource()->GetSize()); if (offset > 0) { decoders[i]->GetResource()->EvictData(offset, offset); @@ -1075,11 +1063,11 @@ TrackBuffer::RangeRemoval(media::Microseconds aStart, } else { // Only trimming existing buffers. for (size_t i = 0; i < decoders.Length(); ++i) { - if (aStart <= media::Microseconds::FromSeconds(buffered->GetStartTime())) { + if (aStart <= buffered.GetStart()) { // It will be entirely emptied, can clear all data. decoders[i]->GetResource()->EvictAll(); } else { - decoders[i]->Trim(aStart.mValue); + decoders[i]->Trim(aStart.ToMicroseconds()); } } } diff --git a/dom/media/mediasource/TrackBuffer.h b/dom/media/mediasource/TrackBuffer.h index e8d16422cc..cba7fb6185 100644 --- a/dom/media/mediasource/TrackBuffer.h +++ b/dom/media/mediasource/TrackBuffer.h @@ -24,12 +24,6 @@ class ContainerParser; class MediaSourceDecoder; class MediaLargeByteBuffer; -namespace dom { - -class TimeRanges; - -} // namespace dom - class TrackBuffer final { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackBuffer); @@ -56,10 +50,9 @@ public: // of the buffer through to aTime. void EvictBefore(double aTime); - // Returns the highest end time of all of the buffered ranges in the - // decoders managed by this TrackBuffer, and returns the union of the - // decoders buffered ranges in aRanges. This may be called on any thread. - double Buffered(dom::TimeRanges* aRanges); + // Returns the union of the decoders buffered ranges in aRanges. + // This may be called on any thread. + media::TimeIntervals Buffered(); // Mark the current decoder's resource as ended, clear mCurrentDecoder and // reset mLast{Start,End}Timestamp. Main thread only. @@ -99,8 +92,8 @@ public: // Implementation is only partial, we can only trim a buffer. // Returns true if data was evicted. // Times are in microseconds. - bool RangeRemoval(mozilla::media::Microseconds aStart, - mozilla::media::Microseconds aEnd); + bool RangeRemoval(mozilla::media::TimeUnit aStart, + mozilla::media::TimeUnit aEnd); // Abort any pending appendBuffer by rejecting any pending promises. void AbortAppendData(); diff --git a/dom/media/ogg/OggReader.cpp b/dom/media/ogg/OggReader.cpp index cc08b1b58b..8729c63de3 100644 --- a/dom/media/ogg/OggReader.cpp +++ b/dom/media/ogg/OggReader.cpp @@ -17,7 +17,6 @@ extern "C" { #include "opus/opus_multistream.h" } -#include "mozilla/dom/TimeRanges.h" #include "mozilla/TimeStamp.h" #include "VorbisUtils.h" #include "MediaMetadataManager.h" @@ -1859,29 +1858,31 @@ nsresult OggReader::SeekBisection(int64_t aTarget, return NS_OK; } -nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered) +media::TimeIntervals OggReader::GetBuffered() { MOZ_ASSERT(mStartTime != -1, "Need to finish metadata decode first"); { mozilla::ReentrantMonitorAutoEnter mon(mMonitor); - if (mIsChained) - return NS_ERROR_FAILURE; + if (mIsChained) { + return media::TimeIntervals::Invalid(); + } } #ifdef OGG_ESTIMATE_BUFFERED - return MediaDecoderReader::GetBuffered(aBuffered); + return MediaDecoderReader::GetBuffered(); #else + media::TimeIntervals buffered; // HasAudio and HasVideo are not used here as they take a lock and cause // a deadlock. Accessing mInfo doesn't require a lock - it doesn't change // after metadata is read. if (!mInfo.HasValidMedia()) { // No need to search through the file if there are no audio or video tracks - return NS_OK; + return buffered; } AutoPinned resource(mDecoder->GetResource()); nsTArray ranges; nsresult res = resource->GetCachedRanges(ranges); - NS_ENSURE_SUCCESS(res, res); + NS_ENSURE_SUCCESS(res, media::TimeIntervals::Invalid()); // Traverse across the buffered byte ranges, determining the time ranges // they contain. MediaResource::GetNextCachedData(offset) returns -1 when @@ -1915,7 +1916,7 @@ nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered) &page, discard); if (res == PAGE_SYNC_ERROR) { - return NS_ERROR_FAILURE; + return media::TimeIntervals::Invalid(); } else if (res == PAGE_SYNC_END_OF_RANGE) { // Hit the end of range without reading a page, give up trying to // find a start time for this buffered range, skip onto the next one. @@ -1955,7 +1956,7 @@ nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered) // prevents us searching through the rest of the media when we // may not be able to extract timestamps from it. SetChained(true); - return NS_OK; + return buffered; } } @@ -1963,14 +1964,15 @@ nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered) // We were able to find a start time for that range, see if we can // find an end time. int64_t endTime = RangeEndTime(startOffset, endOffset, true); - if (endTime != -1) { - aBuffered->Add((startTime - mStartTime) / static_cast(USECS_PER_S), - (endTime - mStartTime) / static_cast(USECS_PER_S)); + if (endTime > startTime) { + buffered += media::TimeInterval( + media::TimeUnit::FromMicroseconds(startTime - mStartTime), + media::TimeUnit::FromMicroseconds(endTime - mStartTime)); } } } - return NS_OK; + return buffered; #endif } diff --git a/dom/media/ogg/OggReader.h b/dom/media/ogg/OggReader.h index 84a241987c..fef0c68695 100644 --- a/dom/media/ogg/OggReader.h +++ b/dom/media/ogg/OggReader.h @@ -18,12 +18,6 @@ #include "VideoUtils.h" #include "mozilla/Monitor.h" -namespace mozilla { -namespace dom { -class TimeRanges; -} -} - namespace mozilla { // Thread safe container to store the codec information and the serial for each @@ -77,7 +71,7 @@ public: MetadataTags** aTags) override; virtual nsRefPtr Seek(int64_t aTime, int64_t aEndTime) override; - virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) override; + virtual media::TimeIntervals GetBuffered() override; virtual bool IsMediaSeekable() override; diff --git a/dom/media/omx/MediaOmxReader.cpp b/dom/media/omx/MediaOmxReader.cpp index 0f839da17b..cda592ddf6 100644 --- a/dom/media/omx/MediaOmxReader.cpp +++ b/dom/media/omx/MediaOmxReader.cpp @@ -8,7 +8,6 @@ #include "MediaDecoderStateMachine.h" #include "mozilla/TimeStamp.h" -#include "mozilla/dom/TimeRanges.h" #include "MediaResource.h" #include "VideoUtils.h" #include "MediaOmxDecoder.h" diff --git a/dom/media/omx/RtspMediaCodecReader.h b/dom/media/omx/RtspMediaCodecReader.h index 57b8cd47a9..e5ac6eaed3 100644 --- a/dom/media/omx/RtspMediaCodecReader.h +++ b/dom/media/omx/RtspMediaCodecReader.h @@ -11,10 +11,6 @@ namespace mozilla { -namespace dom { - class TimeRanges; -} - class AbstractMediaDecoder; class RtspMediaResource; @@ -48,8 +44,8 @@ public: // we returned are not useful for the MediaDecodeStateMachine. Unlike the // ChannelMediaResource, it has a "cache" that can store the whole streaming // data so the |GetBuffered| function can retrieve useful time ranges. - virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) override { - return NS_ERROR_NOT_IMPLEMENTED; + virtual media::TimeIntervals GetBuffered() override { + return media::TimeIntervals::Invalid(); } virtual void SetIdle() override; diff --git a/dom/media/omx/RtspOmxReader.h b/dom/media/omx/RtspOmxReader.h index c8ffd31e9d..8c31b51ea8 100644 --- a/dom/media/omx/RtspOmxReader.h +++ b/dom/media/omx/RtspOmxReader.h @@ -58,8 +58,8 @@ public: // we returned are not useful for the MediaDecodeStateMachine. Unlike the // ChannelMediaResource, it has a "cache" that can store the whole streaming // data so the |GetBuffered| function can retrieve useful time ranges. - virtual nsresult GetBuffered(mozilla::dom::TimeRanges* aBuffered) final override { - return NS_ERROR_NOT_IMPLEMENTED; + virtual media::TimeIntervals GetBuffered() final override { + return media::TimeIntervals::Invalid(); } virtual void SetIdle() override; diff --git a/dom/media/raw/RawReader.cpp b/dom/media/raw/RawReader.cpp index 93b4e8e0ad..d46affee43 100644 --- a/dom/media/raw/RawReader.cpp +++ b/dom/media/raw/RawReader.cpp @@ -289,7 +289,7 @@ nsresult RawReader::SeekInternal(int64_t aTime) return NS_OK; } -nsresult RawReader::GetBuffered(dom::TimeRanges* aBuffered) +media::TimeIntervals RawReader::GetBuffered() { - return NS_OK; + return media::TimeIntervals(); } diff --git a/dom/media/raw/RawReader.h b/dom/media/raw/RawReader.h index 636ec41d95..65d5195bb5 100644 --- a/dom/media/raw/RawReader.h +++ b/dom/media/raw/RawReader.h @@ -42,7 +42,7 @@ public: virtual nsRefPtr Seek(int64_t aTime, int64_t aEndTime) override; - virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) override; + virtual media::TimeIntervals GetBuffered() override; virtual bool IsMediaSeekable() override; diff --git a/dom/media/wave/WaveReader.cpp b/dom/media/wave/WaveReader.cpp index fc1b557391..53f630912f 100644 --- a/dom/media/wave/WaveReader.cpp +++ b/dom/media/wave/WaveReader.cpp @@ -7,7 +7,6 @@ #include "AbstractMediaDecoder.h" #include "MediaResource.h" #include "WaveReader.h" -#include "mozilla/dom/TimeRanges.h" #include "MediaDecoderStateMachine.h" #include "VideoUtils.h" #include "nsISeekableStream.h" @@ -280,15 +279,12 @@ WaveReader::Seek(int64_t aTarget, int64_t aEndTime) } } -static double RoundToUsecs(double aSeconds) { - return floor(aSeconds * USECS_PER_S) / USECS_PER_S; -} - -nsresult WaveReader::GetBuffered(dom::TimeRanges* aBuffered) +media::TimeIntervals WaveReader::GetBuffered() { if (!mInfo.HasAudio()) { - return NS_OK; + return media::TimeIntervals(); } + media::TimeIntervals buffered; AutoPinned resource(mDecoder->GetResource()); int64_t startOffset = resource->GetNextCachedData(mWavePCMOffset); while (startOffset >= 0) { @@ -300,11 +296,12 @@ nsresult WaveReader::GetBuffered(dom::TimeRanges* aBuffered) // We need to round the buffered ranges' times to microseconds so that they // have the same precision as the currentTime and duration attribute on // the media element. - aBuffered->Add(RoundToUsecs(BytesToTime(startOffset - mWavePCMOffset)), - RoundToUsecs(BytesToTime(endOffset - mWavePCMOffset))); + buffered += media::TimeInterval( + media::TimeUnit::FromSeconds(BytesToTime(startOffset - mWavePCMOffset)), + media::TimeUnit::FromSeconds(BytesToTime(endOffset - mWavePCMOffset))); startOffset = resource->GetNextCachedData(endOffset); } - return NS_OK; + return buffered; } bool diff --git a/dom/media/wave/WaveReader.h b/dom/media/wave/WaveReader.h index 4b2eb89647..f7d539d75d 100644 --- a/dom/media/wave/WaveReader.h +++ b/dom/media/wave/WaveReader.h @@ -9,12 +9,6 @@ #include "MediaDecoderReader.h" #include "mozilla/dom/HTMLMediaElement.h" -namespace mozilla { -namespace dom { -class TimeRanges; -} -} - namespace mozilla { class WaveReader : public MediaDecoderReader @@ -46,7 +40,7 @@ public: virtual nsRefPtr Seek(int64_t aTime, int64_t aEndTime) override; - virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) override; + virtual media::TimeIntervals GetBuffered() override; virtual bool IsMediaSeekable() override; diff --git a/dom/media/webm/SoftwareWebMVideoDecoder.cpp b/dom/media/webm/SoftwareWebMVideoDecoder.cpp index b1a9ade38a..1d1b73d496 100644 --- a/dom/media/webm/SoftwareWebMVideoDecoder.cpp +++ b/dom/media/webm/SoftwareWebMVideoDecoder.cpp @@ -8,9 +8,9 @@ #include "gfx2DGlue.h" #include "MediaDecoderStateMachine.h" #include "MediaResource.h" -#include "mozilla/dom/TimeRanges.h" #include "nsError.h" #include "OggReader.h" +#include "TimeUnits.h" #include "VorbisUtils.h" #include "WebMBufferedParser.h" diff --git a/dom/media/webm/WebMBufferedParser.cpp b/dom/media/webm/WebMBufferedParser.cpp index ff3087e2c2..42a298f708 100644 --- a/dom/media/webm/WebMBufferedParser.cpp +++ b/dom/media/webm/WebMBufferedParser.cpp @@ -6,7 +6,6 @@ #include "nsAlgorithm.h" #include "WebMBufferedParser.h" -#include "mozilla/dom/TimeRanges.h" #include "nsThreadUtils.h" #include diff --git a/dom/media/webm/WebMReader.cpp b/dom/media/webm/WebMReader.cpp index 53c777a8be..8f2ba69767 100644 --- a/dom/media/webm/WebMReader.cpp +++ b/dom/media/webm/WebMReader.cpp @@ -10,7 +10,6 @@ #include "SoftwareWebMVideoDecoder.h" #include "WebMReader.h" #include "WebMBufferedParser.h" -#include "mozilla/dom/TimeRanges.h" #include "VorbisUtils.h" #include "gfx2DGlue.h" #include "Layers.h" @@ -1102,21 +1101,21 @@ nsresult WebMReader::SeekInternal(int64_t aTarget) return NS_OK; } -nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered) +media::TimeIntervals WebMReader::GetBuffered() { MOZ_ASSERT(mStartTime != -1, "Need to finish metadata decode first"); - if (aBuffered->Length() != 0) { - return NS_ERROR_FAILURE; - } - AutoPinned resource(mDecoder->GetResource()); + media::TimeIntervals buffered; // Special case completely cached files. This also handles local files. if (mContext && resource->IsDataCachedToEndOfResource(0)) { uint64_t duration = 0; if (nestegg_duration(mContext, &duration) == 0) { - aBuffered->Add(0, duration / NS_PER_S); - return NS_OK; + buffered += + media::TimeInterval(media::TimeUnit::FromSeconds(0), + media::TimeUnit::FromSeconds(duration / NS_PER_S)); + return buffered; + } } } @@ -1124,7 +1123,7 @@ nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered) // the WebM bitstream. nsTArray ranges; nsresult res = resource->GetCachedRanges(ranges); - NS_ENSURE_SUCCESS(res, res); + NS_ENSURE_SUCCESS(res, media::TimeIntervals::Invalid()); for (uint32_t index = 0; index < ranges.Length(); index++) { uint64_t start, end; @@ -1150,11 +1149,12 @@ nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered) } } - aBuffered->Add(startTime, endTime); + buffered += media::TimeInterval(media::TimeUnit::FromSeconds(startTime), + media::TimeUnit::FromSeconds(endTime)); } } - return NS_OK; + return buffered; } void WebMReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, diff --git a/dom/media/webm/WebMReader.h b/dom/media/webm/WebMReader.h index a95b92af56..d45b108d1d 100644 --- a/dom/media/webm/WebMReader.h +++ b/dom/media/webm/WebMReader.h @@ -158,7 +158,7 @@ public: virtual nsRefPtr Seek(int64_t aTime, int64_t aEndTime) override; - virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) override; + virtual media::TimeIntervals GetBuffered() override; virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) override; virtual int64_t GetEvictionOffset(double aTime) override; diff --git a/dom/media/wmf/WMFReader.cpp b/dom/media/wmf/WMFReader.cpp index 660fbb1999..c331909ae1 100644 --- a/dom/media/wmf/WMFReader.cpp +++ b/dom/media/wmf/WMFReader.cpp @@ -10,7 +10,6 @@ #include "WMFByteStream.h" #include "WMFSourceReaderCallback.h" #include "mozilla/ArrayUtils.h" -#include "mozilla/dom/TimeRanges.h" #include "mozilla/dom/HTMLMediaElement.h" #include "mozilla/Preferences.h" #include "DXVA2Manager.h"