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