Bug 1109431 - Apply TimestampsFuzzyEqual rounding to the buffered ranges returned from multiple decoders. r=ajones, a=sledru
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 11 Dec 2014 10:52:57 +1300
changeset 242749 e2febcf7a58686f939be01784d162fedb99c2a46
parent 242748 bcba197a83d771398945d9bf8ed0dfafb8adbd5f
child 242750 72f6dba74653a0c2b3e85aa59aff2a12637afcec
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersajones, sledru
bugs1109431
milestone36.0a2
Bug 1109431 - Apply TimestampsFuzzyEqual rounding to the buffered ranges returned from multiple decoders. r=ajones, a=sledru
dom/html/TimeRanges.cpp
dom/html/TimeRanges.h
dom/media/mediasource/ContainerParser.cpp
dom/media/mediasource/ContainerParser.h
dom/media/mediasource/TrackBuffer.cpp
--- a/dom/html/TimeRanges.cpp
+++ b/dom/html/TimeRanges.cpp
@@ -93,49 +93,49 @@ TimeRanges::GetEndTime()
 {
   if (mRanges.IsEmpty()) {
     return -1.0;
   }
   return mRanges[mRanges.Length() - 1].mEnd;
 }
 
 void
-TimeRanges::Normalize()
+TimeRanges::Normalize(double aError)
 {
   if (mRanges.Length() >= 2) {
     nsAutoTArray<TimeRange,4> normalized;
 
     mRanges.Sort(CompareTimeRanges());
 
     // This merges the intervals.
     TimeRange current(mRanges[0]);
     for (uint32_t i = 1; i < mRanges.Length(); i++) {
       if (current.mStart <= mRanges[i].mStart &&
           current.mEnd >= mRanges[i].mEnd) {
         continue;
       }
-      if (current.mEnd >= mRanges[i].mStart) {
+      if (current.mEnd + aError >= mRanges[i].mStart) {
         current.mEnd = mRanges[i].mEnd;
       } else {
         normalized.AppendElement(current);
         current = mRanges[i];
       }
     }
 
     normalized.AppendElement(current);
 
     mRanges = normalized;
   }
 }
 
 void
-TimeRanges::Union(const TimeRanges* aOtherRanges)
+TimeRanges::Union(const TimeRanges* aOtherRanges, double aError)
 {
   mRanges.AppendElements(aOtherRanges->mRanges);
-  Normalize();
+  Normalize(aError);
 }
 
 void
 TimeRanges::Intersection(const TimeRanges* aOtherRanges)
 {
   nsAutoTArray<TimeRange,4> intersection;
 
   const nsTArray<TimeRange>& otherRanges = aOtherRanges->mRanges;
--- a/dom/html/TimeRanges.h
+++ b/dom/html/TimeRanges.h
@@ -37,20 +37,20 @@ public:
 
   // Returns the start time of the first range, or -1 if no ranges exist.
   double GetStartTime();
 
   // Returns the end time of the last range, or -1 if no ranges exist.
   double GetEndTime();
 
   // See http://www.whatwg.org/html/#normalized-timeranges-object
-  void Normalize();
+  void Normalize(double aError = 0.0);
 
   // Mutate this TimeRange to be the union of this and aOtherRanges.
-  void Union(const TimeRanges* aOtherRanges);
+  void Union(const TimeRanges* aOtherRanges, double aError);
 
   // Mutate this TimeRange to be the intersection of this and aOtherRanges.
   void Intersection(const TimeRanges* aOtherRanges);
 
   JSObject* WrapObject(JSContext* aCx);
 
   uint32_t Length() const
   {
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -56,34 +56,41 @@ ContainerParser::ParseStartAndEndTimesta
                                             int64_t& aStart, int64_t& aEnd)
 {
   return false;
 }
 
 bool
 ContainerParser::TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs)
 {
-  NS_WARNING("Using default ContainerParser::TimestampFuzzyEquals implementation");
-  return aLhs == aRhs;
+  return llabs(aLhs - aRhs) <= GetRoundingError();
+}
+
+int64_t
+ContainerParser::GetRoundingError()
+{
+  NS_WARNING("Using default ContainerParser::GetRoundingError implementation");
+  return 0;
 }
 
 const nsTArray<uint8_t>&
 ContainerParser::InitData()
 {
   MOZ_ASSERT(mHasInitData);
   return mInitData;
 }
 
 class WebMContainerParser : public ContainerParser {
 public:
   WebMContainerParser()
     : mParser(0), mOffset(0)
   {}
 
   static const unsigned NS_PER_USEC = 1000;
+  static const unsigned USEC_PER_SEC = 1000000;
 
   bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength)
   {
     ContainerParser::IsInitSegmentPresent(aData, aLength);
     // XXX: This is overly primitive, needs to collect data as it's appended
     // to the SB and handle, rather than assuming everything is present in a
     // single aData segment.
     // 0x1a45dfa3 // EBML
@@ -177,20 +184,20 @@ public:
               this, aStart, aEnd, mapping[0].mSyncOffset, mapping[endIdx].mEndOffset, mapping.Length(), endIdx);
 
     mapping.RemoveElementsAt(0, endIdx + 1);
     mOverlappedMapping.AppendElements(mapping);
 
     return true;
   }
 
-  bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs)
+  int64_t GetRoundingError()
   {
     int64_t error = mParser.GetTimecodeScale() / NS_PER_USEC;
-    return llabs(aLhs - aRhs) <= error * 2;
+    return error * 2;
   }
 
 private:
   WebMBufferedParser mParser;
   nsTArray<WebMTimeDataOffset> mOverlappedMapping;
   int64_t mOffset;
 };
 
@@ -273,19 +280,19 @@ public:
     }
     aStart = compositionRange.start;
     aEnd = compositionRange.end;
     MSE_DEBUG("MP4ContainerParser(%p)::ParseStartAndEndTimestamps: [%lld, %lld]",
               this, aStart, aEnd);
     return true;
   }
 
-  bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs)
+  int64_t GetRoundingError()
   {
-    return llabs(aLhs - aRhs) <= 1000;
+    return 1000;
   }
 
 private:
   nsRefPtr<mp4_demuxer::BufferStream> mStream;
   nsAutoPtr<mp4_demuxer::MoofParser> mParser;
   Monitor mMonitor;
 };
 
--- a/dom/media/mediasource/ContainerParser.h
+++ b/dom/media/mediasource/ContainerParser.h
@@ -30,17 +30,19 @@ public:
   // segment.  aData may not start on a parser sync boundary.  Return true
   // if aStart and aEnd have been updated.
   virtual bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
                                           int64_t& aStart, int64_t& aEnd);
 
   // Compare aLhs and rHs, considering any error that may exist in the
   // timestamps from the format's base representation.  Return true if aLhs
   // == aRhs within the error epsilon.
-  virtual bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs);
+  bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs);
+
+  virtual int64_t GetRoundingError();
 
   const nsTArray<uint8_t>& InitData();
 
   bool HasInitData()
   {
     return mHasInitData;
   }
 
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -254,17 +254,17 @@ TrackBuffer::Buffered(dom::TimeRanges* a
 
   double highestEndTime = 0;
 
   for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
     nsRefPtr<dom::TimeRanges> r = new dom::TimeRanges();
     mDecoders[i]->GetBuffered(r);
     if (r->Length() > 0) {
       highestEndTime = std::max(highestEndTime, r->GetEndTime());
-      aRanges->Union(r);
+      aRanges->Union(r, double(mParser->GetRoundingError()) / USECS_PER_S);
     }
   }
 
   return highestEndTime;
 }
 
 already_AddRefed<SourceBufferDecoder>
 TrackBuffer::NewDecoder()