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