summaryrefslogtreecommitdiffstats
path: root/dom/media/mp4/MP4Interval.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/media/mp4/MP4Interval.h137
1 files changed, 137 insertions, 0 deletions
diff --git a/dom/media/mp4/MP4Interval.h b/dom/media/mp4/MP4Interval.h
new file mode 100644
index 0000000000..70e6daeadd
--- /dev/null
+++ b/dom/media/mp4/MP4Interval.h
@@ -0,0 +1,137 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+#ifndef INTERVAL_H_
+#define INTERVAL_H_
+
+#include "nsTArray.h"
+#include <algorithm>
+#include <nsString.h>
+
+namespace mozilla {
+
+template <typename T>
+struct MP4Interval {
+ MP4Interval() : start{}, end{} {}
+ MP4Interval(T aStart, T aEnd) : start(aStart), end(aEnd) {
+ MOZ_ASSERT(aStart <= aEnd);
+ }
+ T Length() { return end - start; }
+ MP4Interval Intersection(const MP4Interval& aOther) const {
+ T s = start > aOther.start ? start : aOther.start;
+ T e = end < aOther.end ? end : aOther.end;
+ if (s > e) {
+ return MP4Interval();
+ }
+ return MP4Interval(s, e);
+ }
+ bool Contains(const MP4Interval& aOther) const {
+ return aOther.start >= start && aOther.end <= end;
+ }
+ bool operator==(const MP4Interval& aOther) const {
+ return start == aOther.start && end == aOther.end;
+ }
+ bool operator!=(const MP4Interval& aOther) const {
+ return !(*this == aOther);
+ }
+ bool IsNull() const { return end == start; }
+ MP4Interval Extents(const MP4Interval& aOther) const {
+ if (IsNull()) {
+ return aOther;
+ }
+ return MP4Interval(std::min(start, aOther.start),
+ std::max(end, aOther.end));
+ }
+
+ T start;
+ T end;
+
+ nsCString ToString() {
+ return nsPrintfCString("[%s, %s]", start.ToString().get(),
+ end.ToString().get());
+ }
+
+ static void SemiNormalAppend(nsTArray<MP4Interval<T>>& aIntervals,
+ MP4Interval<T> aMP4Interval) {
+ if (!aIntervals.IsEmpty() &&
+ aIntervals.LastElement().end == aMP4Interval.start) {
+ aIntervals.LastElement().end = aMP4Interval.end;
+ } else {
+ aIntervals.AppendElement(aMP4Interval);
+ }
+ }
+
+ static void Normalize(const nsTArray<MP4Interval<T>>& aIntervals,
+ nsTArray<MP4Interval<T>>* aNormalized) {
+ if (!aNormalized || !aIntervals.Length()) {
+ MOZ_ASSERT(aNormalized);
+ return;
+ }
+ MOZ_ASSERT(aNormalized->IsEmpty());
+
+ nsTArray<MP4Interval<T>> sorted = aIntervals.Clone();
+ sorted.Sort(Compare());
+
+ MP4Interval<T> current = sorted[0];
+ for (size_t i = 1; i < sorted.Length(); i++) {
+ MOZ_ASSERT(sorted[i].start <= sorted[i].end);
+ if (current.Contains(sorted[i])) {
+ continue;
+ }
+ if (current.end >= sorted[i].start) {
+ current.end = sorted[i].end;
+ } else {
+ aNormalized->AppendElement(current);
+ current = sorted[i];
+ }
+ }
+ aNormalized->AppendElement(current);
+ }
+
+ static void Intersection(const nsTArray<MP4Interval<T>>& a0,
+ const nsTArray<MP4Interval<T>>& a1,
+ nsTArray<MP4Interval<T>>* aIntersection) {
+ MOZ_ASSERT(IsNormalized(a0));
+ MOZ_ASSERT(IsNormalized(a1));
+ size_t i0 = 0;
+ size_t i1 = 0;
+ while (i0 < a0.Length() && i1 < a1.Length()) {
+ MP4Interval i = a0[i0].Intersection(a1[i1]);
+ if (i.Length()) {
+ aIntersection->AppendElement(i);
+ }
+ if (a0[i0].end < a1[i1].end) {
+ i0++;
+ // Assert that the array is sorted
+ MOZ_ASSERT(i0 == a0.Length() || a0[i0 - 1].start < a0[i0].start);
+ } else {
+ i1++;
+ // Assert that the array is sorted
+ MOZ_ASSERT(i1 == a1.Length() || a1[i1 - 1].start < a1[i1].start);
+ }
+ }
+ }
+
+ static bool IsNormalized(const nsTArray<MP4Interval<T>>& aIntervals) {
+ for (size_t i = 1; i < aIntervals.Length(); i++) {
+ if (aIntervals[i - 1].end >= aIntervals[i].start) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ struct Compare {
+ bool Equals(const MP4Interval<T>& a0, const MP4Interval<T>& a1) const {
+ return a0.start == a1.start && a0.end == a1.end;
+ }
+
+ bool LessThan(const MP4Interval<T>& a0, const MP4Interval<T>& a1) const {
+ return a0.start < a1.start;
+ }
+ };
+};
+} // namespace mozilla
+
+#endif