summaryrefslogtreecommitdiffstats
path: root/dom/media/TimeUnits.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/TimeUnits.h')
-rw-r--r--dom/media/TimeUnits.h259
1 files changed, 259 insertions, 0 deletions
diff --git a/dom/media/TimeUnits.h b/dom/media/TimeUnits.h
new file mode 100644
index 0000000000..3af1d3e08f
--- /dev/null
+++ b/dom/media/TimeUnits.h
@@ -0,0 +1,259 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 TIME_UNITS_H
+#define TIME_UNITS_H
+
+#include <type_traits>
+
+#include "Intervals.h"
+#include "mozilla/CheckedInt.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/IntegerPrintfMacros.h"
+
+namespace mozilla::media {
+class TimeIntervals;
+} // namespace mozilla::media
+// CopyChooser specialization for nsTArray
+template <>
+struct nsTArray_RelocationStrategy<mozilla::media::TimeIntervals> {
+ typedef nsTArray_RelocateUsingMoveConstructor<mozilla::media::TimeIntervals>
+ Type;
+};
+
+namespace mozilla {
+
+// 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;
+
+namespace media {
+
+// Number of nanoseconds per second. 1e9.
+static const int64_t NSECS_PER_S = 1000000000;
+
+#ifndef PROCESS_DECODE_LOG
+# define PROCESS_DECODE_LOG(sample) \
+ MOZ_LOG( \
+ sPDMLog, mozilla::LogLevel::Verbose, \
+ ("ProcessDecode: mDuration=%" PRIu64 "µs ; mTime=%" PRIu64 \
+ "µs ; mTimecode=%" PRIu64 "µs", \
+ sample->mDuration.ToMicroseconds(), sample->mTime.ToMicroseconds(), \
+ sample->mTimecode.ToMicroseconds()))
+#endif // PROCESS_DECODE_LOG
+
+// TimeUnit at present uses a CheckedInt64 as storage.
+// INT64_MAX has the special meaning of being +oo.
+class TimeUnit final {
+ public:
+ static TimeUnit FromSeconds(double aValue) {
+ MOZ_ASSERT(!IsNaN(aValue));
+
+ if (mozilla::IsInfinite<double>(aValue)) {
+ return aValue > 0 ? FromInfinity() : FromNegativeInfinity();
+ }
+ // Due to internal double representation, this
+ // operation is not commutative, do not attempt to simplify.
+ double halfUsec = .0000005;
+ double val =
+ (aValue <= 0 ? aValue - halfUsec : aValue + halfUsec) * USECS_PER_S;
+ if (val >= double(INT64_MAX)) {
+ return FromMicroseconds(INT64_MAX);
+ } else if (val <= double(INT64_MIN)) {
+ return FromMicroseconds(INT64_MIN);
+ } else {
+ return FromMicroseconds(int64_t(val));
+ }
+ }
+
+ static constexpr TimeUnit FromMicroseconds(int64_t aValue) {
+ return TimeUnit(aValue);
+ }
+
+ static constexpr TimeUnit FromNanoseconds(int64_t aValue) {
+ return TimeUnit(aValue / 1000);
+ }
+
+ static constexpr TimeUnit FromInfinity() { return TimeUnit(INT64_MAX); }
+
+ static constexpr TimeUnit FromNegativeInfinity() {
+ return TimeUnit(INT64_MIN);
+ }
+
+ static TimeUnit FromTimeDuration(const TimeDuration& aDuration) {
+ return FromSeconds(aDuration.ToSeconds());
+ }
+
+ static constexpr TimeUnit Zero() { return TimeUnit(0); }
+
+ static TimeUnit Invalid() {
+ TimeUnit ret;
+ ret.mValue = CheckedInt64(INT64_MAX);
+ // Force an overflow to render the CheckedInt invalid.
+ ret.mValue += 1;
+ return ret;
+ }
+
+ int64_t ToMicroseconds() const { return mValue.value(); }
+
+ int64_t ToNanoseconds() const { return mValue.value() * 1000; }
+
+ double ToSeconds() const {
+ if (IsPosInf()) {
+ return PositiveInfinity<double>();
+ }
+ if (IsNegInf()) {
+ return NegativeInfinity<double>();
+ }
+ return double(mValue.value()) / USECS_PER_S;
+ }
+
+ TimeDuration ToTimeDuration() const {
+ return TimeDuration::FromMicroseconds(mValue.value());
+ }
+
+ bool IsInfinite() const { return IsPosInf() || IsNegInf(); }
+
+ bool IsPositive() const { return mValue.value() > 0; }
+
+ bool IsNegative() const { return mValue.value() < 0; }
+
+ bool operator==(const TimeUnit& aOther) const {
+ MOZ_ASSERT(IsValid() && aOther.IsValid());
+ return mValue.value() == aOther.mValue.value();
+ }
+ bool operator!=(const TimeUnit& aOther) const {
+ MOZ_ASSERT(IsValid() && aOther.IsValid());
+ return mValue.value() != aOther.mValue.value();
+ }
+ bool operator>=(const TimeUnit& aOther) const {
+ MOZ_ASSERT(IsValid() && aOther.IsValid());
+ return mValue.value() >= aOther.mValue.value();
+ }
+ bool operator>(const TimeUnit& aOther) const { return !(*this <= aOther); }
+ bool operator<=(const TimeUnit& aOther) const {
+ MOZ_ASSERT(IsValid() && aOther.IsValid());
+ return mValue.value() <= aOther.mValue.value();
+ }
+ bool operator<(const TimeUnit& aOther) const { return !(*this >= aOther); }
+ TimeUnit operator%(const TimeUnit& aOther) const {
+ MOZ_ASSERT(IsValid() && aOther.IsValid());
+ return TimeUnit(mValue % aOther.mValue);
+ }
+
+ TimeUnit operator+(const TimeUnit& aOther) const {
+ if (IsInfinite() || aOther.IsInfinite()) {
+ // When adding at least one infinite value, the result is either
+ // +/-Inf, or NaN. So do the calculation in floating point for
+ // simplicity.
+ double result = ToSeconds() + aOther.ToSeconds();
+ return IsNaN(result) ? TimeUnit::Invalid() : FromSeconds(result);
+ }
+ return TimeUnit(mValue + aOther.mValue);
+ }
+
+ TimeUnit operator-(const TimeUnit& aOther) const {
+ if (IsInfinite() || aOther.IsInfinite()) {
+ // When subtracting at least one infinite value, the result is either
+ // +/-Inf, or NaN. So do the calculation in floating point for
+ // simplicity.
+ double result = ToSeconds() - aOther.ToSeconds();
+ return IsNaN(result) ? TimeUnit::Invalid() : FromSeconds(result);
+ }
+ MOZ_ASSERT(!IsInfinite() && !aOther.IsInfinite());
+ return TimeUnit(mValue - aOther.mValue);
+ }
+ TimeUnit& operator+=(const TimeUnit& aOther) {
+ *this = *this + aOther;
+ return *this;
+ }
+ TimeUnit& operator-=(const TimeUnit& aOther) {
+ *this = *this - aOther;
+ return *this;
+ }
+
+ template <typename T>
+ TimeUnit operator*(T aVal) const {
+ // See bug 853398 for the reason to block double multiplier.
+ // If required, use MultDouble below and with caution.
+ static_assert(std::is_integral_v<T>, "Must be an integral type");
+ return TimeUnit(mValue * aVal);
+ }
+ TimeUnit MultDouble(double aVal) const {
+ return TimeUnit::FromSeconds(ToSeconds() * aVal);
+ }
+ friend TimeUnit operator/(const TimeUnit& aUnit, int64_t aVal) {
+ MOZ_DIAGNOSTIC_ASSERT(0 <= aVal && aVal <= UINT32_MAX);
+ return TimeUnit(aUnit.mValue / aVal);
+ }
+ friend TimeUnit operator%(const TimeUnit& aUnit, int64_t aVal) {
+ MOZ_DIAGNOSTIC_ASSERT(0 <= aVal && aVal <= UINT32_MAX);
+ return TimeUnit(aUnit.mValue % aVal);
+ }
+
+ bool IsValid() const { return mValue.isValid(); }
+
+ constexpr TimeUnit() = default;
+
+ TimeUnit(const TimeUnit&) = default;
+
+ TimeUnit& operator=(const TimeUnit&) = default;
+
+ bool IsPosInf() const {
+ return mValue.isValid() && mValue.value() == INT64_MAX;
+ }
+ bool IsNegInf() const {
+ return mValue.isValid() && mValue.value() == INT64_MIN;
+ }
+
+ private:
+ explicit constexpr TimeUnit(CheckedInt64 aMicroseconds)
+ : mValue(aMicroseconds) {}
+
+ // Our internal representation is in microseconds.
+ CheckedInt64 mValue{0};
+};
+
+typedef Maybe<TimeUnit> NullableTimeUnit;
+
+typedef Interval<TimeUnit> TimeInterval;
+
+class TimeIntervals : public IntervalSet<TimeUnit> {
+ public:
+ typedef IntervalSet<TimeUnit> BaseType;
+
+ // We can't use inherited constructors yet. So we have to duplicate all the
+ // constructors found in IntervalSet base class.
+ // all this could be later replaced with:
+ // using IntervalSet<TimeUnit>::IntervalSet;
+
+ // MOZ_IMPLICIT as we want to enable initialization in the form:
+ // TimeIntervals i = ... like we would do with IntervalSet<T> i = ...
+ MOZ_IMPLICIT TimeIntervals(const BaseType& aOther) : BaseType(aOther) {}
+ MOZ_IMPLICIT TimeIntervals(BaseType&& aOther) : BaseType(std::move(aOther)) {}
+ explicit TimeIntervals(const BaseType::ElemType& aOther) : BaseType(aOther) {}
+ explicit TimeIntervals(BaseType::ElemType&& aOther)
+ : BaseType(std::move(aOther)) {}
+
+ static TimeIntervals Invalid() {
+ return TimeIntervals(TimeInterval(TimeUnit::FromNegativeInfinity(),
+ TimeUnit::FromNegativeInfinity()));
+ }
+ bool IsInvalid() const {
+ return Length() == 1 && Start(0).IsNegInf() && End(0).IsNegInf();
+ }
+
+ TimeIntervals() = default;
+};
+
+} // namespace media
+} // namespace mozilla
+
+#endif // TIME_UNITS_H