summaryrefslogtreecommitdiff
path: root/Source/WTF/wtf/MediaTime.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WTF/wtf/MediaTime.cpp')
-rw-r--r--Source/WTF/wtf/MediaTime.cpp243
1 files changed, 187 insertions, 56 deletions
diff --git a/Source/WTF/wtf/MediaTime.cpp b/Source/WTF/wtf/MediaTime.cpp
index f856714d0..9f53402c1 100644
--- a/Source/WTF/wtf/MediaTime.cpp
+++ b/Source/WTF/wtf/MediaTime.cpp
@@ -10,7 +10,7 @@
* 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 Computer, Inc. ("Apple") nor the names of
+ * 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.
*
@@ -30,15 +30,17 @@
#include "MediaTime.h"
#include <algorithm>
+#include <cstdlib>
#include <wtf/CheckedArithmetic.h>
#include <wtf/MathExtras.h>
+#include <wtf/PrintStream.h>
namespace WTF {
-static int32_t greatestCommonDivisor(int32_t a, int32_t b)
+static uint32_t greatestCommonDivisor(uint32_t a, uint32_t b)
{
// Euclid's Algorithm
- int32_t temp = 0;
+ uint32_t temp = 0;
while (b) {
temp = b;
b = a % b;
@@ -47,17 +49,17 @@ static int32_t greatestCommonDivisor(int32_t a, int32_t b)
return a;
}
-static int32_t leastCommonMultiple(int32_t a, int32_t b, int32_t &result)
+static uint32_t leastCommonMultiple(uint32_t a, uint32_t b, uint32_t &result)
{
return safeMultiply(a, b / greatestCommonDivisor(a, b), result);
}
-static int32_t signum(int64_t val)
+static int64_t signum(int64_t val)
{
return (0 < val) - (val < 0);
}
-const int32_t MediaTime::MaximumTimeScale = 0x7fffffffL;
+const uint32_t MediaTime::MaximumTimeScale = 0x7fffffffL;
MediaTime::MediaTime()
: m_timeValue(0)
@@ -66,7 +68,7 @@ MediaTime::MediaTime()
{
}
-MediaTime::MediaTime(int64_t value, int32_t scale, uint32_t flags)
+MediaTime::MediaTime(int64_t value, uint32_t scale, uint8_t flags)
: m_timeValue(value)
, m_timeScale(scale)
, m_timeFlags(flags)
@@ -82,7 +84,23 @@ MediaTime::MediaTime(const MediaTime& rhs)
*this = rhs;
}
-MediaTime MediaTime::createWithFloat(float floatTime, int32_t timeScale)
+MediaTime MediaTime::createWithFloat(float floatTime)
+{
+ if (floatTime != floatTime)
+ return invalidTime();
+ if (std::isinf(floatTime))
+ return std::signbit(floatTime) ? negativeInfiniteTime() : positiveInfiniteTime();
+ if (floatTime > std::numeric_limits<int64_t>::max())
+ return positiveInfiniteTime();
+ if (floatTime < std::numeric_limits<int64_t>::min())
+ return negativeInfiniteTime();
+
+ 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();
@@ -98,7 +116,23 @@ MediaTime MediaTime::createWithFloat(float floatTime, int32_t timeScale)
return MediaTime(static_cast<int64_t>(floatTime * timeScale), timeScale, Valid);
}
-MediaTime MediaTime::createWithDouble(double doubleTime, int32_t timeScale)
+MediaTime MediaTime::createWithDouble(double doubleTime)
+{
+ if (doubleTime != doubleTime)
+ return invalidTime();
+ if (std::isinf(doubleTime))
+ return std::signbit(doubleTime) ? negativeInfiniteTime() : positiveInfiniteTime();
+ if (doubleTime > std::numeric_limits<int64_t>::max())
+ return positiveInfiniteTime();
+ if (doubleTime < std::numeric_limits<int64_t>::min())
+ return negativeInfiniteTime();
+
+ 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();
@@ -111,7 +145,7 @@ MediaTime MediaTime::createWithDouble(double doubleTime, int32_t timeScale)
while (doubleTime * timeScale > std::numeric_limits<int64_t>::max())
timeScale /= 2;
- return MediaTime(static_cast<int64_t>(doubleTime * timeScale), timeScale, Valid);
+ return MediaTime(static_cast<int64_t>(std::round(doubleTime * timeScale)), timeScale, Valid);
}
float MediaTime::toFloat() const
@@ -122,6 +156,8 @@ float MediaTime::toFloat() const
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;
}
@@ -133,6 +169,8 @@ double MediaTime::toDouble() const
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;
}
@@ -164,11 +202,20 @@ MediaTime MediaTime::operator+(const MediaTime& rhs) const
if (isNegativeInfinite() || rhs.isNegativeInfinite())
return negativeInfiniteTime();
- int32_t commonTimeScale;
- if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
- commonTimeScale = MaximumTimeScale;
+ if (hasDoubleValue() && rhs.hasDoubleValue())
+ return MediaTime::createWithDouble(m_timeValueAsDouble + rhs.m_timeValueAsDouble);
+
MediaTime a = *this;
MediaTime b = rhs;
+
+ if (a.hasDoubleValue())
+ a.setTimeScale(DefaultTimeScale);
+ else if (b.hasDoubleValue())
+ b.setTimeScale(DefaultTimeScale);
+
+ 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)) {
@@ -201,11 +248,20 @@ MediaTime MediaTime::operator-(const MediaTime& rhs) const
if (isNegativeInfinite() || rhs.isPositiveInfinite())
return negativeInfiniteTime();
- int32_t commonTimeScale;
- if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
- commonTimeScale = MaximumTimeScale;
+ if (hasDoubleValue() && rhs.hasDoubleValue())
+ return MediaTime::createWithDouble(m_timeValueAsDouble - rhs.m_timeValueAsDouble);
+
MediaTime a = *this;
MediaTime b = rhs;
+
+ if (a.hasDoubleValue())
+ a.setTimeScale(DefaultTimeScale);
+ else if (b.hasDoubleValue())
+ b.setTimeScale(DefaultTimeScale);
+
+ 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)) {
@@ -218,6 +274,28 @@ MediaTime MediaTime::operator-(const MediaTime& rhs) const
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())
@@ -243,6 +321,11 @@ MediaTime MediaTime::operator*(int32_t rhs) const
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();
@@ -252,61 +335,86 @@ MediaTime MediaTime::operator*(int32_t rhs) const
return a;
}
-bool MediaTime::operator<(const MediaTime& rhs) const
+bool MediaTime::operator!() const
{
- return compare(rhs) == LessThan;
+ return (m_timeFlags == Valid && !m_timeValue)
+ || (m_timeFlags == (Valid | DoubleValue) && !m_timeValueAsDouble);
}
-bool MediaTime::operator>(const MediaTime& rhs) const
+MediaTime::operator bool() const
{
- return compare(rhs) == GreaterThan;
+ return !(m_timeFlags == Valid && !m_timeValue)
+ && !(m_timeFlags == (Valid | DoubleValue) && !m_timeValueAsDouble);
}
-bool MediaTime::operator!=(const MediaTime& rhs) const
+MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs) const
{
- return compare(rhs) != EqualTo;
-}
+ auto andFlags = m_timeFlags & rhs.m_timeFlags;
+ if (andFlags & (PositiveInfinite | NegativeInfinite | Indefinite))
+ return EqualTo;
-bool MediaTime::operator==(const MediaTime& rhs) const
-{
- return compare(rhs) == EqualTo;
-}
+ auto orFlags = m_timeFlags | rhs.m_timeFlags;
+ if (!(orFlags & Valid))
+ return EqualTo;
-bool MediaTime::operator>=(const MediaTime& rhs) const
-{
- return compare(rhs) >= EqualTo;
-}
+ if (!(andFlags & Valid))
+ return isInvalid() ? GreaterThan : LessThan;
-bool MediaTime::operator<=(const MediaTime& rhs) const
-{
- return compare(rhs) <= EqualTo;
-}
+ if (orFlags & NegativeInfinite)
+ return isNegativeInfinite() ? LessThan : GreaterThan;
-MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs) const
-{
- if ((isPositiveInfinite() && rhs.isPositiveInfinite())
- || (isNegativeInfinite() && rhs.isNegativeInfinite())
- || (isInvalid() && rhs.isInvalid())
- || (isIndefinite() && rhs.isIndefinite()))
+ 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 (isInvalid())
- return GreaterThan;
+ if ((m_timeValue < 0) != (rhs.m_timeValue < 0))
+ return m_timeValue < 0 ? LessThan : GreaterThan;
- if (rhs.isInvalid())
- return LessThan;
+ if (!m_timeValue && !rhs.m_timeValue)
+ return EqualTo;
- if (rhs.isNegativeInfinite() || isPositiveInfinite())
- return GreaterThan;
+ if (m_timeScale == rhs.m_timeScale) {
+ if (m_timeValue == rhs.m_timeValue)
+ return EqualTo;
+ return m_timeValue < rhs.m_timeValue ? LessThan : GreaterThan;
+ }
- if (rhs.isPositiveInfinite() || isNegativeInfinite())
+ if (m_timeValue == rhs.m_timeValue)
+ return m_timeScale < rhs.m_timeScale ? GreaterThan : LessThan;
+
+ if (m_timeValue < rhs.m_timeValue && m_timeScale > rhs.m_timeScale)
return LessThan;
- if (isIndefinite())
+ if (m_timeValue > rhs.m_timeValue && m_timeScale < rhs.m_timeScale)
return GreaterThan;
- if (rhs.isIndefinite())
- return LessThan;
+ 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;
@@ -317,14 +425,21 @@ MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs) const
int64_t rhsRemain = rhs.m_timeValue % rhs.m_timeScale;
int64_t lhsRemain = m_timeValue % m_timeScale;
- int64_t lhsFactor = lhsRemain * rhs.m_timeScale;
- int64_t rhsFactor = rhsRemain * 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 = new MediaTime(0, 1, Valid);
@@ -355,8 +470,13 @@ const MediaTime& MediaTime::indefiniteTime()
return *time;
}
-void MediaTime::setTimeScale(int32_t timeScale)
+void MediaTime::setTimeScale(uint32_t timeScale)
{
+ if (hasDoubleValue()) {
+ *this = MediaTime::createWithDouble(m_timeValueAsDouble, timeScale);
+ return;
+ }
+
if (timeScale == m_timeScale)
return;
timeScale = std::min(MaximumTimeScale, timeScale);
@@ -366,7 +486,7 @@ void MediaTime::setTimeScale(int32_t timeScale)
// timescale by two until the number will fit, and round the
// result.
int64_t newWholePart;
- while (!safeMultiply(wholePart, timeScale, newWholePart))
+ while (!safeMultiply(wholePart, static_cast<int64_t>(timeScale), newWholePart))
timeScale /= 2;
int64_t remainder = m_timeValue % m_timeScale;
@@ -374,14 +494,25 @@ void MediaTime::setTimeScale(int32_t timeScale)
m_timeScale = timeScale;
}
+void MediaTime::dump(PrintStream& out) const
+{
+ out.print("{");
+ if (!hasDoubleValue())
+ out.print(m_timeValue, "/", m_timeScale, " = ");
+ out.print(toDouble(), "}");
+}
+
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 *= signum(rhs.m_timeScale) * signum(rhs.m_timeValue);
+ val.m_timeValue = std::abs(rhs.m_timeValue);
return val;
}