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 "MediaTime.h"
31
32#include <algorithm>
33#include <wtf/CheckedArithmetic.h>
34#include <wtf/MathExtras.h>
35#include <wtf/PrintStream.h>
36
37namespace WTF {
38
39static int32_t greatestCommonDivisor(int32_t a, int32_t b)
40{
41    // Euclid's Algorithm
42    int32_t temp = 0;
43    while (b) {
44        temp = b;
45        b = a % b;
46        a = temp;
47    }
48    return a;
49}
50
51static int32_t leastCommonMultiple(int32_t a, int32_t b, int32_t &result)
52{
53    return safeMultiply(a, b / greatestCommonDivisor(a, b), result);
54}
55
56static int32_t signum(int64_t val)
57{
58    return (0 < val) - (val < 0);
59}
60
61const int32_t MediaTime::MaximumTimeScale = 0x7fffffffL;
62
63MediaTime::MediaTime()
64    : m_timeValue(0)
65    , m_timeScale(DefaultTimeScale)
66    , m_timeFlags(Valid)
67{
68}
69
70MediaTime::MediaTime(int64_t value, int32_t scale, uint32_t flags)
71    : m_timeValue(value)
72    , m_timeScale(scale)
73    , m_timeFlags(flags)
74{
75}
76
77MediaTime::~MediaTime()
78{
79}
80
81MediaTime::MediaTime(const MediaTime& rhs)
82{
83    *this = rhs;
84}
85
86MediaTime MediaTime::createWithFloat(float floatTime, int32_t timeScale)
87{
88    if (floatTime != floatTime)
89        return invalidTime();
90    if (std::isinf(floatTime))
91        return std::signbit(floatTime) ? negativeInfiniteTime() : positiveInfiniteTime();
92    if (floatTime > std::numeric_limits<int64_t>::max())
93        return positiveInfiniteTime();
94    if (floatTime < std::numeric_limits<int64_t>::min())
95        return negativeInfiniteTime();
96
97    while (floatTime * timeScale > std::numeric_limits<int64_t>::max())
98        timeScale /= 2;
99    return MediaTime(static_cast<int64_t>(floatTime * timeScale), timeScale, Valid);
100}
101
102MediaTime MediaTime::createWithDouble(double doubleTime, int32_t timeScale)
103{
104    if (doubleTime != doubleTime)
105        return invalidTime();
106    if (std::isinf(doubleTime))
107        return std::signbit(doubleTime) ? negativeInfiniteTime() : positiveInfiniteTime();
108    if (doubleTime > std::numeric_limits<int64_t>::max())
109        return positiveInfiniteTime();
110    if (doubleTime < std::numeric_limits<int64_t>::min())
111        return negativeInfiniteTime();
112
113    while (doubleTime * timeScale > std::numeric_limits<int64_t>::max())
114        timeScale /= 2;
115    return MediaTime(static_cast<int64_t>(doubleTime * timeScale), timeScale, Valid);
116}
117
118float MediaTime::toFloat() const
119{
120    if (isInvalid() || isIndefinite())
121        return std::numeric_limits<float>::quiet_NaN();
122    if (isPositiveInfinite())
123        return std::numeric_limits<float>::infinity();
124    if (isNegativeInfinite())
125        return -std::numeric_limits<float>::infinity();
126    return static_cast<float>(m_timeValue) / m_timeScale;
127}
128
129double MediaTime::toDouble() const
130{
131    if (isInvalid() || isIndefinite())
132        return std::numeric_limits<double>::quiet_NaN();
133    if (isPositiveInfinite())
134        return std::numeric_limits<double>::infinity();
135    if (isNegativeInfinite())
136        return -std::numeric_limits<double>::infinity();
137    return static_cast<double>(m_timeValue) / m_timeScale;
138}
139
140MediaTime& MediaTime::operator=(const MediaTime& rhs)
141{
142    m_timeValue = rhs.m_timeValue;
143    m_timeScale = rhs.m_timeScale;
144    m_timeFlags = rhs.m_timeFlags;
145    return *this;
146}
147
148MediaTime MediaTime::operator+(const MediaTime& rhs) const
149{
150    if (rhs.isInvalid() || isInvalid())
151        return invalidTime();
152
153    if (rhs.isIndefinite() || isIndefinite())
154        return indefiniteTime();
155
156    if (isPositiveInfinite() && rhs.isNegativeInfinite())
157        return invalidTime();
158
159    if (isNegativeInfinite() && rhs.isPositiveInfinite())
160        return invalidTime();
161
162    if (isPositiveInfinite() || rhs.isPositiveInfinite())
163        return positiveInfiniteTime();
164
165    if (isNegativeInfinite() || rhs.isNegativeInfinite())
166        return negativeInfiniteTime();
167
168    int32_t commonTimeScale;
169    if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
170        commonTimeScale = MaximumTimeScale;
171    MediaTime a = *this;
172    MediaTime b = rhs;
173    a.setTimeScale(commonTimeScale);
174    b.setTimeScale(commonTimeScale);
175    while (!safeAdd(a.m_timeValue, b.m_timeValue, a.m_timeValue)) {
176        if (commonTimeScale == 1)
177            return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime();
178        commonTimeScale /= 2;
179        a.setTimeScale(commonTimeScale);
180        b.setTimeScale(commonTimeScale);
181    }
182    return a;
183}
184
185MediaTime MediaTime::operator-(const MediaTime& rhs) const
186{
187    if (rhs.isInvalid() || isInvalid())
188        return invalidTime();
189
190    if (rhs.isIndefinite() || isIndefinite())
191        return indefiniteTime();
192
193    if (isPositiveInfinite() && rhs.isPositiveInfinite())
194        return invalidTime();
195
196    if (isNegativeInfinite() && rhs.isNegativeInfinite())
197        return invalidTime();
198
199    if (isPositiveInfinite() || rhs.isNegativeInfinite())
200        return positiveInfiniteTime();
201
202    if (isNegativeInfinite() || rhs.isPositiveInfinite())
203        return negativeInfiniteTime();
204
205    int32_t commonTimeScale;
206    if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
207        commonTimeScale = MaximumTimeScale;
208    MediaTime a = *this;
209    MediaTime b = rhs;
210    a.setTimeScale(commonTimeScale);
211    b.setTimeScale(commonTimeScale);
212    while (!safeSub(a.m_timeValue, b.m_timeValue, a.m_timeValue)) {
213        if (commonTimeScale == 1)
214            return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime();
215        commonTimeScale /= 2;
216        a.setTimeScale(commonTimeScale);
217        b.setTimeScale(commonTimeScale);
218    }
219    return a;
220}
221
222MediaTime MediaTime::operator*(int32_t rhs) const
223{
224    if (isInvalid())
225        return invalidTime();
226
227    if (isIndefinite())
228        return indefiniteTime();
229
230    if (!rhs)
231        return zeroTime();
232
233    if (isPositiveInfinite()) {
234        if (rhs > 0)
235            return positiveInfiniteTime();
236        return negativeInfiniteTime();
237    }
238
239    if (isNegativeInfinite()) {
240        if (rhs > 0)
241            return negativeInfiniteTime();
242        return positiveInfiniteTime();
243    }
244
245    MediaTime a = *this;
246
247    while (!safeMultiply(a.m_timeValue, rhs, a.m_timeValue)) {
248        if (a.m_timeScale == 1)
249            return signum(a.m_timeValue) == signum(rhs) ? positiveInfiniteTime() : negativeInfiniteTime();
250        a.setTimeScale(a.m_timeScale / 2);
251    }
252
253    return a;
254}
255
256bool MediaTime::operator<(const MediaTime& rhs) const
257{
258    return compare(rhs) == LessThan;
259}
260
261bool MediaTime::operator>(const MediaTime& rhs) const
262{
263    return compare(rhs) == GreaterThan;
264}
265
266bool MediaTime::operator!=(const MediaTime& rhs) const
267{
268    return compare(rhs) != EqualTo;
269}
270
271bool MediaTime::operator==(const MediaTime& rhs) const
272{
273    return compare(rhs) == EqualTo;
274}
275
276bool MediaTime::operator>=(const MediaTime& rhs) const
277{
278    return compare(rhs) >= EqualTo;
279}
280
281bool MediaTime::operator<=(const MediaTime& rhs) const
282{
283    return compare(rhs) <= EqualTo;
284}
285
286MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs) const
287{
288    if ((isPositiveInfinite() && rhs.isPositiveInfinite())
289        || (isNegativeInfinite() && rhs.isNegativeInfinite())
290        || (isInvalid() && rhs.isInvalid())
291        || (isIndefinite() && rhs.isIndefinite()))
292        return EqualTo;
293
294    if (isInvalid())
295        return GreaterThan;
296
297    if (rhs.isInvalid())
298        return LessThan;
299
300    if (rhs.isNegativeInfinite() || isPositiveInfinite())
301        return GreaterThan;
302
303    if (rhs.isPositiveInfinite() || isNegativeInfinite())
304        return LessThan;
305
306    if (isIndefinite())
307        return GreaterThan;
308
309    if (rhs.isIndefinite())
310        return LessThan;
311
312    int64_t rhsWhole = rhs.m_timeValue / rhs.m_timeScale;
313    int64_t lhsWhole = m_timeValue / m_timeScale;
314    if (lhsWhole > rhsWhole)
315        return GreaterThan;
316    if (lhsWhole < rhsWhole)
317        return LessThan;
318
319    int64_t rhsRemain = rhs.m_timeValue % rhs.m_timeScale;
320    int64_t lhsRemain = m_timeValue % m_timeScale;
321    int64_t lhsFactor = lhsRemain * rhs.m_timeScale;
322    int64_t rhsFactor = rhsRemain * m_timeScale;
323
324    if (lhsFactor == rhsFactor)
325        return EqualTo;
326    return lhsFactor > rhsFactor ? GreaterThan : LessThan;
327}
328
329const MediaTime& MediaTime::zeroTime()
330{
331    static const MediaTime* time = new MediaTime(0, 1, Valid);
332    return *time;
333}
334
335const MediaTime& MediaTime::invalidTime()
336{
337    static const MediaTime* time = new MediaTime(-1, 1, 0);
338    return *time;
339}
340
341const MediaTime& MediaTime::positiveInfiniteTime()
342{
343    static const MediaTime* time = new MediaTime(0, 1, PositiveInfinite | Valid);
344    return *time;
345}
346
347const MediaTime& MediaTime::negativeInfiniteTime()
348{
349    static const MediaTime* time = new MediaTime(-1, 1, NegativeInfinite | Valid);
350    return *time;
351}
352
353const MediaTime& MediaTime::indefiniteTime()
354{
355    static const MediaTime* time = new MediaTime(0, 1, Indefinite | Valid);
356    return *time;
357}
358
359void MediaTime::setTimeScale(int32_t timeScale)
360{
361    if (timeScale == m_timeScale)
362        return;
363    timeScale = std::min(MaximumTimeScale, timeScale);
364    int64_t wholePart = m_timeValue / m_timeScale;
365
366    // If setting the time scale will cause an overflow, divide the
367    // timescale by two until the number will fit, and round the
368    // result.
369    int64_t newWholePart;
370    while (!safeMultiply(wholePart, timeScale, newWholePart))
371        timeScale /= 2;
372
373    int64_t remainder = m_timeValue % m_timeScale;
374    m_timeValue = newWholePart + (remainder * timeScale) / m_timeScale;
375    m_timeScale = timeScale;
376}
377
378void MediaTime::dump(PrintStream &out) const
379{
380    out.print("{", m_timeValue, "/", m_timeScale, ", ", toDouble(), "}");
381}
382
383MediaTime abs(const MediaTime& rhs)
384{
385    if (rhs.isInvalid())
386        return MediaTime::invalidTime();
387    if (rhs.isNegativeInfinite() || rhs.isPositiveInfinite())
388        return MediaTime::positiveInfiniteTime();
389    MediaTime val = rhs;
390    val.m_timeValue *= signum(rhs.m_timeScale) * signum(rhs.m_timeValue);
391    return val;
392}
393
394}
395
396