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