mirror of
https://github.com/darlinghq/darling-WTF.git
synced 2024-11-26 21:30:30 +00:00
645 lines
18 KiB
C++
645 lines
18 KiB
C++
/*
|
|
* Copyright (C) 2012-2019 Apple Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
|
|
* its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <wtf/MediaTime.h>
|
|
|
|
#include <algorithm>
|
|
#include <cstdlib>
|
|
#include <wtf/Assertions.h>
|
|
#include <wtf/CheckedArithmetic.h>
|
|
#include <wtf/JSONValues.h>
|
|
#include <wtf/MathExtras.h>
|
|
#include <wtf/PrintStream.h>
|
|
#include <wtf/text/StringBuilder.h>
|
|
#include <wtf/text/TextStream.h>
|
|
|
|
namespace WTF {
|
|
|
|
static_assert(std::is_trivially_destructible_v<MediaTime>, "MediaTime should be trivially destructible.");
|
|
|
|
static uint32_t greatestCommonDivisor(uint32_t a, uint32_t b)
|
|
{
|
|
ASSERT(a);
|
|
ASSERT(b);
|
|
|
|
// Euclid's Algorithm
|
|
uint32_t temp = 0;
|
|
while (b) {
|
|
temp = b;
|
|
b = a % b;
|
|
a = temp;
|
|
}
|
|
|
|
ASSERT(a);
|
|
return a;
|
|
}
|
|
|
|
static uint32_t leastCommonMultiple(uint32_t a, uint32_t b, uint32_t &result)
|
|
{
|
|
return safeMultiply(a, b / greatestCommonDivisor(a, b), result);
|
|
}
|
|
|
|
static int64_t signum(int64_t val)
|
|
{
|
|
return (0 < val) - (val < 0);
|
|
}
|
|
|
|
const uint32_t MediaTime::MaximumTimeScale = 1000000000;
|
|
|
|
MediaTime::MediaTime(const MediaTime& rhs)
|
|
{
|
|
*this = rhs;
|
|
}
|
|
|
|
MediaTime MediaTime::createWithFloat(float floatTime)
|
|
{
|
|
if (floatTime != floatTime)
|
|
return invalidTime();
|
|
if (std::isinf(floatTime))
|
|
return std::signbit(floatTime) ? negativeInfiniteTime() : positiveInfiniteTime();
|
|
|
|
MediaTime value(0, DefaultTimeScale, Valid | DoubleValue);
|
|
value.m_timeValueAsDouble = floatTime;
|
|
return value;
|
|
}
|
|
|
|
MediaTime MediaTime::createWithFloat(float floatTime, uint32_t timeScale)
|
|
{
|
|
if (floatTime != floatTime)
|
|
return invalidTime();
|
|
if (std::isinf(floatTime))
|
|
return std::signbit(floatTime) ? negativeInfiniteTime() : positiveInfiniteTime();
|
|
if (floatTime >= maxPlusOne<int64_t>)
|
|
return positiveInfiniteTime();
|
|
if (floatTime < std::numeric_limits<int64_t>::min())
|
|
return negativeInfiniteTime();
|
|
if (!timeScale)
|
|
return std::signbit(floatTime) ? negativeInfiniteTime() : positiveInfiniteTime();
|
|
|
|
while (floatTime * timeScale >= maxPlusOne<int64_t>)
|
|
timeScale /= 2;
|
|
return MediaTime(static_cast<int64_t>(floatTime * timeScale), timeScale, Valid);
|
|
}
|
|
|
|
MediaTime MediaTime::createWithDouble(double doubleTime)
|
|
{
|
|
if (doubleTime != doubleTime)
|
|
return invalidTime();
|
|
if (std::isinf(doubleTime))
|
|
return std::signbit(doubleTime) ? negativeInfiniteTime() : positiveInfiniteTime();
|
|
|
|
MediaTime value(0, DefaultTimeScale, Valid | DoubleValue);
|
|
value.m_timeValueAsDouble = doubleTime;
|
|
return value;
|
|
}
|
|
|
|
MediaTime MediaTime::createWithDouble(double doubleTime, uint32_t timeScale)
|
|
{
|
|
if (doubleTime != doubleTime)
|
|
return invalidTime();
|
|
if (std::isinf(doubleTime))
|
|
return std::signbit(doubleTime) ? negativeInfiniteTime() : positiveInfiniteTime();
|
|
if (doubleTime >= maxPlusOne<int64_t>)
|
|
return positiveInfiniteTime();
|
|
if (doubleTime < std::numeric_limits<int64_t>::min())
|
|
return negativeInfiniteTime();
|
|
if (!timeScale)
|
|
return std::signbit(doubleTime) ? negativeInfiniteTime() : positiveInfiniteTime();
|
|
|
|
while (doubleTime * timeScale >= maxPlusOne<int64_t>)
|
|
timeScale /= 2;
|
|
return MediaTime(static_cast<int64_t>(std::round(doubleTime * timeScale)), timeScale, Valid);
|
|
}
|
|
|
|
float MediaTime::toFloat() const
|
|
{
|
|
if (isInvalid() || isIndefinite())
|
|
return std::numeric_limits<float>::quiet_NaN();
|
|
if (isPositiveInfinite())
|
|
return std::numeric_limits<float>::infinity();
|
|
if (isNegativeInfinite())
|
|
return -std::numeric_limits<float>::infinity();
|
|
if (hasDoubleValue())
|
|
return m_timeValueAsDouble;
|
|
return static_cast<float>(m_timeValue) / m_timeScale;
|
|
}
|
|
|
|
double MediaTime::toDouble() const
|
|
{
|
|
if (isInvalid() || isIndefinite())
|
|
return std::numeric_limits<double>::quiet_NaN();
|
|
if (isPositiveInfinite())
|
|
return std::numeric_limits<double>::infinity();
|
|
if (isNegativeInfinite())
|
|
return -std::numeric_limits<double>::infinity();
|
|
if (hasDoubleValue())
|
|
return m_timeValueAsDouble;
|
|
return static_cast<double>(m_timeValue) / m_timeScale;
|
|
}
|
|
|
|
MediaTime& MediaTime::operator=(const MediaTime& rhs)
|
|
{
|
|
m_timeValue = rhs.m_timeValue;
|
|
m_timeScale = rhs.m_timeScale;
|
|
m_timeFlags = rhs.m_timeFlags;
|
|
return *this;
|
|
}
|
|
|
|
MediaTime MediaTime::operator+(const MediaTime& rhs) const
|
|
{
|
|
if (rhs.isInvalid() || isInvalid())
|
|
return invalidTime();
|
|
|
|
if (rhs.isIndefinite() || isIndefinite())
|
|
return indefiniteTime();
|
|
|
|
if (isPositiveInfinite() && rhs.isNegativeInfinite())
|
|
return invalidTime();
|
|
|
|
if (isNegativeInfinite() && rhs.isPositiveInfinite())
|
|
return invalidTime();
|
|
|
|
if (isPositiveInfinite() || rhs.isPositiveInfinite())
|
|
return positiveInfiniteTime();
|
|
|
|
if (isNegativeInfinite() || rhs.isNegativeInfinite())
|
|
return negativeInfiniteTime();
|
|
|
|
if (hasDoubleValue() && rhs.hasDoubleValue())
|
|
return MediaTime::createWithDouble(m_timeValueAsDouble + rhs.m_timeValueAsDouble);
|
|
|
|
if (hasDoubleValue() || rhs.hasDoubleValue())
|
|
return MediaTime::createWithDouble(toDouble() + rhs.toDouble());
|
|
|
|
MediaTime a = *this;
|
|
MediaTime b = rhs;
|
|
|
|
uint32_t commonTimeScale;
|
|
if (!leastCommonMultiple(a.m_timeScale, b.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
|
|
commonTimeScale = MaximumTimeScale;
|
|
a.setTimeScale(commonTimeScale);
|
|
b.setTimeScale(commonTimeScale);
|
|
while (!safeAdd(a.m_timeValue, b.m_timeValue, a.m_timeValue)) {
|
|
if (commonTimeScale == 1)
|
|
return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime();
|
|
commonTimeScale /= 2;
|
|
a.setTimeScale(commonTimeScale);
|
|
b.setTimeScale(commonTimeScale);
|
|
}
|
|
return a;
|
|
}
|
|
|
|
MediaTime MediaTime::operator-(const MediaTime& rhs) const
|
|
{
|
|
if (rhs.isInvalid() || isInvalid())
|
|
return invalidTime();
|
|
|
|
if (rhs.isIndefinite() || isIndefinite())
|
|
return indefiniteTime();
|
|
|
|
if (isPositiveInfinite() && rhs.isPositiveInfinite())
|
|
return invalidTime();
|
|
|
|
if (isNegativeInfinite() && rhs.isNegativeInfinite())
|
|
return invalidTime();
|
|
|
|
if (isPositiveInfinite() || rhs.isNegativeInfinite())
|
|
return positiveInfiniteTime();
|
|
|
|
if (isNegativeInfinite() || rhs.isPositiveInfinite())
|
|
return negativeInfiniteTime();
|
|
|
|
if (hasDoubleValue() && rhs.hasDoubleValue())
|
|
return MediaTime::createWithDouble(m_timeValueAsDouble - rhs.m_timeValueAsDouble);
|
|
|
|
if (hasDoubleValue() || rhs.hasDoubleValue())
|
|
return MediaTime::createWithDouble(toDouble() - rhs.toDouble());
|
|
|
|
MediaTime a = *this;
|
|
MediaTime b = rhs;
|
|
|
|
uint32_t commonTimeScale;
|
|
if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
|
|
commonTimeScale = MaximumTimeScale;
|
|
a.setTimeScale(commonTimeScale);
|
|
b.setTimeScale(commonTimeScale);
|
|
while (!safeSub(a.m_timeValue, b.m_timeValue, a.m_timeValue)) {
|
|
if (commonTimeScale == 1)
|
|
return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime();
|
|
commonTimeScale /= 2;
|
|
a.setTimeScale(commonTimeScale);
|
|
b.setTimeScale(commonTimeScale);
|
|
}
|
|
return a;
|
|
}
|
|
|
|
MediaTime MediaTime::operator-() const
|
|
{
|
|
if (isInvalid())
|
|
return invalidTime();
|
|
|
|
if (isIndefinite())
|
|
return indefiniteTime();
|
|
|
|
if (isPositiveInfinite())
|
|
return negativeInfiniteTime();
|
|
|
|
if (isNegativeInfinite())
|
|
return positiveInfiniteTime();
|
|
|
|
MediaTime negativeTime = *this;
|
|
if (negativeTime.hasDoubleValue())
|
|
negativeTime.m_timeValueAsDouble = -negativeTime.m_timeValueAsDouble;
|
|
else
|
|
negativeTime.m_timeValue = -negativeTime.m_timeValue;
|
|
return negativeTime;
|
|
}
|
|
|
|
MediaTime MediaTime::operator*(int32_t rhs) const
|
|
{
|
|
if (isInvalid())
|
|
return invalidTime();
|
|
|
|
if (isIndefinite())
|
|
return indefiniteTime();
|
|
|
|
if (!rhs)
|
|
return zeroTime();
|
|
|
|
if (isPositiveInfinite()) {
|
|
if (rhs > 0)
|
|
return positiveInfiniteTime();
|
|
return negativeInfiniteTime();
|
|
}
|
|
|
|
if (isNegativeInfinite()) {
|
|
if (rhs > 0)
|
|
return negativeInfiniteTime();
|
|
return positiveInfiniteTime();
|
|
}
|
|
|
|
MediaTime a = *this;
|
|
|
|
if (a.hasDoubleValue()) {
|
|
a.m_timeValueAsDouble *= rhs;
|
|
return a;
|
|
}
|
|
|
|
while (!safeMultiply(a.m_timeValue, rhs, a.m_timeValue)) {
|
|
if (a.m_timeScale == 1)
|
|
return signum(a.m_timeValue) == signum(rhs) ? positiveInfiniteTime() : negativeInfiniteTime();
|
|
a.setTimeScale(a.m_timeScale / 2);
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
bool MediaTime::operator!() const
|
|
{
|
|
return (m_timeFlags == Valid && !m_timeValue)
|
|
|| (m_timeFlags == (Valid | DoubleValue) && !m_timeValueAsDouble)
|
|
|| isInvalid();
|
|
}
|
|
|
|
MediaTime::operator bool() const
|
|
{
|
|
return !(m_timeFlags == Valid && !m_timeValue)
|
|
&& !(m_timeFlags == (Valid | DoubleValue) && !m_timeValueAsDouble)
|
|
&& !isInvalid();
|
|
}
|
|
|
|
MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs) const
|
|
{
|
|
auto andFlags = m_timeFlags & rhs.m_timeFlags;
|
|
if (andFlags & (PositiveInfinite | NegativeInfinite | Indefinite))
|
|
return EqualTo;
|
|
|
|
auto orFlags = m_timeFlags | rhs.m_timeFlags;
|
|
if (!(orFlags & Valid))
|
|
return EqualTo;
|
|
|
|
if (!(andFlags & Valid))
|
|
return isInvalid() ? GreaterThan : LessThan;
|
|
|
|
if (orFlags & NegativeInfinite)
|
|
return isNegativeInfinite() ? LessThan : GreaterThan;
|
|
|
|
if (orFlags & PositiveInfinite)
|
|
return isPositiveInfinite() ? GreaterThan : LessThan;
|
|
|
|
if (orFlags & Indefinite)
|
|
return isIndefinite() ? GreaterThan : LessThan;
|
|
|
|
if (andFlags & DoubleValue) {
|
|
if (m_timeValueAsDouble == rhs.m_timeValueAsDouble)
|
|
return EqualTo;
|
|
|
|
return m_timeValueAsDouble < rhs.m_timeValueAsDouble ? LessThan : GreaterThan;
|
|
}
|
|
|
|
if (orFlags & DoubleValue) {
|
|
double a = toDouble();
|
|
double b = rhs.toDouble();
|
|
if (a > b)
|
|
return GreaterThan;
|
|
if (a < b)
|
|
return LessThan;
|
|
return EqualTo;
|
|
}
|
|
|
|
if ((m_timeValue < 0) != (rhs.m_timeValue < 0))
|
|
return m_timeValue < 0 ? LessThan : GreaterThan;
|
|
|
|
if (!m_timeValue && !rhs.m_timeValue)
|
|
return EqualTo;
|
|
|
|
if (m_timeScale == rhs.m_timeScale) {
|
|
if (m_timeValue == rhs.m_timeValue)
|
|
return EqualTo;
|
|
return m_timeValue < rhs.m_timeValue ? LessThan : GreaterThan;
|
|
}
|
|
|
|
if (m_timeValue == rhs.m_timeValue)
|
|
return m_timeScale < rhs.m_timeScale ? GreaterThan : LessThan;
|
|
|
|
if (m_timeValue >= 0) {
|
|
if (m_timeValue < rhs.m_timeValue && m_timeScale > rhs.m_timeScale)
|
|
return LessThan;
|
|
|
|
if (m_timeValue > rhs.m_timeValue && m_timeScale < rhs.m_timeScale)
|
|
return GreaterThan;
|
|
} else {
|
|
if (m_timeValue < rhs.m_timeValue && m_timeScale < rhs.m_timeScale)
|
|
return LessThan;
|
|
|
|
if (m_timeValue > rhs.m_timeValue && m_timeScale > rhs.m_timeScale)
|
|
return GreaterThan;
|
|
}
|
|
|
|
int64_t lhsFactor;
|
|
int64_t rhsFactor;
|
|
if (safeMultiply(m_timeValue, static_cast<int64_t>(rhs.m_timeScale), lhsFactor)
|
|
&& safeMultiply(rhs.m_timeValue, static_cast<int64_t>(m_timeScale), rhsFactor)) {
|
|
if (lhsFactor == rhsFactor)
|
|
return EqualTo;
|
|
return lhsFactor < rhsFactor ? LessThan : GreaterThan;
|
|
}
|
|
|
|
int64_t rhsWhole = rhs.m_timeValue / rhs.m_timeScale;
|
|
int64_t lhsWhole = m_timeValue / m_timeScale;
|
|
if (lhsWhole > rhsWhole)
|
|
return GreaterThan;
|
|
if (lhsWhole < rhsWhole)
|
|
return LessThan;
|
|
|
|
int64_t rhsRemain = rhs.m_timeValue % rhs.m_timeScale;
|
|
int64_t lhsRemain = m_timeValue % m_timeScale;
|
|
lhsFactor = lhsRemain * rhs.m_timeScale;
|
|
rhsFactor = rhsRemain * m_timeScale;
|
|
|
|
if (lhsFactor == rhsFactor)
|
|
return EqualTo;
|
|
return lhsFactor > rhsFactor ? GreaterThan : LessThan;
|
|
}
|
|
|
|
bool MediaTime::isBetween(const MediaTime& a, const MediaTime& b) const
|
|
{
|
|
if (a > b)
|
|
return *this > b && *this < a;
|
|
return *this > a && *this < b;
|
|
}
|
|
|
|
const MediaTime& MediaTime::zeroTime()
|
|
{
|
|
static const MediaTime time(0, 1, Valid);
|
|
return time;
|
|
}
|
|
|
|
const MediaTime& MediaTime::invalidTime()
|
|
{
|
|
static const MediaTime time(-1, 1, 0);
|
|
return time;
|
|
}
|
|
|
|
const MediaTime& MediaTime::positiveInfiniteTime()
|
|
{
|
|
static const MediaTime time(0, 1, PositiveInfinite | Valid);
|
|
return time;
|
|
}
|
|
|
|
const MediaTime& MediaTime::negativeInfiniteTime()
|
|
{
|
|
static const MediaTime time(-1, 1, NegativeInfinite | Valid);
|
|
return time;
|
|
}
|
|
|
|
const MediaTime& MediaTime::indefiniteTime()
|
|
{
|
|
static const MediaTime time(0, 1, Indefinite | Valid);
|
|
return time;
|
|
}
|
|
|
|
MediaTime MediaTime::toTimeScale(uint32_t timeScale, RoundingFlags flags) const
|
|
{
|
|
MediaTime result = *this;
|
|
result.setTimeScale(timeScale, flags);
|
|
return result;
|
|
}
|
|
|
|
void MediaTime::setTimeScale(uint32_t timeScale, RoundingFlags flags)
|
|
{
|
|
if (hasDoubleValue()) {
|
|
*this = MediaTime::createWithDouble(m_timeValueAsDouble, timeScale);
|
|
return;
|
|
}
|
|
|
|
if (!timeScale) {
|
|
*this = m_timeValue < 0 ? negativeInfiniteTime() : positiveInfiniteTime();
|
|
return;
|
|
}
|
|
|
|
if (timeScale == m_timeScale)
|
|
return;
|
|
|
|
timeScale = std::min(MaximumTimeScale, timeScale);
|
|
|
|
#if HAVE(INT128_T)
|
|
__int128_t newValue = static_cast<__int128_t>(m_timeValue) * timeScale;
|
|
int64_t remainder = newValue % m_timeScale;
|
|
newValue = newValue / m_timeScale;
|
|
|
|
if (newValue < std::numeric_limits<int64_t>::min()) {
|
|
*this = negativeInfiniteTime();
|
|
return;
|
|
}
|
|
|
|
if (newValue > std::numeric_limits<int64_t>::max()) {
|
|
*this = positiveInfiniteTime();
|
|
return;
|
|
}
|
|
#else
|
|
int64_t newValue = m_timeValue / m_timeScale;
|
|
int64_t partialRemainder = (m_timeValue % m_timeScale) * timeScale;
|
|
int64_t remainder = partialRemainder % m_timeScale;
|
|
|
|
if (!safeMultiply<int64_t>(newValue, static_cast<int64_t>(timeScale), newValue)
|
|
|| !safeAdd(newValue, partialRemainder / m_timeScale, newValue)) {
|
|
*this = newValue < 0 ? negativeInfiniteTime() : positiveInfiniteTime();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
m_timeValue = newValue;
|
|
std::swap(m_timeScale, timeScale);
|
|
|
|
if (!remainder)
|
|
return;
|
|
|
|
m_timeFlags |= HasBeenRounded;
|
|
switch (flags) {
|
|
case RoundingFlags::HalfAwayFromZero:
|
|
if (static_cast<int64_t>(llabs(remainder)) * 2 >= static_cast<int64_t>(timeScale)) {
|
|
// round up (away from zero)
|
|
if (remainder < 0)
|
|
m_timeValue--;
|
|
else
|
|
m_timeValue++;
|
|
}
|
|
break;
|
|
|
|
case RoundingFlags::TowardZero:
|
|
break;
|
|
|
|
case RoundingFlags::AwayFromZero:
|
|
if (remainder < 0)
|
|
m_timeValue--;
|
|
else
|
|
m_timeValue++;
|
|
break;
|
|
|
|
case RoundingFlags::TowardPositiveInfinity:
|
|
if (remainder > 0)
|
|
m_timeValue++;
|
|
break;
|
|
|
|
case RoundingFlags::TowardNegativeInfinity:
|
|
if (remainder < 0)
|
|
m_timeValue--;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MediaTime::dump(PrintStream& out) const
|
|
{
|
|
out.print("{");
|
|
if (!hasDoubleValue())
|
|
out.print(m_timeValue, "/", m_timeScale, " = ");
|
|
out.print(toDouble(), "}");
|
|
}
|
|
|
|
String MediaTime::toString() const
|
|
{
|
|
StringBuilder builder;
|
|
builder.append('{');
|
|
if (!hasDoubleValue())
|
|
builder.append(m_timeValue, '/', m_timeScale, " = ");
|
|
builder.append(toDouble());
|
|
if (isInvalid())
|
|
builder.appendLiteral(", invalid");
|
|
builder.append('}');
|
|
return builder.toString();
|
|
}
|
|
|
|
Ref<JSON::Object> MediaTime::toJSONObject() const
|
|
{
|
|
auto object = JSON::Object::create();
|
|
|
|
if (hasDoubleValue()) {
|
|
object->setDouble("value"_s, toDouble());
|
|
return object;
|
|
}
|
|
|
|
if (isInvalid())
|
|
object->setBoolean("invalid"_s, true);
|
|
else if (isIndefinite())
|
|
object->setString("value"_s, "NaN"_s);
|
|
else if (isPositiveInfinite())
|
|
object->setString("value"_s, "POSITIVE_INFINITY"_s);
|
|
else if (isNegativeInfinite())
|
|
object->setString("value"_s, "NEGATIVE_INFINITY"_s);
|
|
else
|
|
object->setDouble("value"_s, toDouble());
|
|
|
|
object->setDouble("numerator"_s, static_cast<double>(m_timeValue));
|
|
object->setInteger("denominator"_s, m_timeScale);
|
|
object->setInteger("flags"_s, m_timeFlags);
|
|
|
|
return object;
|
|
}
|
|
|
|
String MediaTime::toJSONString() const
|
|
{
|
|
return toJSONObject()->toJSONString();
|
|
}
|
|
|
|
MediaTime abs(const MediaTime& rhs)
|
|
{
|
|
if (rhs.isInvalid())
|
|
return MediaTime::invalidTime();
|
|
if (rhs.isNegativeInfinite() || rhs.isPositiveInfinite())
|
|
return MediaTime::positiveInfiniteTime();
|
|
if (rhs.hasDoubleValue())
|
|
return MediaTime::createWithDouble(fabs(rhs.m_timeValueAsDouble));
|
|
|
|
MediaTime val = rhs;
|
|
val.m_timeValue = std::abs(rhs.m_timeValue);
|
|
return val;
|
|
}
|
|
|
|
String MediaTimeRange::toJSONString() const
|
|
{
|
|
auto object = JSON::Object::create();
|
|
|
|
object->setObject("start"_s, start.toJSONObject());
|
|
object->setObject("end"_s, end.toJSONObject());
|
|
|
|
return object->toJSONString();
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
|
|
TextStream& operator<<(TextStream& stream, const MediaTime& time)
|
|
{
|
|
return stream << time.toJSONString();
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|