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
41namespace WTF {
42
43static 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
60static uint32_t leastCommonMultiple(uint32_t a, uint32_t b, uint32_t &result)
61{
62 return safeMultiply(a, b / greatestCommonDivisor(a, b), result);
63}
64
65static int64_t signum(int64_t val)
66{
67 return (0 < val) - (val < 0);
68}
69
70const uint32_t MediaTime::MaximumTimeScale = 1000000000;
71
72MediaTime::MediaTime()
73 : m_timeValue(0)
74 , m_timeScale(DefaultTimeScale)
75 , m_timeFlags(Valid)
76{
77}
78
79MediaTime::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
90MediaTime::~MediaTime()
91{
92}
93
94MediaTime::MediaTime(const MediaTime& rhs)
95{
96 *this = rhs;
97}
98
99MediaTime 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
111MediaTime 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
129MediaTime 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
141MediaTime 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
159float 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
172double 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
185MediaTime& 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
193MediaTime 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
237MediaTime 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
281MediaTime 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
303MediaTime 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
342bool MediaTime::operator!() const
343{
344 return (m_timeFlags == Valid && !m_timeValue)
345 || (m_timeFlags == (Valid | DoubleValue) && !m_timeValueAsDouble)
346 || isInvalid();
347}
348
349MediaTime::operator bool() const
350{
351 return !(m_timeFlags == Valid && !m_timeValue)
352 && !(m_timeFlags == (Valid | DoubleValue) && !m_timeValueAsDouble)
353 && !isInvalid();
354}
355
356MediaTime::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
450bool 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
457const MediaTime& MediaTime::zeroTime()
458{
459 static const MediaTime* time = new MediaTime(0, 1, Valid);
460 return *time;
461}
462
463const MediaTime& MediaTime::invalidTime()
464{
465 static const MediaTime* time = new MediaTime(-1, 1, 0);
466 return *time;
467}
468
469const MediaTime& MediaTime::positiveInfiniteTime()
470{
471 static const MediaTime* time = new MediaTime(0, 1, PositiveInfinite | Valid);
472 return *time;
473}
474
475const MediaTime& MediaTime::negativeInfiniteTime()
476{
477 static const MediaTime* time = new MediaTime(-1, 1, NegativeInfinite | Valid);
478 return *time;
479}
480
481const MediaTime& MediaTime::indefiniteTime()
482{
483 static const MediaTime* time = new MediaTime(0, 1, Indefinite | Valid);
484 return *time;
485}
486
487MediaTime MediaTime::toTimeScale(uint32_t timeScale, RoundingFlags flags) const
488{
489 MediaTime result = *this;
490 result.setTimeScale(timeScale, flags);
491 return result;
492}
493
494void 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
577void 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
585String 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.appendFixedPrecisionNumber(toDouble());
597 if (isInvalid())
598 builder.appendLiteral(", invalid");
599 builder.append('}');
600 return builder.toString();
601}
602
603Ref<JSON::Object> MediaTime::toJSONObject() const
604{
605 auto object = JSON::Object::create();
606
607 if (hasDoubleValue()) {
608 object->setDouble("value"_s, toDouble());
609 return object;
610 }
611
612 if (isInvalid())
613 object->setBoolean("invalid"_s, true);
614 else if (isIndefinite())
615 object->setString("value"_s, "NaN"_s);
616 else if (isPositiveInfinite())
617 object->setString("value"_s, "POSITIVE_INFINITY"_s);
618 else if (isNegativeInfinite())
619 object->setString("value"_s, "NEGATIVE_INFINITY"_s);
620 else
621 object->setDouble("value"_s, toDouble());
622
623 object->setDouble("numerator"_s, static_cast<double>(m_timeValue));
624 object->setInteger("denominator"_s, m_timeScale);
625 object->setInteger("flags"_s, m_timeFlags);
626
627 return object;
628}
629
630String MediaTime::toJSONString() const
631{
632 return toJSONObject()->toJSONString();
633}
634
635MediaTime abs(const MediaTime& rhs)
636{
637 if (rhs.isInvalid())
638 return MediaTime::invalidTime();
639 if (rhs.isNegativeInfinite() || rhs.isPositiveInfinite())
640 return MediaTime::positiveInfiniteTime();
641 if (rhs.hasDoubleValue())
642 return MediaTime::createWithDouble(fabs(rhs.m_timeValueAsDouble));
643
644 MediaTime val = rhs;
645 val.m_timeValue = std::abs(rhs.m_timeValue);
646 return val;
647}
648
649String MediaTimeRange::toJSONString() const
650{
651 auto object = JSON::Object::create();
652
653 object->setObject("start"_s, start.toJSONObject());
654 object->setObject("end"_s, end.toJSONObject());
655
656 return object->toJSONString();
657}
658
659}
660