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