Bug 1538023 - Add support for -Inf to media::TimeUnits. r=jya

TimeUnits with a negative infinity value are used in the next patch.

Differential Revision: https://phabricator.services.mozilla.com/D30309

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Chris Pearce 2019-05-08 06:27:03 +00:00
Родитель 91b62e5a8d
Коммит b64a2d776d
4 изменённых файлов: 84 добавлений и 11 удалений

Просмотреть файл

@ -45,7 +45,7 @@ class TimeUnit final {
MOZ_ASSERT(!IsNaN(aValue));
if (mozilla::IsInfinite<double>(aValue)) {
return FromInfinity();
return aValue > 0 ? FromInfinity() : FromNegativeInfinity();
}
// Due to internal double representation, this
// operation is not commutative, do not attempt to simplify.
@ -71,6 +71,10 @@ class TimeUnit final {
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());
}
@ -90,9 +94,12 @@ class TimeUnit final {
int64_t ToNanoseconds() const { return mValue.value() * 1000; }
double ToSeconds() const {
if (IsInfinite()) {
if (IsPosInf()) {
return PositiveInfinity<double>();
}
if (IsNegInf()) {
return NegativeInfinity<double>();
}
return double(mValue.value()) / USECS_PER_S;
}
@ -100,7 +107,7 @@ class TimeUnit final {
return TimeDuration::FromMicroseconds(mValue.value());
}
bool IsInfinite() const { return mValue.value() == INT64_MAX; }
bool IsInfinite() const { return IsPosInf() || IsNegInf(); }
bool IsPositive() const { return mValue.value() > 0; }
@ -128,15 +135,25 @@ class TimeUnit final {
MOZ_ASSERT(IsValid() && aOther.IsValid());
return TimeUnit(mValue % aOther.mValue);
}
TimeUnit operator+(const TimeUnit& aOther) const {
if (IsInfinite() || aOther.IsInfinite()) {
return FromInfinity();
// 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()) {
return FromInfinity();
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);
@ -177,6 +194,13 @@ class TimeUnit final {
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) {}
@ -207,12 +231,11 @@ class TimeIntervals : public IntervalSet<TimeUnit> {
: BaseType(std::move(aOther)) {}
static TimeIntervals Invalid() {
return TimeIntervals(TimeInterval(TimeUnit::FromMicroseconds(INT64_MIN),
TimeUnit::FromMicroseconds(INT64_MIN)));
return TimeIntervals(TimeInterval(TimeUnit::FromNegativeInfinity(),
TimeUnit::FromNegativeInfinity()));
}
bool IsInvalid() const {
return Length() == 1 && Start(0).ToMicroseconds() == INT64_MIN &&
End(0).ToMicroseconds() == INT64_MIN;
return Length() == 1 && Start(0).IsNegInf() && End(0).IsNegInf();
}
TimeIntervals() = default;

Просмотреть файл

@ -9,6 +9,7 @@
#include <vector>
using namespace mozilla;
using namespace mozilla::media;
TEST(TimeUnit, Rounding)
{
@ -20,3 +21,51 @@ TEST(TimeUnit, Rounding)
usecs = 4169470;
EXPECT_EQ(media::TimeUnit::FromSeconds(seconds).ToMicroseconds(), usecs);
}
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);
}

Просмотреть файл

@ -37,6 +37,7 @@ UNIFIED_SOURCES += [
'TestMP4Demuxer.cpp',
'TestOpusParser.cpp',
'TestRust.cpp',
'TestTimeUnit.cpp',
'TestVideoSegment.cpp',
'TestVideoUtils.cpp',
'TestVPXDecoding.cpp',

Просмотреть файл

@ -28,7 +28,7 @@ FFmpegDataDecoder<LIBAV_VER>::FFmpegDataDecoder(FFmpegLibWrapper* aLib,
mExtraData(nullptr),
mCodecID(aCodecID),
mTaskQueue(aTaskQueue),
mLastInputDts(media::TimeUnit::FromMicroseconds(INT64_MIN)) {
mLastInputDts(media::TimeUnit::FromNegativeInfinity()) {
MOZ_ASSERT(aLib);
MOZ_COUNT_CTOR(FFmpegDataDecoder);
}