diff options
Diffstat (limited to '')
-rw-r--r-- | dom/media/gtest/TestTimeUnit.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/dom/media/gtest/TestTimeUnit.cpp b/dom/media/gtest/TestTimeUnit.cpp new file mode 100644 index 0000000000..7b199376cc --- /dev/null +++ b/dom/media/gtest/TestTimeUnit.cpp @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#include "gtest/gtest.h" +#include <algorithm> +#include <vector> + +#include "TimeUnits.h" + +using namespace mozilla; +using namespace mozilla::media; +using TimeUnit = mozilla::media::TimeUnit; + +TEST(TimeUnit, BasicArithmetic) +{ + const TimeUnit a(1000, 44100); + { + TimeUnit b = a * 10; + EXPECT_EQ(b.mBase, 44100); + EXPECT_EQ(b.mTicks.value(), a.mTicks.value() * 10); + EXPECT_EQ(a * 10, b); + } + { + TimeUnit b = a / 10; + EXPECT_EQ(b.mBase, 44100); + EXPECT_EQ(b.mTicks.value(), a.mTicks.value() / 10); + EXPECT_EQ(a / 10, b); + } + { + TimeUnit b = TimeUnit(10, 44100); + b += a; + EXPECT_EQ(b.mBase, 44100); + EXPECT_EQ(b.mTicks.value(), a.mTicks.value() + 10); + EXPECT_EQ(b - a, TimeUnit(10, 44100)); + } + { + TimeUnit b = TimeUnit(1010, 44100); + b -= a; // now 10 + EXPECT_EQ(b.mBase, 44100); + EXPECT_EQ(b.mTicks.value(), 10); + EXPECT_EQ(a + b, TimeUnit(1010, 44100)); + } + { + TimeUnit b = TimeUnit(4010, 44100); + TimeUnit c = b % a; // now 10 + EXPECT_EQ(c.mBase, 44100); + EXPECT_EQ(c.mTicks.value(), 10); + } + { + // Adding 6s in nanoseconds (e.g. coming from script) to a typical number + // from an mp4, 9001 in base 90000 + TimeUnit b = TimeUnit(6000000000, 1000000000); + TimeUnit c = TimeUnit(9001, 90000); + TimeUnit d = c + b; + EXPECT_EQ(d.mBase, 90000); + EXPECT_EQ(d.mTicks.value(), 549001); + } + { + // Subtracting 9001 in base 9000 from 6s in nanoseconds (e.g. coming from + // script), converting to back to base 9000. + TimeUnit b = TimeUnit(6000000000, 1000000000); + TimeUnit c = TimeUnit(9001, 90000); + TimeUnit d = (b - c).ToBase(90000); + EXPECT_EQ(d.mBase, 90000); + EXPECT_EQ(d.mTicks.value(), 530998); + } +} + +TEST(TimeUnit, Base) +{ + { + TimeUnit a = TimeUnit::FromSeconds(1); + EXPECT_EQ(a.mTicks.value(), 1000000); + EXPECT_EQ(a.mBase, 1000000); + } + { + TimeUnit a = TimeUnit::FromMicroseconds(44100000000); + EXPECT_EQ(a.mTicks.value(), 44100000000); + EXPECT_EQ(a.mBase, 1000000); + } + { + TimeUnit a = TimeUnit::FromSeconds(6.0); + EXPECT_EQ(a.mTicks.value(), 6000000); + EXPECT_EQ(a.mBase, 1000000); + double error; + TimeUnit b = a.ToBase(90000, error); + EXPECT_EQ(error, 0); + EXPECT_EQ(b.mTicks.value(), 540000); + EXPECT_EQ(b.mBase, 90000); + } +} + +TEST(TimeUnit, Rounding) +{ + int64_t usecs = 662617; + double seconds = TimeUnit::FromMicroseconds(usecs).ToSeconds(); + TimeUnit fromSeconds = TimeUnit::FromSeconds(seconds); + EXPECT_EQ(fromSeconds.mTicks.value(), usecs); + // TimeUnit base is microseconds if not explicitly passed. + EXPECT_EQ(fromSeconds.mBase, 1000000); + EXPECT_EQ(fromSeconds.ToMicroseconds(), usecs); + + seconds = 4.169470123; + int64_t nsecs = 4169470123; + EXPECT_EQ(TimeUnit::FromSeconds(seconds, 1e9).ToNanoseconds(), nsecs); + EXPECT_EQ(TimeUnit::FromSeconds(seconds, 1e9).ToMicroseconds(), nsecs / 1000); + + seconds = 2312312.16947012; + nsecs = 2312312169470120; + EXPECT_EQ(TimeUnit::FromSeconds(seconds, 1e9).ToNanoseconds(), nsecs); + EXPECT_EQ(TimeUnit::FromSeconds(seconds, 1e9).ToMicroseconds(), nsecs / 1000); + + seconds = 2312312.169470123; + nsecs = 2312312169470123; + // A double doesn't have enough precision to roundtrip this time value + // correctly in this base, but the number of microseconds is still correct. + // This value is about 142.5 days however. + // This particular calculation results in exactly 1ns of difference after + // roundtrip. Enable this after remoing the MOZ_CRASH in TimeUnit::FromSeconds + // EXPECT_EQ(TimeUnit::FromSeconds(seconds, 1e9).ToNanoseconds() - nsecs, 1); + EXPECT_EQ(TimeUnit::FromSeconds(seconds, 1e9).ToMicroseconds(), nsecs / 1000); +} + +TEST(TimeUnit, Comparisons) +{ + TimeUnit a(0, 1e9); + TimeUnit b(1, 1e9); + TimeUnit c(1, 1e6); + + EXPECT_GE(b, a); + EXPECT_GE(c, a); + EXPECT_GE(c, b); + + EXPECT_GT(b, a); + EXPECT_GT(c, a); + EXPECT_GT(c, b); + + EXPECT_LE(a, b); + EXPECT_LE(a, c); + EXPECT_LE(b, c); + + EXPECT_LT(a, b); + EXPECT_LT(a, c); + EXPECT_LT(b, c); + + // Equivalence of zero regardless of the base + TimeUnit d(0, 1); + TimeUnit e(0, 1000); + EXPECT_EQ(a, d); + EXPECT_EQ(a, e); + + // Equivalence of time accross bases + TimeUnit f(1000, 1e9); + TimeUnit g(1, 1e6); + EXPECT_EQ(f, g); + + // Comparisons with infinity, same base + TimeUnit h = TimeUnit::FromInfinity(); + TimeUnit i = TimeUnit::Zero(); + EXPECT_LE(i, h); + EXPECT_LT(i, h); + EXPECT_GE(h, i); + EXPECT_GT(h, i); + + // Comparisons with infinity, different base + TimeUnit j = TimeUnit::FromInfinity(); + TimeUnit k = TimeUnit::Zero(1000000); + EXPECT_LE(k, j); + EXPECT_LT(k, j); + EXPECT_GE(j, k); + EXPECT_GT(j, k); + + // Comparison of very big numbers, different base that have a gcd that makes + // it easy to reduce, to test the fraction reduction code + TimeUnit l = TimeUnit(123123120000000, 1000000000); + TimeUnit m = TimeUnit(123123120000000, 1000); + EXPECT_LE(l, m); + EXPECT_LT(l, m); + EXPECT_GE(m, l); + EXPECT_GT(m, l); + + // Comparison of very big numbers, different base that are co-prime: worst + // cast scenario. + TimeUnit n = TimeUnit(123123123123123, 1000000000); + TimeUnit o = TimeUnit(123123123123123, 1000000001); + EXPECT_LE(o, n); + EXPECT_LT(o, n); + EXPECT_GE(n, o); + EXPECT_GT(n, o); + + // Values taken from a real website (this is about 53 years, Date.now() in + // 2023). + TimeUnit leftBound(74332508253360, 44100); + TimeUnit rightBound(74332508297392, 44100); + TimeUnit fuzz(250000, 1000000); + TimeUnit time(1685544404790205, 1000000); + + EXPECT_LT(leftBound - fuzz, time); + EXPECT_GT(time, leftBound - fuzz); + EXPECT_GE(rightBound + fuzz, time); + EXPECT_LT(time, rightBound + fuzz); + + TimeUnit zero = TimeUnit::Zero(); // default base 1e6 + TimeUnit datenow( + 151737439364679, + 90000); // Also from `Date.now()` in a common base for an mp4 + EXPECT_NE(zero, datenow); +} + +TEST(TimeUnit, InfinityMath) +{ + // Operator plus/minus uses floating point behaviour for positive and + // negative infinity values, i.e.: + // posInf + posInf = inf + // posInf + negInf = -nan + // posInf + finite = inf + // posInf - posInf = -nan + // posInf - negInf = inf + // posInf - finite = inf + // negInf + negInf = -inf + // negInf + posInf = -nan + // negInf + finite = -inf + // negInf - negInf = -nan + // negInf - posInf = -inf + // negInf - finite = -inf + // finite + posInf = inf + // finite - posInf = -inf + // finite + negInf = -inf + // finite - negInf = inf + + const TimeUnit posInf = TimeUnit::FromInfinity(); + EXPECT_EQ(TimeUnit::FromSeconds(mozilla::PositiveInfinity<double>()), posInf); + + const TimeUnit negInf = TimeUnit::FromNegativeInfinity(); + EXPECT_EQ(TimeUnit::FromSeconds(mozilla::NegativeInfinity<double>()), negInf); + + EXPECT_EQ(posInf + posInf, posInf); + EXPECT_FALSE((posInf + negInf).IsValid()); + EXPECT_FALSE((posInf - posInf).IsValid()); + EXPECT_EQ(posInf - negInf, posInf); + EXPECT_EQ(negInf + negInf, negInf); + EXPECT_FALSE((negInf + posInf).IsValid()); + EXPECT_FALSE((negInf - negInf).IsValid()); + EXPECT_EQ(negInf - posInf, negInf); + + const TimeUnit finite = TimeUnit::FromSeconds(42.0); + EXPECT_EQ(posInf - finite, posInf); + EXPECT_EQ(posInf + finite, posInf); + EXPECT_EQ(negInf - finite, negInf); + EXPECT_EQ(negInf + finite, negInf); + + EXPECT_EQ(finite + posInf, posInf); + EXPECT_EQ(finite - posInf, negInf); + EXPECT_EQ(finite + negInf, negInf); + EXPECT_EQ(finite - negInf, posInf); +} + +TEST(TimeUnit, BaseConversion) +{ + const int64_t packetSize = 1024; // typical for AAC + int64_t sampleRates[] = {16000, 44100, 48000, 88200, 96000}; + const double hnsPerSeconds = 10000000.; + for (auto sampleRate : sampleRates) { + int64_t frameCount = 0; + TimeUnit pts; + do { + // Compute a time in hundreds of nanoseconds based of frame count, typical + // on Windows platform, checking that it round trips properly. + int64_t hns = AssertedCast<int64_t>( + std::round(hnsPerSeconds * static_cast<double>(frameCount) / + static_cast<double>(sampleRate))); + pts = TimeUnit::FromHns(hns, sampleRate); + EXPECT_EQ( + AssertedCast<int64_t>(std::round(pts.ToSeconds() * hnsPerSeconds)), + hns); + frameCount += packetSize; + } while (pts.ToSeconds() < 36000); + } +} |