| 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 | 
|---|