A MediaTime timescale must never be zero
[WebKit-https.git] / Source / WTF / wtf / MediaTime.cpp
1 /*
2  * Copyright (C) 2012-2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include <wtf/MediaTime.h>
31
32 #include <algorithm>
33 #include <cstdlib>
34 #include <wtf/Assertions.h>
35 #include <wtf/CheckedArithmetic.h>
36 #include <wtf/JSONValues.h>
37 #include <wtf/MathExtras.h>
38 #include <wtf/PrintStream.h>
39 #include <wtf/text/StringBuilder.h>
40
41 namespace WTF {
42
43 static uint32_t greatestCommonDivisor(uint32_t a, uint32_t b)
44 {
45     ASSERT(a);
46     ASSERT(b);
47
48     // Euclid's Algorithm
49     uint32_t temp = 0;
50     while (b) {
51         temp = b;
52         b = a % b;
53         a = temp;
54     }
55
56     ASSERT(a);
57     return a;
58 }
59
60 static uint32_t leastCommonMultiple(uint32_t a, uint32_t b, uint32_t &result)
61 {
62     return safeMultiply(a, b / greatestCommonDivisor(a, b), result);
63 }
64
65 static int64_t signum(int64_t val)
66 {
67     return (0 < val) - (val < 0);
68 }
69
70 const uint32_t MediaTime::MaximumTimeScale = 1000000000;
71
72 MediaTime::MediaTime()
73     : m_timeValue(0)
74     , m_timeScale(DefaultTimeScale)
75     , m_timeFlags(Valid)
76 {
77 }
78
79 MediaTime::MediaTime(int64_t value, uint32_t scale, uint8_t flags)
80     : m_timeValue(value)
81     , m_timeScale(scale)
82     , m_timeFlags(flags)
83 {
84     if (scale || isInvalid())
85         return;
86
87     *this = value < 0 ? negativeInfiniteTime() : positiveInfiniteTime();
88 }
89
90 MediaTime::~MediaTime()
91 {
92 }
93
94 MediaTime::MediaTime(const MediaTime& rhs)
95 {
96     *this = rhs;
97 }
98
99 MediaTime MediaTime::createWithFloat(float floatTime)
100 {
101     if (floatTime != floatTime)
102         return invalidTime();
103     if (std::isinf(floatTime))
104         return std::signbit(floatTime) ? negativeInfiniteTime() : positiveInfiniteTime();
105
106     MediaTime value(0, DefaultTimeScale, Valid | DoubleValue);
107     value.m_timeValueAsDouble = floatTime;
108     return value;
109 }
110
111 MediaTime MediaTime::createWithFloat(float floatTime, uint32_t timeScale)
112 {
113     if (floatTime != floatTime)
114         return invalidTime();
115     if (std::isinf(floatTime))
116         return std::signbit(floatTime) ? negativeInfiniteTime() : positiveInfiniteTime();
117     if (floatTime > std::numeric_limits<int64_t>::max())
118         return positiveInfiniteTime();
119     if (floatTime < std::numeric_limits<int64_t>::min())
120         return negativeInfiniteTime();
121     if (!timeScale)
122         return std::signbit(floatTime) ? negativeInfiniteTime() : positiveInfiniteTime();
123
124     while (floatTime * timeScale > std::numeric_limits<int64_t>::max())
125         timeScale /= 2;
126     return MediaTime(static_cast<int64_t>(floatTime * timeScale), timeScale, Valid);
127 }
128
129 MediaTime MediaTime::createWithDouble(double doubleTime)
130 {
131     if (doubleTime != doubleTime)
132         return invalidTime();
133     if (std::isinf(doubleTime))
134         return std::signbit(doubleTime) ? negativeInfiniteTime() : positiveInfiniteTime();
135
136     MediaTime value(0, DefaultTimeScale, Valid | DoubleValue);
137     value.m_timeValueAsDouble = doubleTime;
138     return value;
139 }
140
141 MediaTime MediaTime::createWithDouble(double doubleTime, uint32_t timeScale)
142 {
143     if (doubleTime != doubleTime)
144         return invalidTime();
145     if (std::isinf(doubleTime))
146         return std::signbit(doubleTime) ? negativeInfiniteTime() : positiveInfiniteTime();
147     if (doubleTime > std::numeric_limits<int64_t>::max())
148         return positiveInfiniteTime();
149     if (doubleTime < std::numeric_limits<int64_t>::min())
150         return negativeInfiniteTime();
151     if (!timeScale)
152         return std::signbit(doubleTime) ? negativeInfiniteTime() : positiveInfiniteTime();
153
154     while (doubleTime * timeScale > std::numeric_limits<int64_t>::max())
155         timeScale /= 2;
156     return MediaTime(static_cast<int64_t>(std::round(doubleTime * timeScale)), timeScale, Valid);
157 }
158
159 float MediaTime::toFloat() const
160 {
161     if (isInvalid() || isIndefinite())
162         return std::numeric_limits<float>::quiet_NaN();
163     if (isPositiveInfinite())
164         return std::numeric_limits<float>::infinity();
165     if (isNegativeInfinite())
166         return -std::numeric_limits<float>::infinity();
167     if (hasDoubleValue())
168         return m_timeValueAsDouble;
169     return static_cast<float>(m_timeValue) / m_timeScale;
170 }
171
172 double MediaTime::toDouble() const
173 {
174     if (isInvalid() || isIndefinite())
175         return std::numeric_limits<double>::quiet_NaN();
176     if (isPositiveInfinite())
177         return std::numeric_limits<double>::infinity();
178     if (isNegativeInfinite())
179         return -std::numeric_limits<double>::infinity();
180     if (hasDoubleValue())
181         return m_timeValueAsDouble;
182     return static_cast<double>(m_timeValue) / m_timeScale;
183 }
184
185 MediaTime& MediaTime::operator=(const MediaTime& rhs)
186 {
187     m_timeValue = rhs.m_timeValue;
188     m_timeScale = rhs.m_timeScale;
189     m_timeFlags = rhs.m_timeFlags;
190     return *this;
191 }
192
193 MediaTime MediaTime::operator+(const MediaTime& rhs) const
194 {
195     if (rhs.isInvalid() || isInvalid())
196         return invalidTime();
197
198     if (rhs.isIndefinite() || isIndefinite())
199         return indefiniteTime();
200
201     if (isPositiveInfinite() && rhs.isNegativeInfinite())
202         return invalidTime();
203
204     if (isNegativeInfinite() && rhs.isPositiveInfinite())
205         return invalidTime();
206
207     if (isPositiveInfinite() || rhs.isPositiveInfinite())
208         return positiveInfiniteTime();
209
210     if (isNegativeInfinite() || rhs.isNegativeInfinite())
211         return negativeInfiniteTime();
212
213     if (hasDoubleValue() && rhs.hasDoubleValue())
214         return MediaTime::createWithDouble(m_timeValueAsDouble + rhs.m_timeValueAsDouble);
215
216     if (hasDoubleValue() || rhs.hasDoubleValue())
217         return MediaTime::createWithDouble(toDouble() + rhs.toDouble());
218
219     MediaTime a = *this;
220     MediaTime b = rhs;
221
222     uint32_t commonTimeScale;
223     if (!leastCommonMultiple(a.m_timeScale, b.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
224         commonTimeScale = MaximumTimeScale;
225     a.setTimeScale(commonTimeScale);
226     b.setTimeScale(commonTimeScale);
227     while (!safeAdd(a.m_timeValue, b.m_timeValue, a.m_timeValue)) {
228         if (commonTimeScale == 1)
229             return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime();
230         commonTimeScale /= 2;
231         a.setTimeScale(commonTimeScale);
232         b.setTimeScale(commonTimeScale);
233     }
234     return a;
235 }
236
237 MediaTime MediaTime::operator-(const MediaTime& rhs) const
238 {
239     if (rhs.isInvalid() || isInvalid())
240         return invalidTime();
241
242     if (rhs.isIndefinite() || isIndefinite())
243         return indefiniteTime();
244
245     if (isPositiveInfinite() && rhs.isPositiveInfinite())
246         return invalidTime();
247
248     if (isNegativeInfinite() && rhs.isNegativeInfinite())
249         return invalidTime();
250
251     if (isPositiveInfinite() || rhs.isNegativeInfinite())
252         return positiveInfiniteTime();
253
254     if (isNegativeInfinite() || rhs.isPositiveInfinite())
255         return negativeInfiniteTime();
256
257     if (hasDoubleValue() && rhs.hasDoubleValue())
258         return MediaTime::createWithDouble(m_timeValueAsDouble - rhs.m_timeValueAsDouble);
259
260     if (hasDoubleValue() || rhs.hasDoubleValue())
261         return MediaTime::createWithDouble(toDouble() - rhs.toDouble());
262
263     MediaTime a = *this;
264     MediaTime b = rhs;
265
266     uint32_t commonTimeScale;
267     if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
268         commonTimeScale = MaximumTimeScale;
269     a.setTimeScale(commonTimeScale);
270     b.setTimeScale(commonTimeScale);
271     while (!safeSub(a.m_timeValue, b.m_timeValue, a.m_timeValue)) {
272         if (commonTimeScale == 1)
273             return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime();
274         commonTimeScale /= 2;
275         a.setTimeScale(commonTimeScale);
276         b.setTimeScale(commonTimeScale);
277     }
278     return a;
279 }
280
281 MediaTime MediaTime::operator-() const
282 {
283     if (isInvalid())
284         return invalidTime();
285
286     if (isIndefinite())
287         return indefiniteTime();
288
289     if (isPositiveInfinite())
290         return negativeInfiniteTime();
291
292     if (isNegativeInfinite())
293         return positiveInfiniteTime();
294
295     MediaTime negativeTime = *this;
296     if (negativeTime.hasDoubleValue())
297         negativeTime.m_timeValueAsDouble = -negativeTime.m_timeValueAsDouble;
298     else
299         negativeTime.m_timeValue = -negativeTime.m_timeValue;
300     return negativeTime;
301 }
302
303 MediaTime MediaTime::operator*(int32_t rhs) const
304 {
305     if (isInvalid())
306         return invalidTime();
307
308     if (isIndefinite())
309         return indefiniteTime();
310
311     if (!rhs)
312         return zeroTime();
313
314     if (isPositiveInfinite()) {
315         if (rhs > 0)
316             return positiveInfiniteTime();
317         return negativeInfiniteTime();
318     }
319
320     if (isNegativeInfinite()) {
321         if (rhs > 0)
322             return negativeInfiniteTime();
323         return positiveInfiniteTime();
324     }
325
326     MediaTime a = *this;
327
328     if (a.hasDoubleValue()) {
329         a.m_timeValueAsDouble *= rhs;
330         return a;
331     }
332
333     while (!safeMultiply(a.m_timeValue, rhs, a.m_timeValue)) {
334         if (a.m_timeScale == 1)
335             return signum(a.m_timeValue) == signum(rhs) ? positiveInfiniteTime() : negativeInfiniteTime();
336         a.setTimeScale(a.m_timeScale / 2);
337     }
338
339     return a;
340 }
341
342 bool MediaTime::operator!() const
343 {
344     return (m_timeFlags == Valid && !m_timeValue)
345         || (m_timeFlags == (Valid | DoubleValue) && !m_timeValueAsDouble)
346         || isInvalid();
347 }
348
349 MediaTime::operator bool() const
350 {
351     return !(m_timeFlags == Valid && !m_timeValue)
352         && !(m_timeFlags == (Valid | DoubleValue) && !m_timeValueAsDouble)
353         && !isInvalid();
354 }
355
356 MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs) const
357 {
358     auto andFlags = m_timeFlags & rhs.m_timeFlags;
359     if (andFlags & (PositiveInfinite | NegativeInfinite | Indefinite))
360         return EqualTo;
361
362     auto orFlags = m_timeFlags | rhs.m_timeFlags;
363     if (!(orFlags & Valid))
364         return EqualTo;
365
366     if (!(andFlags & Valid))
367         return isInvalid() ? GreaterThan : LessThan;
368
369     if (orFlags & NegativeInfinite)
370         return isNegativeInfinite() ? LessThan : GreaterThan;
371
372     if (orFlags & PositiveInfinite)
373         return isPositiveInfinite() ? GreaterThan : LessThan;
374
375     if (orFlags & Indefinite)
376         return isIndefinite() ? GreaterThan : LessThan;
377
378     if (andFlags & DoubleValue) {
379         if (m_timeValueAsDouble == rhs.m_timeValueAsDouble)
380             return EqualTo;
381
382         return m_timeValueAsDouble < rhs.m_timeValueAsDouble ? LessThan : GreaterThan;
383     }
384
385     if (orFlags & DoubleValue) {
386         double a = toDouble();
387         double b = rhs.toDouble();
388         if (a > b)
389             return GreaterThan;
390         if (a < b)
391             return LessThan;
392         return EqualTo;
393     }
394
395     if ((m_timeValue < 0) != (rhs.m_timeValue < 0))
396         return m_timeValue < 0 ? LessThan : GreaterThan;
397
398     if (!m_timeValue && !rhs.m_timeValue)
399         return EqualTo;
400
401     if (m_timeScale == rhs.m_timeScale) {
402         if (m_timeValue == rhs.m_timeValue)
403             return EqualTo;
404         return m_timeValue < rhs.m_timeValue ? LessThan : GreaterThan;
405     }
406
407     if (m_timeValue == rhs.m_timeValue)
408         return m_timeScale < rhs.m_timeScale ? GreaterThan : LessThan;
409
410     if (m_timeValue >= 0) {
411         if (m_timeValue < rhs.m_timeValue && m_timeScale > rhs.m_timeScale)
412             return LessThan;
413
414         if (m_timeValue > rhs.m_timeValue && m_timeScale < rhs.m_timeScale)
415             return GreaterThan;
416     } else {
417         if (m_timeValue < rhs.m_timeValue && m_timeScale < rhs.m_timeScale)
418             return LessThan;
419
420         if (m_timeValue > rhs.m_timeValue && m_timeScale > rhs.m_timeScale)
421             return GreaterThan;
422     }
423
424     int64_t lhsFactor;
425     int64_t rhsFactor;
426     if (safeMultiply(m_timeValue, static_cast<int64_t>(rhs.m_timeScale), lhsFactor)
427         && safeMultiply(rhs.m_timeValue, static_cast<int64_t>(m_timeScale), rhsFactor)) {
428         if (lhsFactor == rhsFactor)
429             return EqualTo;
430         return lhsFactor < rhsFactor ? LessThan : GreaterThan;
431     }
432
433     int64_t rhsWhole = rhs.m_timeValue / rhs.m_timeScale;
434     int64_t lhsWhole = m_timeValue / m_timeScale;
435     if (lhsWhole > rhsWhole)
436         return GreaterThan;
437     if (lhsWhole < rhsWhole)
438         return LessThan;
439
440     int64_t rhsRemain = rhs.m_timeValue % rhs.m_timeScale;
441     int64_t lhsRemain = m_timeValue % m_timeScale;
442     lhsFactor = lhsRemain * rhs.m_timeScale;
443     rhsFactor = rhsRemain * m_timeScale;
444
445     if (lhsFactor == rhsFactor)
446         return EqualTo;
447     return lhsFactor > rhsFactor ? GreaterThan : LessThan;
448 }
449
450 bool MediaTime::isBetween(const MediaTime& a, const MediaTime& b) const
451 {
452     if (a > b)
453         return *this > b && *this < a;
454     return *this > a && *this < b;
455 }
456
457 const MediaTime& MediaTime::zeroTime()
458 {
459     static const MediaTime* time = new MediaTime(0, 1, Valid);
460     return *time;
461 }
462
463 const MediaTime& MediaTime::invalidTime()
464 {
465     static const MediaTime* time = new MediaTime(-1, 1, 0);
466     return *time;
467 }
468
469 const MediaTime& MediaTime::positiveInfiniteTime()
470 {
471     static const MediaTime* time = new MediaTime(0, 1, PositiveInfinite | Valid);
472     return *time;
473 }
474
475 const MediaTime& MediaTime::negativeInfiniteTime()
476 {
477     static const MediaTime* time = new MediaTime(-1, 1, NegativeInfinite | Valid);
478     return *time;
479 }
480
481 const MediaTime& MediaTime::indefiniteTime()
482 {
483     static const MediaTime* time = new MediaTime(0, 1, Indefinite | Valid);
484     return *time;
485 }
486
487 MediaTime MediaTime::toTimeScale(uint32_t timeScale, RoundingFlags flags) const
488 {
489     MediaTime result = *this;
490     result.setTimeScale(timeScale, flags);
491     return result;
492 }
493
494 void MediaTime::setTimeScale(uint32_t timeScale, RoundingFlags flags)
495 {
496     if (hasDoubleValue()) {
497         *this = MediaTime::createWithDouble(m_timeValueAsDouble, timeScale);
498         return;
499     }
500
501     if (!timeScale) {
502         *this = m_timeValue < 0 ? negativeInfiniteTime() : positiveInfiniteTime();
503         return;
504     }
505
506     if (timeScale == m_timeScale)
507         return;
508
509     timeScale = std::min(MaximumTimeScale, timeScale);
510
511 #if HAVE(INT128_T)
512     __int128_t newValue = static_cast<__int128_t>(m_timeValue) * timeScale;
513     int64_t remainder = newValue % m_timeScale;
514     newValue = newValue / m_timeScale;
515
516     if (newValue < std::numeric_limits<int64_t>::min()) {
517         *this = negativeInfiniteTime();
518         return;
519     }
520
521     if (newValue > std::numeric_limits<int64_t>::max()) {
522         *this = positiveInfiniteTime();
523         return;
524     }
525 #else
526     int64_t newValue = m_timeValue / m_timeScale;
527     int64_t partialRemainder = (m_timeValue % m_timeScale) * timeScale;
528     int64_t remainder = partialRemainder % m_timeScale;
529
530     if (!safeMultiply<int64_t>(newValue, static_cast<int64_t>(timeScale), newValue)
531         || !safeAdd(newValue, partialRemainder / m_timeScale, newValue)) {
532         *this = newValue < 0 ? negativeInfiniteTime() : positiveInfiniteTime();
533         return;
534     }
535 #endif
536
537     m_timeValue = newValue;
538     std::swap(m_timeScale, timeScale);
539
540     if (!remainder)
541         return;
542
543     m_timeFlags |= HasBeenRounded;
544     switch (flags) {
545     case RoundingFlags::HalfAwayFromZero:
546         if (static_cast<int64_t>(llabs(remainder)) * 2 >= static_cast<int64_t>(timeScale)) {
547             // round up (away from zero)
548             if (remainder < 0)
549                 m_timeValue--;
550             else
551                 m_timeValue++;
552         }
553         break;
554
555     case RoundingFlags::TowardZero:
556         break;
557
558     case RoundingFlags::AwayFromZero:
559         if (remainder < 0)
560             m_timeValue--;
561         else
562             m_timeValue++;
563         break;
564
565     case RoundingFlags::TowardPositiveInfinity:
566         if (remainder > 0)
567             m_timeValue++;
568         break;
569         
570     case RoundingFlags::TowardNegativeInfinity:
571         if (remainder < 0)
572             m_timeValue--;
573         break;
574     }
575 }
576
577 void MediaTime::dump(PrintStream& out) const
578 {
579     out.print("{");
580     if (!hasDoubleValue())
581         out.print(m_timeValue, "/", m_timeScale, " = ");
582     out.print(toDouble(), "}");
583 }
584
585 String MediaTime::toString() const
586 {
587     StringBuilder builder;
588
589     builder.append('{');
590     if (!hasDoubleValue()) {
591         builder.appendNumber(m_timeValue);
592         builder.append('/');
593         builder.appendNumber(m_timeScale);
594         builder.appendLiteral(" = ");
595     }
596     builder.appendNumber(toDouble());
597     builder.append('}');
598     return builder.toString();
599 }
600
601 static Ref<JSON::Object> toJSONStringInternal(const MediaTime& time)
602 {
603     auto object = JSON::Object::create();
604
605     if (time.hasDoubleValue())
606         object->setDouble("value"_s, time.toDouble());
607     else {
608         if (time.isInvalid() || time.isIndefinite())
609             object->setString("value"_s, "NaN"_s);
610         else if (time.isPositiveInfinite())
611             object->setString("value"_s, "POSITIVE_INFINITY"_s);
612         else if (time.isNegativeInfinite())
613             object->setString("value"_s, "NEGATIVE_INFINITY"_s);
614         else
615             object->setDouble("value"_s, time.toDouble());
616
617         object->setInteger("numerator"_s, static_cast<int>(time.timeValue()));
618         object->setInteger("denominator"_s, time.timeScale());
619         object->setInteger("flags"_s, time.timeFlags());
620     }
621
622     return object;
623 }
624
625 String MediaTime::toJSONString() const
626 {
627     return toJSONStringInternal(*this)->toJSONString();
628 }
629
630 MediaTime abs(const MediaTime& rhs)
631 {
632     if (rhs.isInvalid())
633         return MediaTime::invalidTime();
634     if (rhs.isNegativeInfinite() || rhs.isPositiveInfinite())
635         return MediaTime::positiveInfiniteTime();
636     if (rhs.hasDoubleValue())
637         return MediaTime::createWithDouble(fabs(rhs.m_timeValueAsDouble));
638
639     MediaTime val = rhs;
640     val.m_timeValue = std::abs(rhs.m_timeValue);
641     return val;
642 }
643
644 String MediaTimeRange::toJSONString() const
645 {
646     auto object = JSON::Object::create();
647
648     object->setObject("start"_s, toJSONStringInternal(start));
649     object->setObject("end"_s, toJSONStringInternal(end));
650
651     return object->toJSONString();
652 }
653
654 }