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