OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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 #ifndef CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_SETS_H_ | |
6 #define CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_SETS_H_ | |
7 | |
8 #include <algorithm> | |
9 #include <limits> | |
10 #include <utility> | |
11 #include <vector> | |
12 | |
13 #include "base/gtest_prod_util.h" | |
14 #include "base/logging.h" | |
15 #include "content/common/content_export.h" | |
16 #include "media/base/limits.h" | |
17 | |
18 namespace blink { | |
19 struct WebMediaTrackConstraintSet; | |
20 } | |
21 | |
22 namespace content { | |
23 | |
24 // This class template represents a set of candidates suitable for a numeric | |
25 // range-based constraint. | |
26 template <typename T> | |
27 class NumericRangeSet { | |
28 public: | |
29 NumericRangeSet() : min_(0), max_(DefaultMax()) {} | |
30 NumericRangeSet(T min, T max) : min_(min), max_(max) {} | |
31 NumericRangeSet(const NumericRangeSet& other) = default; | |
32 NumericRangeSet& operator=(const NumericRangeSet& other) = default; | |
33 ~NumericRangeSet() = default; | |
34 | |
35 T Min() const { return min_; } | |
36 T Max() const { return max_; } | |
37 bool IsEmpty() const { return max_ < min_; } | |
38 | |
39 NumericRangeSet Intersection(const NumericRangeSet& other) const { | |
40 return NumericRangeSet(std::max(min_, other.min_), | |
41 std::min(max_, other.max_)); | |
42 } | |
43 | |
44 // Creates a NumericRangeSet based on the minimum and maximum values of | |
45 // |constraint|. | |
46 template <typename ConstraintType> | |
47 static auto FromConstraint(ConstraintType constraint) | |
48 -> NumericRangeSet<decltype(constraint.min())> { | |
49 return NumericRangeSet<decltype(constraint.min())>( | |
50 ConstraintHasMin(constraint) ? ConstraintMin(constraint) : 0, | |
51 ConstraintHasMax(constraint) ? ConstraintMax(constraint) | |
52 : DefaultMax()); | |
53 } | |
54 | |
55 private: | |
56 static inline T DefaultMax() { | |
57 return std::numeric_limits<T>::has_infinity | |
58 ? std::numeric_limits<T>::infinity() | |
59 : std::numeric_limits<T>::max(); | |
60 } | |
61 T min_; | |
62 T max_; | |
63 }; | |
64 | |
65 // This class defines a set of discrete elements suitable for resolving | |
66 // constraints with a countable number of choices not suitable to be constrained | |
67 // by range such as strings, booleans and certain constraints of type long. | |
hta - Chromium
2017/03/03 11:02:36
Better language: "... not suitable to be constrain
Guido Urdaneta
2017/03/06 11:08:23
Done.
| |
68 // The set of elements of an unconstrained set is application defined. | |
hta - Chromium
2017/03/03 11:02:36
I don't understand what this sentence tries to say
hbos_chromium
2017/03/03 16:01:42
The unconstrained set is a set that conceptually c
Guido Urdaneta
2017/03/06 11:08:23
Addressed following hbos' suggestion.
Guido Urdaneta
2017/03/06 11:08:23
Done.
| |
69 template <typename T> | |
70 class DiscreteSet { | |
71 public: | |
72 // Creates an unconstrained set. | |
73 DiscreteSet() : is_unconstrained_(true) {} | |
hbos_chromium
2017/03/03 16:01:42
I would prefer a static function similar to EmptyS
Guido Urdaneta
2017/03/06 11:08:23
Done.
Also renamed is_unconstrained to is_universa
| |
74 // Creates a set containing the elements in |elements|. | |
75 // It is the responsibility of the caller to ensure that |elements| is not | |
76 // equivalent to the unconstrained set and that |elements| has no repeated | |
77 // values. Takes ownership of |elements|. | |
78 explicit DiscreteSet(std::vector<T> elements) | |
79 : is_unconstrained_(false), elements_(std::move(elements)) {} | |
80 // Creates an empty set; | |
81 static DiscreteSet EmptySet() { return DiscreteSet(std::vector<T>()); } | |
82 | |
83 DiscreteSet(const DiscreteSet& other) = default; | |
hta - Chromium
2017/03/03 11:02:36
C++ query: Is there any code-generation effect fro
Guido Urdaneta
2017/03/06 11:08:23
This is intended. I want the class to be copyable
| |
84 DiscreteSet& operator=(const DiscreteSet& other) = default; | |
85 DiscreteSet(DiscreteSet&& other) = default; | |
86 DiscreteSet& operator=(DiscreteSet&& other) = default; | |
87 ~DiscreteSet() = default; | |
88 | |
89 bool Contains(const T& value) const { | |
90 return is_unconstrained_ || | |
91 std::find(elements_.begin(), elements_.end(), value) != | |
92 elements_.end(); | |
93 } | |
94 | |
95 bool IsEmpty() const { return !is_unconstrained_ && elements_.empty(); } | |
96 | |
97 bool IsNonEmptyFinite() const { return !elements_.empty(); } | |
98 | |
99 DiscreteSet Intersection(const DiscreteSet& other) const { | |
100 if (is_unconstrained_) | |
101 return other; | |
102 if (other.is_unconstrained_) | |
103 return *this; | |
104 if (IsEmpty() || other.IsEmpty()) | |
105 return EmptySet(); | |
106 | |
107 // Both sets are finite and nonempty. | |
hta - Chromium
2017/03/03 11:02:36
s/finite/constrained/
Guido Urdaneta
2017/03/06 11:08:23
Done.
Changed the wording to both sets have explic
| |
108 std::vector<T> intersection; | |
109 for (const auto& entry : elements_) { | |
110 auto it = | |
111 std::find(other.elements_.begin(), other.elements_.end(), entry); | |
112 if (it != other.elements_.end()) { | |
113 intersection.push_back(entry); | |
114 } | |
115 } | |
116 return DiscreteSet(std::move(intersection)); | |
hbos_chromium
2017/03/03 16:01:42
std::set would yield O(n log n) instead of O(n^2)
Guido Urdaneta
2017/03/06 11:08:23
Yes. For small sets vector is faster and makes it
| |
117 } | |
118 | |
119 // Returns a copy of the first element in the set. This is useful as a simple | |
120 // tie-breaker rule. | |
hbos_chromium
2017/03/03 16:01:42
Add a comment saying that this is not applicable t
Guido Urdaneta
2017/03/06 11:08:23
Done.
| |
121 T FirstElement() const { | |
122 DCHECK(IsNonEmptyFinite()); | |
123 return elements_[0]; | |
124 } | |
125 | |
126 bool is_unconstrained() const { return is_unconstrained_; } | |
127 | |
128 private: | |
129 bool is_unconstrained_; | |
130 std::vector<T> elements_; | |
hta - Chromium
2017/03/03 11:02:36
Query: Would this work with std::set<>?
In that c
hbos_chromium
2017/03/03 16:01:42
(In that case this could be represented by an Opti
Guido Urdaneta
2017/03/06 11:08:23
Acknowledged.
Guido Urdaneta
2017/03/06 11:08:23
This type is basically a wrapper over std::vector
| |
131 }; | |
132 | |
133 // This class represents a set of (height, width) screen resolution candidates | |
134 // determined by width, height and aspect-ratio constraints. | |
135 class CONTENT_EXPORT ResolutionSet { | |
136 public: | |
137 static constexpr int kMinConstrainedDimension = 1; | |
138 static constexpr int kMaxConstrainedDimension = | |
139 media::limits::kMaxDimension - 1; | |
hta - Chromium
2017/03/03 11:02:36
kMaxDimension is already 32767 - I think you're us
Guido Urdaneta
2017/03/06 11:08:23
Got rid of all the "Constrained" constants and met
| |
140 static constexpr int kMinConstrainedAspectRatio = | |
141 static_cast<double>(kMinConstrainedDimension) / | |
142 static_cast<double>(kMaxConstrainedDimension); | |
143 static constexpr int kMaxConstrainedAspectRatio = | |
144 static_cast<double>(kMaxConstrainedDimension) / | |
145 static_cast<double>(kMinConstrainedDimension); | |
hbos_chromium
2017/03/03 16:01:42
Doesn't it make more sense to use max and min (not
Guido Urdaneta
2017/03/06 11:08:23
I think you're right. The class now just supports
| |
146 | |
147 // Helper class that represents (height, width) points on a plane. | |
148 class Point { | |
hta - Chromium
2017/03/03 11:02:36
I'm not sure of the value of another point class.
hbos_chromium
2017/03/03 16:01:42
Point uses int. There is gfx::PointF and gfx::Vect
Guido Urdaneta
2017/03/06 11:08:22
I prefer to keep this class (at least for one more
Guido Urdaneta
2017/03/06 11:08:23
See reply to hbos.
| |
149 public: | |
150 // Creates a (|height|, |width|) point. |height| and |width| must be finite. | |
151 Point(double height, double width); | |
152 Point(const Point& other); | |
153 Point& operator=(const Point& other); | |
154 ~Point(); | |
155 | |
156 // Accessors. | |
157 double height() const { return height_; } | |
158 double width() const { return width_; } | |
159 double AspectRatio() const { return width_ / height_; } | |
hbos_chromium
2017/03/03 16:01:42
Watch out for divide by zero?
Guido Urdaneta
2017/03/06 11:08:22
divide by zero is fine in most cases. NaN (0/0 or
| |
160 | |
161 // Exact equality/inequality operators. | |
162 bool operator==(const Point& other) const; | |
163 bool operator!=(const Point& other) const; | |
164 | |
165 // Returns true if both coordinates of this point and |other| are | |
166 // approximately equal. | |
167 bool IsApproximatelyEqualTo(const Point& other) const; | |
168 | |
169 // Vector-style addition and subtraction operators. | |
170 Point operator+(const Point& other) const; | |
171 Point operator-(const Point& other) const; | |
172 | |
173 // Returns the dot product between |p1| and |p2|. | |
174 static double Dot(const Point& p1, const Point& p2); | |
175 | |
176 // Returns the square Euclidean distance from |p1| to |p2|. | |
hta - Chromium
2017/03/03 11:02:36
Does it return the square of the distance or the d
hbos_chromium
2017/03/03 16:01:42
It's the square, so the function should be renamed
Guido Urdaneta
2017/03/06 11:08:22
Renamed.
Guido Urdaneta
2017/03/06 11:08:23
Square Euclidean is still a distance :)
But rename
| |
177 static double DistanceToPoint(const Point& p1, const Point& p2); | |
178 | |
179 // Returns the point in the line segment determined by |s1| and |s2| that | |
180 // is closest to |p|. | |
181 static Point ClosestPointInSegment(const Point& p, | |
182 const Point& s1, | |
183 const Point& s2); | |
184 | |
185 private: | |
186 double height_; | |
187 double width_; | |
hbos_chromium
2017/03/03 16:01:42
The point has no width and height, only coordinate
Guido Urdaneta
2017/03/06 11:08:23
I like height and width better to avoid confusion
hbos_chromium
2017/03/08 21:03:00
The way I see it is: Input to the algorithm is wid
| |
188 }; | |
189 | |
190 ResolutionSet(); // Creates an unconstrained candidate set. | |
191 ResolutionSet(int min_height, | |
192 int max_height, | |
193 int min_width, | |
194 int max_width, | |
195 double min_aspect_ratio, | |
196 double max_aspect_ratio); | |
197 ResolutionSet(const ResolutionSet& other); | |
198 ResolutionSet& operator=(const ResolutionSet& other); | |
199 ~ResolutionSet(); | |
200 | |
201 // Getters. | |
202 int min_height() const { return min_height_; } | |
203 int max_height() const { return max_height_; } | |
204 int min_width() const { return min_width_; } | |
205 int max_width() const { return max_width_; } | |
206 double min_aspect_ratio() const { return min_aspect_ratio_; } | |
207 double max_aspect_ratio() const { return max_aspect_ratio_; } | |
208 | |
209 // Returns true if this set is empty. | |
210 bool IsEmpty() const; | |
211 | |
212 // These functions return true if a particular constraint causes the set to | |
213 // be empty. | |
214 bool IsHeightEmpty() const; | |
215 bool IsWidthEmpty() const; | |
216 bool IsAspectRatioEmpty() const; | |
217 | |
218 // These functions return true if a particular variable is constrained. | |
219 // MinHeight and MinWidth are unconstrained if their value is less than | |
220 // kMinValidDimension. | |
221 // MaxHeight and MaxWidth are unconstrained if their value is greater than | |
222 // kMaxValidDimension. | |
223 // MinAspectRatio is unconstrained if its value is 0.0 or less. | |
224 // MaxAspectRatio is unconstrained if its value is positive infinity. | |
225 bool HasMinHeight() const; | |
226 bool HasMaxHeight() const; | |
227 bool HasMinWidth() const; | |
228 bool HasMaxWidth() const; | |
229 bool HasMinAspectRatio() const; | |
230 bool HasMaxAspectRatio() const; | |
231 | |
232 // These functions return true if a particular variable is unconstrained on | |
233 // both ends. | |
234 bool IsHeightUnconstrained() const; | |
235 bool IsWidthUnconstrained() const; | |
236 bool IsAspectRatioUnconstrained() const; | |
237 | |
238 // Returns true if the point (height, width) is included in this set. | |
239 bool ContainsPoint(int height, int width) const; | |
240 bool ContainsPoint(const Point& point) const; | |
241 | |
242 // Returns a new set with the intersection of |*this| and |other|. | |
243 ResolutionSet Intersection(const ResolutionSet& other) const; | |
244 | |
245 // Returns the closest point in this set to |point|. If |point| is included in | |
246 // this set, Point is returned. If this set is empty, behavior is undefined. | |
247 Point ClosestPointTo(const Point& point) const; | |
248 | |
249 // Returns a point in this (nonempty) set closest to the ideal values for the | |
250 // height, width and aspectRatio constraints in |constraint_set|. | |
251 // Note that this function ignores all the other data in |constraint_set|. | |
252 // Only the ideal height, width and aspect ratio are used, and from now on | |
253 // referred to as |ideal_height|, |ideal_width| and |ideal_aspect_ratio| | |
254 // respectively. | |
255 // | |
256 // * If all three ideal values are given, |ideal_aspect_ratio| is ignored and | |
257 // the point closest to (|ideal_height|, |ideal_width|) is returned. | |
hbos_chromium
2017/03/03 16:01:42
It doesn't matter but it surprised/confused me at
Guido Urdaneta
2017/03/06 11:08:23
Because it is easier to think of aspectRatio as a
hbos_chromium
2017/03/08 21:03:00
Acknowledged.
If this at any point is replaced by
| |
258 // * If two ideal values are given, they are used to determine a single ideal | |
259 // point, which can be one of: | |
260 // - (|ideal_height|, |ideal_width|), | |
261 // - (|ideal_height|, |ideal_height|*|ideal_aspect_ratio|), or | |
262 // - (|ideal_width| / |ideal_aspect_ratio|, |ideal_width|). | |
263 // The point in the set closest to the ideal point is returned. | |
264 // * If a single ideal value is given, a point in the set closest to the line | |
265 // defined by the ideal value is returned. If there is more than one point | |
266 // closest to the ideal line, the following tie-breaker rules are used: | |
267 // - If |ideal_height| is provided, the point closest to | |
268 // (|ideal_height|, |ideal_height| * kDefaultAspectRatio). | |
269 // - If |ideal_width| is provided, the point closest to | |
270 // (|ideal_width| / kDefaultAspectRatio, |ideal_width|). | |
271 // - If |ideal_aspect_ratio| is provided, the point with largest area among | |
272 // the points closest to | |
273 // (kDefaultHeight, kDefaultHeight * aspect_ratio) and | |
274 // (kDefaultWidth / aspect_ratio, kDefaultWidth), | |
275 // where aspect_ratio is |ideal_aspect_ratio| if the ideal line intersects | |
276 // the set, and the closest aspect ratio to |ideal_aspect_ratio| among the | |
277 // points in the set if no point in the set has an aspect ratio equal to | |
278 // |ideal_aspect_ratio|. | |
279 // * If no ideal value is given, proceed as if only |ideal_aspect_ratio| was | |
280 // provided with a value of kDefaultAspectRatio. | |
281 // | |
282 // This is intended to support the implementation of the spec algorithm for | |
283 // selection of track settings, as defined in | |
284 // https://w3c.github.io/mediacapture-main/#dfn-selectsettings. | |
285 // | |
286 // The main difference between this algorithm and the spec is that when ideal | |
287 // values are provided, the spec mandates finding a point that minimizes the | |
288 // sum of custom relative distances for each provided ideal value, while this | |
289 // algorithm minimizes either the Euclidean distance (sum of square distances) | |
290 // on a height-width plane for the cases where two or three ideal values are | |
291 // provided, or the absolute distance for the case with one ideal value. | |
292 // Also, in the case with three ideal values, this algorithm ignores the | |
293 // distance to the ideal aspect ratio. | |
294 // In most cases the difference in the final result should be negligible. | |
295 // The reason to follow this approach is that optimization in the worst case | |
296 // is reduced to projection of a point on line segment, which is a simple | |
297 // operation that provides exact results. Using the distance function of the | |
298 // spec, which is not continuous, would require complex optimization methods | |
299 // that do not necessarily guarantee finding the real optimal value. | |
300 // | |
301 // This function has undefined behavior if this set is empty. | |
302 Point SelectClosestPointToIdeal( | |
303 const blink::WebMediaTrackConstraintSet& constraint_set) const; | |
304 | |
305 // Utilities that return ResolutionCandidateSets constrained on a specific | |
hta - Chromium
2017/03/03 11:02:36
They return |ResolutionSet|s, not ResolutionCandid
Guido Urdaneta
2017/03/06 11:08:23
Indeed a leftover. Done.
| |
306 // variable. | |
307 static ResolutionSet FromHeight(int min, int max); | |
308 static ResolutionSet FromExactHeight(int value); | |
309 static ResolutionSet FromWidth(int min, int max); | |
310 static ResolutionSet FromExactWidth(int value); | |
311 static ResolutionSet FromAspectRatio(double min, double max); | |
312 static ResolutionSet FromExactAspectRatio(double value); | |
313 | |
314 // Returns a ResolutionCandidateSet initialized with |constraint_set|'s | |
315 // width, height and aspectRatio constraints. | |
316 static ResolutionSet FromConstraintSet( | |
317 const blink::WebMediaTrackConstraintSet& constraint_set); | |
318 | |
319 private: | |
320 FRIEND_TEST_ALL_PREFIXES(MediaStreamConstraintsUtilSetsTest, | |
321 ResolutionVertices); | |
322 | |
323 // Returns a list of the vertices defined by the constraints on a height-width | |
324 // Cartesian plane. | |
325 // If the list is empty, the set is empty. | |
326 // If the list contains a single point, the set contains a single point. | |
327 // If the list contains two points, the set is composed of points on a line | |
328 // segment. | |
329 // If the list contains three to six points, they are the vertices of a | |
330 // convex polygon containing all valid points in the set. Each pair of | |
331 // consecutive vertices (modulo the size of the list) corresponds to a side of | |
332 // the polygon, with the vertices given in counterclockwise order. | |
333 // The list cannot contain more than six points. | |
334 std::vector<Point> ComputeVertices() const; | |
335 | |
336 // Adds |point| to |vertices| if |point| is included in this candidate set. | |
337 void TryAddVertex(std::vector<ResolutionSet::Point>* vertices, | |
338 const ResolutionSet::Point& point) const; | |
339 | |
340 // Returns the vertices of the set that have the property accessed | |
341 // by |accessor| closest to |value|. The returned vector always has one or two | |
342 // elements. Behavior is undefined if the set is empty. | |
343 std::vector<Point> GetClosestVertices(double (Point::*accessor)() const, | |
344 double value) const; | |
345 | |
346 // Implements SelectClosestPointToIdeal() for the case when only the ideal | |
347 // aspect ratio is provided. | |
348 Point SelectClosestPointToIdealAspectRatio(double ideal_aspect_ratio) const; | |
349 | |
350 int min_height_; | |
351 int max_height_; | |
352 int min_width_; | |
353 int max_width_; | |
354 double min_aspect_ratio_; | |
355 double max_aspect_ratio_; | |
356 }; | |
357 | |
358 // Scalar multiplication for Points. | |
359 ResolutionSet::Point CONTENT_EXPORT operator*(double d, | |
360 const ResolutionSet::Point& p); | |
361 | |
362 } // namespace content | |
363 | |
364 #endif // CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_SETS_H_ | |
OLD | NEW |