| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <limits> | |
| 6 #include <utility> | |
| 7 | |
| 8 #include "mojo/public/cpp/environment/logging.h" | |
| 9 #include "mojo/services/media/common/cpp/ratio.h" | |
| 10 | |
| 11 namespace mojo { | |
| 12 namespace media { | |
| 13 | |
| 14 namespace { | |
| 15 | |
| 16 // Calculates the greatest common denominator (factor) of two values. | |
| 17 template <typename T> | |
| 18 T BinaryGcd(T a, T b) { | |
| 19 if (a == 0) { | |
| 20 return b; | |
| 21 } | |
| 22 | |
| 23 if (b == 0) { | |
| 24 return a; | |
| 25 } | |
| 26 | |
| 27 // Remove and count the common factors of 2. | |
| 28 uint8_t twos; | |
| 29 for (twos = 0; ((a | b) & 1) == 0; ++twos) { | |
| 30 a >>= 1; | |
| 31 b >>= 1; | |
| 32 } | |
| 33 | |
| 34 // Get rid of the non-common factors of 2 in a. a is non-zero, so this | |
| 35 // terminates. | |
| 36 while ((a & 1) == 0) { | |
| 37 a >>= 1; | |
| 38 } | |
| 39 | |
| 40 do { | |
| 41 // Get rid of the non-common factors of 2 in b. b is non-zero, so this | |
| 42 // terminates. | |
| 43 while ((b & 1) == 0) { | |
| 44 b >>= 1; | |
| 45 } | |
| 46 | |
| 47 // Apply the Euclid subtraction method. | |
| 48 if (a > b) { | |
| 49 std::swap(a, b); | |
| 50 } | |
| 51 | |
| 52 b = b - a; | |
| 53 } while (b != 0); | |
| 54 | |
| 55 // Multiply in the common factors of two. | |
| 56 return a << twos; | |
| 57 } | |
| 58 | |
| 59 // Reduces the ration of *numerator and *denominator. | |
| 60 template <typename T> | |
| 61 void ReduceRatio(T* numerator, T* denominator) { | |
| 62 MOJO_DCHECK(numerator != nullptr); | |
| 63 MOJO_DCHECK(denominator != nullptr); | |
| 64 MOJO_DCHECK(*denominator != 0); | |
| 65 | |
| 66 T gcd = BinaryGcd(*numerator, *denominator); | |
| 67 | |
| 68 if (gcd == 0) { | |
| 69 *denominator = 1; | |
| 70 return; | |
| 71 } | |
| 72 | |
| 73 if (gcd == 1) { | |
| 74 return; | |
| 75 } | |
| 76 | |
| 77 *numerator = *numerator / gcd; | |
| 78 *denominator = *denominator / gcd; | |
| 79 } | |
| 80 | |
| 81 template void ReduceRatio<uint64_t>(uint64_t* numerator, uint64_t* denominator); | |
| 82 template void ReduceRatio<uint32_t>(uint32_t* numerator, uint32_t* denominator); | |
| 83 | |
| 84 // Scales a uint64_t value by the ratio of two uint32_t values. If round_up is | |
| 85 // true, the result is rounded up rather than down. overflow is set to indicate | |
| 86 // overflow. | |
| 87 uint64_t ScaleUInt64(uint64_t value, | |
| 88 uint32_t numerator, | |
| 89 uint32_t denominator, | |
| 90 bool round_up, | |
| 91 bool* overflow) { | |
| 92 MOJO_DCHECK(denominator != 0u); | |
| 93 MOJO_DCHECK(overflow != nullptr); | |
| 94 | |
| 95 constexpr uint64_t kLow32Bits = 0xffffffffu; | |
| 96 constexpr uint64_t kHigh32Bits = kLow32Bits << 32u; | |
| 97 | |
| 98 // high and low are the product of the numerator and the high and low halves | |
| 99 // (respectively) of value. | |
| 100 uint64_t high = numerator * (value >> 32u); | |
| 101 uint64_t low = numerator * (value & kLow32Bits); | |
| 102 // Ignoring overflow and remainder, the result we want is: | |
| 103 // ((high << 32) + low) / denominator. | |
| 104 | |
| 105 // Move the high end of low into the low end of high. | |
| 106 high += low >> 32u; | |
| 107 low = low & kLow32Bits; | |
| 108 // Ignoring overflow and remainder, the result we want is still: | |
| 109 // ((high << 32) + low) / denominator. | |
| 110 | |
| 111 // When we divide high by denominator, there'll be a remainder. Make | |
| 112 // that the high end of low, which is currently all zeroes. | |
| 113 low |= (high % denominator) << 32u; | |
| 114 | |
| 115 // Determine if we need to round up when we're done: | |
| 116 round_up = round_up && (low % denominator) != 0; | |
| 117 | |
| 118 // Do the division. | |
| 119 high /= denominator; | |
| 120 low /= denominator; | |
| 121 | |
| 122 // If high's top 32 bits aren't all zero, we have overflow. | |
| 123 if (high & kHigh32Bits) { | |
| 124 *overflow = true; | |
| 125 return 0; | |
| 126 } | |
| 127 | |
| 128 uint64_t result = (high << 32u) | low; | |
| 129 if (round_up) { | |
| 130 if (result == std::numeric_limits<int64_t>::max()) { | |
| 131 *overflow = true; | |
| 132 return 0; | |
| 133 } | |
| 134 ++result; | |
| 135 } | |
| 136 | |
| 137 *overflow = false; | |
| 138 return result; | |
| 139 } | |
| 140 | |
| 141 } // namespace | |
| 142 | |
| 143 // static | |
| 144 void Ratio::Reduce(uint32_t* numerator, uint32_t* denominator) { | |
| 145 ReduceRatio(numerator, denominator); | |
| 146 } | |
| 147 | |
| 148 // static | |
| 149 void Ratio::Product(uint32_t a_numerator, | |
| 150 uint32_t a_denominator, | |
| 151 uint32_t b_numerator, | |
| 152 uint32_t b_denominator, | |
| 153 uint32_t* product_numerator, | |
| 154 uint32_t* product_denominator, | |
| 155 bool exact) { | |
| 156 MOJO_DCHECK(a_denominator != 0); | |
| 157 MOJO_DCHECK(b_denominator != 0); | |
| 158 MOJO_DCHECK(product_numerator != nullptr); | |
| 159 MOJO_DCHECK(product_denominator != nullptr); | |
| 160 | |
| 161 uint64_t numerator = static_cast<uint64_t>(a_numerator) * b_numerator; | |
| 162 uint64_t denominator = static_cast<uint64_t>(a_denominator) * b_denominator; | |
| 163 | |
| 164 ReduceRatio(&numerator, &denominator); | |
| 165 | |
| 166 if (numerator > std::numeric_limits<uint32_t>::max() || | |
| 167 denominator > std::numeric_limits<uint32_t>::max()) { | |
| 168 MOJO_DCHECK(!exact); | |
| 169 | |
| 170 do { | |
| 171 numerator >>= 1; | |
| 172 denominator >>= 1; | |
| 173 } while (numerator > std::numeric_limits<uint32_t>::max() || | |
| 174 denominator > std::numeric_limits<uint32_t>::max()); | |
| 175 | |
| 176 if (denominator == 0) { | |
| 177 // Product is larger than we can represent. Return the largest value we | |
| 178 // can represent. | |
| 179 *product_numerator = std::numeric_limits<uint32_t>::max(); | |
| 180 *product_denominator = 1; | |
| 181 return; | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 *product_numerator = static_cast<uint32_t>(numerator); | |
| 186 *product_denominator = static_cast<uint32_t>(denominator); | |
| 187 } | |
| 188 | |
| 189 // static | |
| 190 int64_t Ratio::Scale(int64_t value, uint32_t numerator, uint32_t denominator) { | |
| 191 static constexpr uint64_t abs_of_min_int64 = | |
| 192 static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1; | |
| 193 | |
| 194 MOJO_DCHECK(denominator != 0u); | |
| 195 | |
| 196 bool overflow; | |
| 197 | |
| 198 uint64_t abs_result; | |
| 199 | |
| 200 if (value >= 0) { | |
| 201 abs_result = ScaleUInt64(static_cast<uint64_t>(value), numerator, | |
| 202 denominator, false, &overflow); | |
| 203 } else if (value == std::numeric_limits<int64_t>::min()) { | |
| 204 abs_result = ScaleUInt64(abs_of_min_int64, numerator, denominator, | |
| 205 true, &overflow); | |
| 206 } else { | |
| 207 abs_result = ScaleUInt64(static_cast<uint64_t>(-value), numerator, | |
| 208 denominator, true, &overflow); | |
| 209 } | |
| 210 | |
| 211 if (overflow) { | |
| 212 return Ratio::kOverflow; | |
| 213 } | |
| 214 | |
| 215 // Make sure we won't overflow when we cast to int64_t. | |
| 216 if (abs_result > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) { | |
| 217 if (value < 0 && abs_result == abs_of_min_int64) { | |
| 218 return std::numeric_limits<int64_t>::min(); | |
| 219 } | |
| 220 return Ratio::kOverflow; | |
| 221 } | |
| 222 | |
| 223 return value >= 0 ? static_cast<int64_t>(abs_result) | |
| 224 : -static_cast<int64_t>(abs_result); | |
| 225 } | |
| 226 | |
| 227 } // namespace media | |
| 228 } // namespace mojo | |
| OLD | NEW |