Bug 1227396: P7. Replace nsTArray<MediaByteRange> with dedicated MediaByteRangeSet object. r=cpearce
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 24 Nov 2015 20:16:52 +1100
changeset 308742 c15c9f37f220e491e570fbca50edde924367b26e
parent 308741 fbe31e1d14f98f0f898248b74a3d7a00bde8b825
child 308743 8a42bbaec5c597bc630e52c296fd8f3ffe5bee6c
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1227396
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1227396: P7. Replace nsTArray<MediaByteRange> with dedicated MediaByteRangeSet object. r=cpearce
dom/media/BufferMediaResource.h
dom/media/MediaCache.cpp
dom/media/MediaCache.h
dom/media/MediaResource.cpp
dom/media/MediaResource.h
dom/media/RtspMediaResource.h
dom/media/directshow/DirectShowReader.cpp
dom/media/fmp4/MP4Demuxer.cpp
dom/media/gstreamer/GStreamerReader.cpp
dom/media/gtest/MockMediaResource.cpp
dom/media/gtest/MockMediaResource.h
dom/media/mediasource/ContainerParser.cpp
dom/media/mediasource/MediaSourceResource.h
dom/media/mediasource/SourceBufferResource.h
dom/media/ogg/OggReader.cpp
dom/media/omx/MediaOmxReader.cpp
dom/media/webm/WebMBufferedParser.cpp
dom/media/webm/WebMBufferedParser.h
dom/media/webm/WebMDemuxer.cpp
dom/media/webm/WebMReader.cpp
media/libstagefright/binding/Box.cpp
media/libstagefright/binding/Index.cpp
media/libstagefright/binding/MoofParser.cpp
media/libstagefright/binding/include/mp4_demuxer/Box.h
media/libstagefright/binding/include/mp4_demuxer/Index.h
media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
media/libstagefright/gtest/TestParser.cpp
--- a/dom/media/BufferMediaResource.h
+++ b/dom/media/BufferMediaResource.h
@@ -94,19 +94,19 @@ private:
     return NS_OK;
   }
 
   virtual nsresult Open(nsIStreamListener** aStreamListener) override
   {
     return NS_ERROR_FAILURE;
   }
 
-  virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) override
+  virtual nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override
   {
-    aRanges.AppendElement(MediaByteRange(0, mLength));
+    aRanges += MediaByteRange(0, mLength);
     return NS_OK;
   }
 
   bool IsTransportSeekable() override { return true; }
 
   virtual const nsCString& GetContentType() const override
   {
     return mContentType;
--- a/dom/media/MediaCache.cpp
+++ b/dom/media/MediaCache.cpp
@@ -2437,32 +2437,32 @@ MediaCacheStream::InitAsClone(MediaCache
     // Every block is a readahead block for the clone because the clone's initial
     // stream offset is zero
     gMediaCache->AddBlockOwnerAsReadahead(cacheBlockIndex, this, i);
   }
 
   return NS_OK;
 }
 
-nsresult MediaCacheStream::GetCachedRanges(nsTArray<MediaByteRange>& aRanges)
+nsresult MediaCacheStream::GetCachedRanges(MediaByteRangeSet& aRanges)
 {
   // Take the monitor, so that the cached data ranges can't grow while we're
   // trying to loop over them.
   ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
 
   // We must be pinned while running this, otherwise the cached data ranges may
   // shrink while we're trying to loop over them.
   NS_ASSERTION(mPinCount > 0, "Must be pinned");
 
   int64_t startOffset = GetNextCachedDataInternal(0);
   while (startOffset >= 0) {
     int64_t endOffset = GetCachedDataEndInternal(startOffset);
     NS_ASSERTION(startOffset < endOffset, "Buffered range must end after its start");
     // Bytes [startOffset..endOffset] are cached.
-    aRanges.AppendElement(MediaByteRange(startOffset, endOffset));
+    aRanges += MediaByteRange(startOffset, endOffset);
     startOffset = GetNextCachedDataInternal(endOffset);
     NS_ASSERTION(startOffset == -1 || startOffset > endOffset,
       "Must have advanced to start of next range, or hit end of stream");
   }
   return NS_OK;
 }
 
 } // namespace mozilla
--- a/dom/media/MediaCache.h
+++ b/dom/media/MediaCache.h
@@ -6,23 +6,24 @@
 
 #ifndef MediaCache_h_
 #define MediaCache_h_
 
 #include "nsTArray.h"
 #include "nsCOMPtr.h"
 #include "nsHashKeys.h"
 #include "nsTHashtable.h"
+#include "Intervals.h"
 
 class nsIPrincipal;
 
 namespace mozilla {
 // defined in MediaResource.h
 class ChannelMediaResource;
-class MediaByteRange;
+typedef media::IntervalSet<int64_t> MediaByteRangeSet;
 class MediaResource;
 class ReentrantMonitorAutoEnter;
 
 /**
  * Media applications want fast, "on demand" random access to media data,
  * for pausing, seeking, etc. But we are primarily interested
  * in transporting media data using HTTP over the Internet, which has
  * high latency to open a connection, requires a new connection for every
@@ -295,17 +296,17 @@ public:
   int64_t GetCachedDataEnd(int64_t aOffset);
   // Returns the offset of the first byte of cached data at or after aOffset,
   // or -1 if there is no such cached data.
   int64_t GetNextCachedData(int64_t aOffset);
   // Fills aRanges with the ByteRanges representing the data which is currently
   // cached. Locks the media cache while running, to prevent any ranges
   // growing. The stream should be pinned while this runs and while its results
   // are used, to ensure no data is evicted.
-  nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges);
+  nsresult GetCachedRanges(MediaByteRangeSet& aRanges);
 
   // Reads from buffered data only. Will fail if not all data to be read is
   // in the cache. Will not mark blocks as read. Can be called from the main
   // thread. It's the caller's responsibility to wrap the call in a pin/unpin,
   // and also to check that the range they want is cached before calling this.
   nsresult ReadFromCache(char* aBuffer,
                          int64_t aOffset,
                          int64_t aCount);
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -733,17 +733,17 @@ ChannelMediaResource::MediaReadAt(int64_
 
 int64_t ChannelMediaResource::Tell()
 {
   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
 
   return mCacheStream.Tell();
 }
 
-nsresult ChannelMediaResource::GetCachedRanges(nsTArray<MediaByteRange>& aRanges)
+nsresult ChannelMediaResource::GetCachedRanges(MediaByteRangeSet& aRanges)
 {
   return mCacheStream.GetCachedRanges(aRanges);
 }
 
 void ChannelMediaResource::Suspend(bool aCloseImmediately)
 {
   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
 
@@ -1197,17 +1197,17 @@ public:
     EnsureSizeInitialized();
     return std::max(aOffset, mSize);
   }
   virtual bool    IsDataCachedToEndOfResource(int64_t aOffset) override { return true; }
   virtual bool    IsSuspendedByCache() override { return true; }
   virtual bool    IsSuspended() override { return true; }
   virtual bool    IsTransportSeekable() override { return true; }
 
-  nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) override;
+  nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override;
 
   virtual size_t SizeOfExcludingThis(
                         MallocSizeOf aMallocSizeOf) const override
   {
     // Might be useful to track in the future:
     // - mInput
     return BaseMediaResource::SizeOfExcludingThis(aMallocSizeOf);
   }
@@ -1269,25 +1269,25 @@ void FileMediaResource::EnsureSizeInitia
   uint64_t size;
   nsresult res = mInput->Available(&size);
   if (NS_SUCCEEDED(res) && size <= INT64_MAX) {
     mSize = (int64_t)size;
     mCallback->NotifyDataEnded(NS_OK);
   }
 }
 
-nsresult FileMediaResource::GetCachedRanges(nsTArray<MediaByteRange>& aRanges)
+nsresult FileMediaResource::GetCachedRanges(MediaByteRangeSet& aRanges)
 {
   MutexAutoLock lock(mLock);
 
   EnsureSizeInitialized();
   if (mSize == -1) {
     return NS_ERROR_FAILURE;
   }
-  aRanges.AppendElement(MediaByteRange(0, mSize));
+  aRanges += MediaByteRange(0, mSize);
   return NS_OK;
 }
 
 nsresult FileMediaResource::Open(nsIStreamListener** aStreamListener)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   if (aStreamListener) {
--- a/dom/media/MediaResource.h
+++ b/dom/media/MediaResource.h
@@ -148,16 +148,18 @@ public:
     : BaseType(Move(aOther))
   {}
   MediaByteRange(int64_t aStart, int64_t aEnd)
     : media::Interval<int64_t>(aStart, aEnd)
   {}
   MediaByteRange() = default;
 };
 
+typedef media::IntervalSet<int64_t> MediaByteRangeSet;
+
 class RtspMediaResource;
 
 /**
  * Provides a thread-safe, seek/read interface to resources
  * loaded from a URI. Uses MediaCache to cache data received over
  * Necko's async channel API, thus resolving the mismatch between clients
  * that need efficient random access to the data and protocols that do not
  * support efficient random access, such as HTTP.
@@ -338,17 +340,17 @@ public:
    */
   virtual nsresult Open(nsIStreamListener** aStreamListener) = 0;
 
   /**
    * Fills aRanges with MediaByteRanges representing the data which is cached
    * in the media cache. Stream should be pinned during call and while
    * aRanges is being used.
    */
-  virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) = 0;
+  virtual nsresult GetCachedRanges(MediaByteRangeSet& aRanges) = 0;
 
   // Ensure that the media cache writes any data held in its partial block.
   // Called on the main thread only.
   virtual void FlushCache() { }
 
   // Notify that the last data byte range was loaded.
   virtual void NotifyLastByteRange() { }
 
@@ -650,17 +652,17 @@ public:
 
     void Revoke() { mResource = nullptr; }
 
   private:
     RefPtr<ChannelMediaResource> mResource;
   };
   friend class Listener;
 
-  virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) override;
+  virtual nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override;
 
 protected:
   // These are called on the main thread by Listener.
   nsresult OnStartRequest(nsIRequest* aRequest);
   nsresult OnStopRequest(nsIRequest* aRequest, nsresult aStatus);
   nsresult OnDataAvailable(nsIRequest* aRequest,
                            nsIInputStream* aStream,
                            uint32_t aCount);
--- a/dom/media/RtspMediaResource.h
+++ b/dom/media/RtspMediaResource.h
@@ -157,17 +157,17 @@ public:
   virtual int64_t GetNextCachedData(int64_t aOffset) override { return 0; }
   // dummy
   virtual int64_t GetCachedDataEnd(int64_t aOffset) override { return 0; }
   // dummy
   virtual bool    IsDataCachedToEndOfResource(int64_t aOffset) override {
     return false;
   }
   // dummy
-  nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) override {
+  nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override {
     return NS_ERROR_FAILURE;
   }
 
   // The following methods can be called on main thread only.
 
   virtual nsresult Open(nsIStreamListener** aStreamListener) override;
   virtual nsresult Close() override;
   virtual void     Suspend(bool aCloseImmediately) override;
--- a/dom/media/directshow/DirectShowReader.cpp
+++ b/dom/media/directshow/DirectShowReader.cpp
@@ -379,17 +379,17 @@ void
 DirectShowReader::NotifyDataArrivedInternal()
 {
   MOZ_ASSERT(OnTaskQueue());
   if (!mMP3FrameParser.NeedsData()) {
     return;
   }
 
   AutoPinned<MediaResource> resource(mDecoder->GetResource());
-  nsTArray<MediaByteRange> byteRanges;
+  MediaByteRangeSet byteRanges;
   nsresult rv = resource->GetCachedRanges(byteRanges);
 
   if (NS_FAILED(rv)) {
     return;
   }
 
   IntervalSet<int64_t> intervals;
   for (auto& range : byteRanges) {
--- a/dom/media/fmp4/MP4Demuxer.cpp
+++ b/dom/media/fmp4/MP4Demuxer.cpp
@@ -259,17 +259,17 @@ MP4TrackDemuxer::GetInfo() const
 
 void
 MP4TrackDemuxer::EnsureUpToDateIndex()
 {
   if (!mNeedReIndex) {
     return;
   }
   AutoPinned<MediaResource> resource(mParent->mResource);
-  nsTArray<MediaByteRange> byteRanges;
+  MediaByteRangeSet byteRanges;
   nsresult rv = resource->GetCachedRanges(byteRanges);
   if (NS_FAILED(rv)) {
     return;
   }
   MonitorAutoLock mon(mMonitor);
   mIndex->UpdateMoofIndex(byteRanges);
   mNeedReIndex = false;
 }
@@ -408,17 +408,17 @@ MP4TrackDemuxer::SkipToNextRandomAccessP
   }
 }
 
 media::TimeIntervals
 MP4TrackDemuxer::GetBuffered()
 {
   EnsureUpToDateIndex();
   AutoPinned<MediaResource> resource(mParent->mResource);
-  nsTArray<MediaByteRange> byteRanges;
+  MediaByteRangeSet byteRanges;
   nsresult rv = resource->GetCachedRanges(byteRanges);
 
   if (NS_FAILED(rv)) {
     return media::TimeIntervals();
   }
   nsTArray<mp4_demuxer::Interval<int64_t>> timeRanges;
 
   MonitorAutoLock mon(mMonitor);
--- a/dom/media/gstreamer/GStreamerReader.cpp
+++ b/dom/media/gstreamer/GStreamerReader.cpp
@@ -880,17 +880,17 @@ media::TimeIntervals GStreamerReader::Ge
   if (!mInfo.HasValidMedia()) {
     return buffered;
   }
 
 #if GST_VERSION_MAJOR == 0
   GstFormat format = GST_FORMAT_TIME;
 #endif
   AutoPinned<MediaResource> resource(mDecoder->GetResource());
-  nsTArray<MediaByteRange> ranges;
+  MediaByteRangeSet ranges;
   resource->GetCachedRanges(ranges);
 
   if (resource->IsDataCachedToEndOfResource(0)) {
     /* fast path for local or completely cached files */
     gint64 duration =
        mDuration.Ref().refOr(media::TimeUnit::FromMicroseconds(0)).ToMicroseconds();
     LOG(LogLevel::Debug, "complete range [0, %f] for [0, %li]",
         (double) duration / GST_MSECOND, GetDataLength());
@@ -1281,17 +1281,17 @@ void GStreamerReader::NotifyDataArrivedI
   if (HasVideo()) {
     return;
   }
   if (!mMP3FrameParser.NeedsData()) {
     return;
   }
 
   AutoPinned<MediaResource> resource(mResource.GetResource());
-  nsTArray<MediaByteRange> byteRanges;
+  MediaByteRangeSet byteRanges;
   nsresult rv = resource->GetCachedRanges(byteRanges);
 
   if (NS_FAILED(rv)) {
     return;
   }
 
   IntervalSet<int64_t> intervals;
   for (auto& range : byteRanges) {
--- a/dom/media/gtest/MockMediaResource.cpp
+++ b/dom/media/gtest/MockMediaResource.cpp
@@ -72,17 +72,17 @@ void
 MockMediaResource::MockClearBufferedRanges()
 {
   mRanges.Clear();
 }
 
 void
 MockMediaResource::MockAddBufferedRange(int64_t aStart, int64_t aEnd)
 {
-  mRanges.AppendElement(MediaByteRange(aStart, aEnd));
+  mRanges += MediaByteRange(aStart, aEnd);
 }
 
 int64_t
 MockMediaResource::GetNextCachedData(int64_t aOffset)
 {
   if (!aOffset) {
     return mRanges.Length() ? mRanges[0].mStart : -1;
   }
@@ -102,16 +102,15 @@ MockMediaResource::GetCachedDataEnd(int6
     if (aOffset == mRanges[i].mStart) {
       return mRanges[i].mEnd;
     }
   }
   return -1;
 }
 
 nsresult
-MockMediaResource::GetCachedRanges(nsTArray<MediaByteRange>& aRanges)
+MockMediaResource::GetCachedRanges(MediaByteRangeSet& aRanges)
 {
-  aRanges.Clear();
-  aRanges.AppendElements(mRanges);
+  aRanges = mRanges;
   return NS_OK;
 }
 
 } // namespace mozilla
--- a/dom/media/gtest/MockMediaResource.h
+++ b/dom/media/gtest/MockMediaResource.h
@@ -53,32 +53,32 @@ public:
     uint32_t bytesRead = 0;
     nsresult rv = ReadAt(aOffset, aBuffer, aCount, &bytesRead);
     NS_ENSURE_SUCCESS(rv, rv);
     return bytesRead == aCount ? NS_OK : NS_ERROR_FAILURE;
   }
 
   virtual bool IsTransportSeekable() override { return true; }
   virtual nsresult Open(nsIStreamListener** aStreamListener) override;
-  virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges)
+  virtual nsresult GetCachedRanges(MediaByteRangeSet& aRanges)
     override;
   virtual const nsCString& GetContentType() const override
   {
     return mContentType;
   }
 
   void MockClearBufferedRanges();
   void MockAddBufferedRange(int64_t aStart, int64_t aEnd);
 
 protected:
   virtual ~MockMediaResource();
 
 private:
   FILE* mFileHandle;
   const char* mFileName;
-  nsTArray<MediaByteRange> mRanges;
+  MediaByteRangeSet mRanges;
   Atomic<int> mEntry;
   nsCString mContentType;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -433,20 +433,19 @@ public:
       // timestampOffsets.
       mParser = new mp4_demuxer::MoofParser(mStream, 0, /* aIsAudio = */ false, &mMonitor);
       mInitData = new MediaByteBuffer();
     } else if (!mStream || !mParser) {
       return false;
     }
 
     mResource->AppendData(aData);
-    nsTArray<MediaByteRange> byteRanges;
-    MediaByteRange mbr =
+    MediaByteRangeSet byteRanges;
+    byteRanges +=
       MediaByteRange(mParser->mOffset, mResource->GetLength());
-    byteRanges.AppendElement(mbr);
     mParser->RebuildFragmentedIndex(byteRanges);
 
     if (initSegment || !HasCompleteInitData()) {
       MediaByteRange& range = mParser->mInitRange;
       if (range.Length()) {
         mCompleteInitSegmentRange = range;
         if (!mInitData->SetLength(range.Length(), fallible)) {
           // Super unlikely OOM
--- a/dom/media/mediasource/MediaSourceResource.h
+++ b/dom/media/mediasource/MediaSourceResource.h
@@ -49,20 +49,20 @@ public:
   virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) override { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
   virtual nsresult Open(nsIStreamListener** aStreamListener) override { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
 
   virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override
   {
     return RefPtr<nsIPrincipal>(mPrincipal).forget();
   }
 
-  virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) override
+  virtual nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override
   {
     UNIMPLEMENTED();
-    aRanges.AppendElement(MediaByteRange(0, GetLength()));
+    aRanges += MediaByteRange(0, GetLength());
     return NS_OK;
   }
 
   virtual bool IsTransportSeekable() override { return true; }
   virtual const nsCString& GetContentType() const override { return mType; }
 
   virtual bool IsLiveStream() override
   {
--- a/dom/media/mediasource/SourceBufferResource.h
+++ b/dom/media/mediasource/SourceBufferResource.h
@@ -65,22 +65,22 @@ public:
   virtual int64_t GetCachedDataEnd(int64_t aOffset) override { UNIMPLEMENTED(); return -1; }
   virtual bool IsDataCachedToEndOfResource(int64_t aOffset) override { return false; }
   virtual bool IsSuspendedByCache() override { UNIMPLEMENTED(); return false; }
   virtual bool IsSuspended() override { UNIMPLEMENTED(); return false; }
   virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) override;
   virtual bool IsTransportSeekable() override { UNIMPLEMENTED(); return true; }
   virtual nsresult Open(nsIStreamListener** aStreamListener) override { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
 
-  virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) override
+  virtual nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override
   {
     ReentrantMonitorAutoEnter mon(mMonitor);
     if (mInputBuffer.GetLength()) {
-      aRanges.AppendElement(MediaByteRange(mInputBuffer.GetOffset(),
-                                           mInputBuffer.GetLength()));
+      aRanges += MediaByteRange(mInputBuffer.GetOffset(),
+                                mInputBuffer.GetLength());
     }
     return NS_OK;
   }
 
   virtual const nsCString& GetContentType() const override { return mType; }
 
   virtual size_t SizeOfExcludingThis(
                       MallocSizeOf aMallocSizeOf) const override
--- a/dom/media/ogg/OggReader.cpp
+++ b/dom/media/ogg/OggReader.cpp
@@ -1155,22 +1155,22 @@ int64_t OggReader::RangeEndTime(int64_t 
 
   return endTime;
 }
 
 nsresult OggReader::GetSeekRanges(nsTArray<SeekRange>& aRanges)
 {
   MOZ_ASSERT(OnTaskQueue());
   AutoPinned<MediaResource> resource(mDecoder->GetResource());
-  nsTArray<MediaByteRange> cached;
+  MediaByteRangeSet cached;
   nsresult res = resource->GetCachedRanges(cached);
   NS_ENSURE_SUCCESS(res, res);
 
   for (uint32_t index = 0; index < cached.Length(); index++) {
-    MediaByteRange& range = cached[index];
+    auto& range = cached[index];
     int64_t startTime = -1;
     int64_t endTime = -1;
     if (NS_FAILED(ResetDecode())) {
       return NS_ERROR_FAILURE;
     }
     int64_t startOffset = range.mStart;
     int64_t endOffset = range.mEnd;
     startTime = RangeStartTime(startOffset);
@@ -1836,17 +1836,17 @@ media::TimeIntervals OggReader::GetBuffe
   // 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 buffered;
   }
 
   AutoPinned<MediaResource> resource(mDecoder->GetResource());
-  nsTArray<MediaByteRange> ranges;
+  MediaByteRangeSet ranges;
   nsresult res = resource->GetCachedRanges(ranges);
   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
   // offset is after the end of the media resource, or there's no more cached
   // data after the offset. This loop will run until we've checked every
   // buffered range in the media, in increasing order of offset.
--- a/dom/media/omx/MediaOmxReader.cpp
+++ b/dom/media/omx/MediaOmxReader.cpp
@@ -459,17 +459,17 @@ void MediaOmxReader::NotifyDataArrivedIn
   if (HasVideo()) {
     return;
   }
   if (!mMP3FrameParser.NeedsData()) {
     return;
   }
 
   AutoPinned<MediaResource> resource(mDecoder->GetResource());
-  nsTArray<MediaByteRange> byteRanges;
+  MediaByteRangeSet byteRanges;
   nsresult rv = resource->GetCachedRanges(byteRanges);
 
   if (NS_FAILED(rv)) {
     return;
   }
 
   IntervalSet<int64_t> intervals;
   for (auto& range : byteRanges) {
--- a/dom/media/webm/WebMBufferedParser.cpp
+++ b/dom/media/webm/WebMBufferedParser.cpp
@@ -378,17 +378,17 @@ void WebMBufferedState::NotifyDataArrive
   mLastBlockOffset = mRangeParsers.LastElement().mBlockEndOffset;
 }
 
 void WebMBufferedState::Reset() {
   mRangeParsers.Clear();
   mTimeMapping.Clear();
 }
 
-void WebMBufferedState::UpdateIndex(const nsTArray<MediaByteRange>& aRanges, MediaResource* aResource)
+void WebMBufferedState::UpdateIndex(const MediaByteRangeSet& aRanges, MediaResource* aResource)
 {
   for (uint32_t index = 0; index < aRanges.Length(); index++) {
     const MediaByteRange& range = aRanges[index];
     int64_t offset = range.mStart;
     uint32_t length = range.mEnd - range.mStart;
 
     uint32_t idx = mRangeParsers.IndexOfFirstElementGt(offset - 1);
     if (!idx || !(mRangeParsers[idx-1] == offset)) {
--- a/dom/media/webm/WebMBufferedParser.h
+++ b/dom/media/webm/WebMBufferedParser.h
@@ -261,17 +261,17 @@ public:
     : mReentrantMonitor("WebMBufferedState")
     , mLastBlockOffset(-1)
   {
     MOZ_COUNT_CTOR(WebMBufferedState);
   }
 
   void NotifyDataArrived(const unsigned char* aBuffer, uint32_t aLength, int64_t aOffset);
   void Reset();
-  void UpdateIndex(const nsTArray<MediaByteRange>& aRanges, MediaResource* aResource);
+  void UpdateIndex(const MediaByteRangeSet& aRanges, MediaResource* aResource);
   bool CalculateBufferedForRange(int64_t aStartOffset, int64_t aEndOffset,
                                  uint64_t* aStartTime, uint64_t* aEndTime);
 
   // Returns true if aTime is is present in mTimeMapping and sets aOffset to
   // the latest offset for which decoding can resume without data
   // dependencies to arrive at aTime.
   bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset);
 
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -434,17 +434,17 @@ WebMDemuxer::IsSeekable() const
 
 void
 WebMDemuxer::EnsureUpToDateIndex()
 {
   if (!mNeedReIndex || !mInitData) {
     return;
   }
   AutoPinned<MediaResource> resource(mResource.GetResource());
-  nsTArray<MediaByteRange> byteRanges;
+  MediaByteRangeSet byteRanges;
   nsresult rv = resource->GetCachedRanges(byteRanges);
   if (NS_FAILED(rv) || !byteRanges.Length()) {
     return;
   }
   mBufferedState->UpdateIndex(byteRanges, resource);
 
   mNeedReIndex = false;
 
@@ -727,17 +727,17 @@ WebMDemuxer::SeekInternal(const media::T
 media::TimeIntervals
 WebMDemuxer::GetBuffered()
 {
   EnsureUpToDateIndex();
   AutoPinned<MediaResource> resource(mResource.GetResource());
 
   media::TimeIntervals buffered;
 
-  nsTArray<MediaByteRange> ranges;
+  MediaByteRangeSet ranges;
   nsresult rv = resource->GetCachedRanges(ranges);
   if (NS_FAILED(rv)) {
     return media::TimeIntervals();
   }
   uint64_t duration = 0;
   uint64_t startOffset = 0;
   if (!nestegg_duration(mContext, &duration)) {
     if(mBufferedState->GetStartTime(&startOffset)) {
--- a/dom/media/webm/WebMReader.cpp
+++ b/dom/media/webm/WebMReader.cpp
@@ -744,17 +744,17 @@ media::TimeIntervals WebMReader::GetBuff
         media::TimeInterval(media::TimeUnit::FromSeconds(0),
                             media::TimeUnit::FromSeconds(duration / NS_PER_S));
       return buffered;
     }
   }
 
   // Either we the file is not fully cached, or we couldn't find a duration in
   // the WebM bitstream.
-  nsTArray<MediaByteRange> ranges;
+  MediaByteRangeSet ranges;
   nsresult res = resource->GetCachedRanges(ranges);
   NS_ENSURE_SUCCESS(res, media::TimeIntervals::Invalid());
 
   for (uint32_t index = 0; index < ranges.Length(); index++) {
     uint64_t start, end;
     bool rv = mBufferedState->CalculateBufferedForRange(ranges[index].mStart,
                                                         ranges[index].mEnd,
                                                         &start, &end);
@@ -783,17 +783,17 @@ media::TimeIntervals WebMReader::GetBuff
 
   return buffered;
 }
 
 void WebMReader::NotifyDataArrivedInternal()
 {
   MOZ_ASSERT(OnTaskQueue());
   AutoPinned<MediaResource> resource(mDecoder->GetResource());
-  nsTArray<MediaByteRange> byteRanges;
+  MediaByteRangeSet byteRanges;
   nsresult rv = resource->GetCachedRanges(byteRanges);
 
   if (NS_FAILED(rv)) {
     return;
   }
 
   for (auto& range : byteRanges) {
     RefPtr<MediaByteBuffer> bytes =
--- a/media/libstagefright/binding/Box.cpp
+++ b/media/libstagefright/binding/Box.cpp
@@ -51,17 +51,17 @@ Box::Box(BoxContext* aContext, uint64_t 
   }
 
   const MediaByteRange* byteRange;
   for (int i = 0; ; i++) {
     if (i == mContext->mByteRanges.Length()) {
       return;
     }
 
-    byteRange = &mContext->mByteRanges[i];
+    byteRange = static_cast<const MediaByteRange*>(&mContext->mByteRanges[i]);
     if (byteRange->Contains(headerRange)) {
       break;
     }
   }
 
   size_t bytes;
   if (!mContext->mSource->CachedReadAt(aOffset, header, sizeof(header),
                                        &bytes) ||
@@ -83,17 +83,17 @@ Box::Box(BoxContext* aContext, uint64_t 
                                          sizeof(bigLength), &bytes) ||
         bytes != sizeof(bigLength)) {
       return;
     }
     size = BigEndian::readUint64(bigLength);
     mBodyOffset = bigLengthRange.mEnd;
   } else if (size == 0) {
     // box extends to end of file.
-    size = mContext->mByteRanges.LastElement().mEnd - aOffset;
+    size = mContext->mByteRanges.LastInterval().mEnd - aOffset;
     mBodyOffset = headerRange.mEnd;
   } else {
     mBodyOffset = headerRange.mEnd;
   }
 
   if (size > INT64_MAX) {
     return;
   }
--- a/media/libstagefright/binding/Index.cpp
+++ b/media/libstagefright/binding/Index.cpp
@@ -20,26 +20,26 @@ namespace mp4_demuxer
 {
 
 class MOZ_STACK_CLASS RangeFinder
 {
 public:
   // Given that we're processing this in order we don't use a binary search
   // to find the apropriate time range. Instead we search linearly from the
   // last used point.
-  explicit RangeFinder(const nsTArray<mozilla::MediaByteRange>& ranges)
+  explicit RangeFinder(const MediaByteRangeSet& ranges)
     : mRanges(ranges), mIndex(0)
   {
     // Ranges must be normalised for this to work
   }
 
   bool Contains(MediaByteRange aByteRange);
 
 private:
-  const nsTArray<MediaByteRange>& mRanges;
+  const MediaByteRangeSet& mRanges;
   size_t mIndex;
 };
 
 bool
 RangeFinder::Contains(MediaByteRange aByteRange)
 {
   if (!mRanges.Length()) {
     return false;
@@ -261,27 +261,27 @@ Index::Index(const nsTArray<Indice>& aIn
       MOZ_ALWAYS_TRUE(mIndex.AppendElement(sample, fallible));
     }
   }
 }
 
 Index::~Index() {}
 
 void
-Index::UpdateMoofIndex(const nsTArray<MediaByteRange>& aByteRanges)
+Index::UpdateMoofIndex(const MediaByteRangeSet& aByteRanges)
 {
   if (!mMoofParser) {
     return;
   }
 
   mMoofParser->RebuildFragmentedIndex(aByteRanges);
 }
 
 Microseconds
-Index::GetEndCompositionIfBuffered(const nsTArray<MediaByteRange>& aByteRanges)
+Index::GetEndCompositionIfBuffered(const MediaByteRangeSet& aByteRanges)
 {
   FallibleTArray<Sample>* index;
   if (mMoofParser) {
     if (!mMoofParser->ReachedEnd() || mMoofParser->Moofs().IsEmpty()) {
       return 0;
     }
     index = &mMoofParser->Moofs().LastElement().mIndex;
   } else {
@@ -300,17 +300,17 @@ Index::GetEndCompositionIfBuffered(const
       return lastComposition;
     }
   }
   return 0;
 }
 
 void
 Index::ConvertByteRangesToTimeRanges(
-  const nsTArray<MediaByteRange>& aByteRanges,
+  const MediaByteRangeSet& aByteRanges,
   nsTArray<Interval<Microseconds>>* aTimeRanges)
 {
   RangeFinder rangeFinder(aByteRanges);
   nsTArray<Interval<Microseconds>> timeRanges;
 
   nsTArray<FallibleTArray<Sample>*> indexes;
   if (mMoofParser) {
     // We take the index out of the moof parser and move it into a local
--- a/media/libstagefright/binding/MoofParser.cpp
+++ b/media/libstagefright/binding/MoofParser.cpp
@@ -23,17 +23,17 @@ extern mozilla::LogModule* GetDemuxerLog
 namespace mp4_demuxer
 {
 
 using namespace stagefright;
 using namespace mozilla;
 
 bool
 MoofParser::RebuildFragmentedIndex(
-  const nsTArray<mozilla::MediaByteRange>& aByteRanges)
+  const MediaByteRangeSet& aByteRanges)
 {
   BoxContext context(mSource, aByteRanges);
   return RebuildFragmentedIndex(context);
 }
 
 bool
 MoofParser::RebuildFragmentedIndex(BoxContext& aContext)
 {
@@ -54,26 +54,26 @@ MoofParser::RebuildFragmentedIndex(BoxCo
 
       if (!mMoofs.IsEmpty()) {
         // Stitch time ranges together in the case of a (hopefully small) time
         // range gap between moofs.
         mMoofs.LastElement().FixRounding(moof);
       }
 
       mMoofs.AppendElement(moof);
-      mMediaRanges.AppendElement(moof.mRange);
+      mMediaRanges += moof.mRange;
       foundValidMoof = true;
     } else if (box.IsType("mdat") && !Moofs().IsEmpty()) {
       // Check if we have all our data from last moof.
       Moof& moof = Moofs().LastElement();
       media::Interval<int64_t> datarange(moof.mMdatRange.mStart, moof.mMdatRange.mEnd, 0);
       media::Interval<int64_t> mdat(box.Range().mStart, box.Range().mEnd, 0);
       if (datarange.Intersects(mdat)) {
-        mMediaRanges.LastElement() =
-          mMediaRanges.LastElement().Span(box.Range());
+        mMediaRanges.LastInterval() =
+          mMediaRanges.LastInterval().Span(box.Range());
       }
     }
     mOffset = box.NextOffset();
   }
   return foundValidMoof;
 }
 
 MediaByteRange
@@ -123,39 +123,39 @@ private:
   RefPtr<Stream> mStream;
 };
 
 bool
 MoofParser::BlockingReadNextMoof()
 {
   int64_t length = std::numeric_limits<int64_t>::max();
   mSource->Length(&length);
-  nsTArray<MediaByteRange> byteRanges;
-  byteRanges.AppendElement(MediaByteRange(0, length));
+  MediaByteRangeSet byteRanges;
+  byteRanges += MediaByteRange(0, length);
   RefPtr<mp4_demuxer::BlockingStream> stream = new BlockingStream(mSource);
 
   BoxContext context(stream, byteRanges);
   for (Box box(&context, mOffset); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("moof")) {
       byteRanges.Clear();
-      byteRanges.AppendElement(MediaByteRange(mOffset, box.Range().mEnd));
+      byteRanges += MediaByteRange(mOffset, box.Range().mEnd);
       return RebuildFragmentedIndex(context);
     }
   }
   return false;
 }
 
 void
 MoofParser::ScanForMetadata(mozilla::MediaByteRange& aFtyp,
                             mozilla::MediaByteRange& aMoov)
 {
   int64_t length = std::numeric_limits<int64_t>::max();
   mSource->Length(&length);
-  nsTArray<MediaByteRange> byteRanges;
-  byteRanges.AppendElement(MediaByteRange(0, length));
+  MediaByteRangeSet byteRanges;
+  byteRanges += MediaByteRange(0, length);
   RefPtr<mp4_demuxer::BlockingStream> stream = new BlockingStream(mSource);
 
   BoxContext context(stream, byteRanges);
   for (Box box(&context, mOffset); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("ftyp")) {
       aFtyp = box.Range();
       continue;
     }
@@ -202,17 +202,17 @@ MoofParser::Metadata()
     stream->ReadAt(moov.mStart, metadata->Elements() + ftyp.Length(), moov.Length(), &read);
   if (!rv || read != moov.Length()) {
     return nullptr;
   }
   return metadata.forget();
 }
 
 Interval<Microseconds>
-MoofParser::GetCompositionRange(const nsTArray<MediaByteRange>& aByteRanges)
+MoofParser::GetCompositionRange(const MediaByteRangeSet& aByteRanges)
 {
   Interval<Microseconds> compositionRange;
   BoxContext context(mSource, aByteRanges);
   for (size_t i = 0; i < mMoofs.Length(); i++) {
     Moof& moof = mMoofs[i];
     Box box(&context, moof.mRange.mStart);
     if (box.IsAvailable()) {
       compositionRange = compositionRange.Extents(moof.mTimeRange);
--- a/media/libstagefright/binding/include/mp4_demuxer/Box.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/Box.h
@@ -18,23 +18,23 @@ using namespace mozilla;
 
 namespace mp4_demuxer {
 
 class Stream;
 
 class BoxContext
 {
 public:
-  BoxContext(Stream* aSource, const nsTArray<MediaByteRange>& aByteRanges)
+  BoxContext(Stream* aSource, const MediaByteRangeSet& aByteRanges)
     : mSource(aSource), mByteRanges(aByteRanges)
   {
   }
 
   RefPtr<Stream> mSource;
-  const nsTArray<MediaByteRange>& mByteRanges;
+  const MediaByteRangeSet& mByteRanges;
 };
 
 class Box
 {
 public:
   Box(BoxContext* aContext, uint64_t aOffset, const Box* aParent = nullptr);
   Box();
 
--- a/media/libstagefright/binding/include/mp4_demuxer/Index.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/Index.h
@@ -55,21 +55,21 @@ public:
   };
 
   Index(const nsTArray<Indice>& aIndex,
         Stream* aSource,
         uint32_t aTrackId,
         bool aIsAudio,
         mozilla::Monitor* aMonitor);
 
-  void UpdateMoofIndex(const nsTArray<mozilla::MediaByteRange>& aByteRanges);
+  void UpdateMoofIndex(const mozilla::MediaByteRangeSet& aByteRanges);
   Microseconds GetEndCompositionIfBuffered(
-    const nsTArray<mozilla::MediaByteRange>& aByteRanges);
+    const mozilla::MediaByteRangeSet& aByteRanges);
   void ConvertByteRangesToTimeRanges(
-    const nsTArray<mozilla::MediaByteRange>& aByteRanges,
+    const mozilla::MediaByteRangeSet& aByteRanges,
     nsTArray<Interval<Microseconds>>* aTimeRanges);
   uint64_t GetEvictionOffset(Microseconds aTime);
   bool IsFragmented() { return mMoofParser; }
 
   friend class SampleIterator;
 
 private:
   ~Index();
--- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
@@ -160,17 +160,17 @@ public:
   AtomType mAuxInfoType;
   uint32_t mAuxInfoTypeParameter;
   nsTArray<uint64_t> mOffsets;
 };
 
 class AuxInfo {
 public:
   AuxInfo(int64_t aMoofOffset, Saiz& aSaiz, Saio& aSaio);
-  bool GetByteRanges(nsTArray<MediaByteRange>* aByteRanges);
+  bool GetByteRanges(MediaByteRangeSet* aByteRanges);
 
 private:
   int64_t mMoofOffset;
   Saiz& mSaiz;
   Saio& mSaio;
 };
 
 class Moof : public Atom
@@ -207,20 +207,20 @@ public:
     , mTrex(aTrackId)
     , mMonitor(aMonitor)
     , mIsAudio(aIsAudio)
   {
     // Setting the mTrex.mTrackId to 0 is a nasty work around for calculating
     // the composition range for MSE. We need an array of tracks.
   }
   bool RebuildFragmentedIndex(
-    const nsTArray<mozilla::MediaByteRange>& aByteRanges);
+    const mozilla::MediaByteRangeSet& aByteRanges);
   bool RebuildFragmentedIndex(BoxContext& aContext);
   Interval<Microseconds> GetCompositionRange(
-    const nsTArray<mozilla::MediaByteRange>& aByteRanges);
+    const mozilla::MediaByteRangeSet& aByteRanges);
   bool ReachedEnd();
   void ParseMoov(Box& aBox);
   void ParseTrak(Box& aBox);
   void ParseMdia(Box& aBox, Tkhd& aTkhd);
   void ParseMvex(Box& aBox);
 
   void ParseMinf(Box& aBox);
   void ParseStbl(Box& aBox);
@@ -245,14 +245,14 @@ public:
   Edts mEdts;
   Sinf mSinf;
   Monitor* mMonitor;
   nsTArray<Moof>& Moofs() { mMonitor->AssertCurrentThreadOwns(); return mMoofs; }
 private:
   void ScanForMetadata(mozilla::MediaByteRange& aFtyp,
                        mozilla::MediaByteRange& aMoov);
   nsTArray<Moof> mMoofs;
-  nsTArray<MediaByteRange> mMediaRanges;
+  MediaByteRangeSet mMediaRanges;
   bool mIsAudio;
 };
 }
 
 #endif
--- a/media/libstagefright/gtest/TestParser.cpp
+++ b/media/libstagefright/gtest/TestParser.cpp
@@ -97,18 +97,17 @@ TEST(stagefright_MoofParser, EmptyStream
   RefPtr<Stream> stream = new TestStream(nullptr, 0);
 
   Monitor monitor("MP4Metadata::gtest");
   MonitorAutoLock mon(monitor);
   MoofParser parser(stream, 0, false, &monitor);
   EXPECT_EQ(0u, parser.mOffset);
   EXPECT_TRUE(parser.ReachedEnd());
 
-  nsTArray<MediaByteRange> byteRanges;
-  byteRanges.AppendElement(MediaByteRange(0, 0));
+  MediaByteRangeSet byteRanges;
   EXPECT_FALSE(parser.RebuildFragmentedIndex(byteRanges));
 
   EXPECT_TRUE(parser.GetCompositionRange(byteRanges).IsNull());
   EXPECT_TRUE(parser.mInitRange.IsEmpty());
   EXPECT_EQ(0u, parser.mOffset);
   EXPECT_TRUE(parser.ReachedEnd());
   EXPECT_FALSE(parser.HasMetadata());
   RefPtr<MediaByteBuffer> metadataBuffer = parser.Metadata();
@@ -287,18 +286,17 @@ TEST(stagefright_MoofParser, test_case_m
     RefPtr<Stream> stream = new TestStream(buffer.Elements(), buffer.Length());
 
     Monitor monitor("MP4Metadata::HasCompleteMetadata");
     MonitorAutoLock mon(monitor);
     MoofParser parser(stream, 0, false, &monitor);
     EXPECT_EQ(0u, parser.mOffset);
     EXPECT_FALSE(parser.ReachedEnd());
 
-    nsTArray<MediaByteRange> byteRanges;
-    byteRanges.AppendElement(MediaByteRange(0, 0));
+    MediaByteRangeSet byteRanges;
     EXPECT_FALSE(parser.RebuildFragmentedIndex(byteRanges));
 
     EXPECT_TRUE(parser.GetCompositionRange(byteRanges).IsNull());
     EXPECT_TRUE(parser.mInitRange.IsEmpty());
     EXPECT_EQ(0u, parser.mOffset);
     EXPECT_FALSE(parser.ReachedEnd());
     EXPECT_TRUE(parser.HasMetadata());
     RefPtr<MediaByteBuffer> metadataBuffer = parser.Metadata();
@@ -324,18 +322,17 @@ TEST(stagefright_MoofParser, test_case_m
     // No checks because results would differ for each position.
     for (size_t offset = 0; offset < buffer.Length() - step; offset += step) {
       size_t size = buffer.Length() - offset;
       while (size > 0) {
         RefPtr<TestStream> stream =
           new TestStream(buffer.Elements() + offset, size);
 
         MoofParser parser(stream, 0, false, &monitor);
-        nsTArray<MediaByteRange> byteRanges;
-        byteRanges.AppendElement(MediaByteRange(0, 0));
+        MediaByteRangeSet byteRanges;
         EXPECT_FALSE(parser.RebuildFragmentedIndex(byteRanges));
         parser.GetCompositionRange(byteRanges);
         parser.HasMetadata();
         RefPtr<MediaByteBuffer> metadataBuffer = parser.Metadata();
         parser.FirstCompleteMediaSegment();
         parser.FirstCompleteMediaHeader();
 
         if (stream->mHighestSuccessfulEndOffset <= 0) {