Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Side by Side Diff: content/renderer/media/media_stream_constraints_util_sets.h

Issue 2728633002: Add utility set classes to support getUserMedia constraint proccessing. (Closed)
Patch Set: fix Windows compile issues + comments/formatting Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/renderer/BUILD.gn ('k') | content/renderer/media/media_stream_constraints_util_sets.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 "content/renderer/media/media_stream_constraints_util.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. Examples are strings, booleans and certain constraints of type
68 // long. A DiscreteSet can be empty, have their elements explicitly stated, or
69 // be the universal set. The universal set is a set that contains all possible
70 // elements. The specific definition of what elements are in the universal set
71 // is application defined (e.g., it could be all possible boolean values, all
72 // possible strings of length N, or anything that suits a particular
73 // application).
74 template <typename T>
75 class DiscreteSet {
76 public:
77 // Creates a set containing the elements in |elements|.
78 // It is the responsibility of the caller to ensure that |elements| is not
79 // equivalent to the universal set and that |elements| has no repeated
80 // values. Takes ownership of |elements|.
81 explicit DiscreteSet(std::vector<T> elements)
82 : is_universal_(false), elements_(std::move(elements)) {}
83 // Creates an empty set;
84 static DiscreteSet EmptySet() { return DiscreteSet(std::vector<T>()); }
85 static DiscreteSet UniversalSet() { return DiscreteSet(); }
86
87 DiscreteSet(const DiscreteSet& other) = default;
88 DiscreteSet& operator=(const DiscreteSet& other) = default;
89 DiscreteSet(DiscreteSet&& other) = default;
90 DiscreteSet& operator=(DiscreteSet&& other) = default;
91 ~DiscreteSet() = default;
92
93 bool Contains(const T& value) const {
94 return is_universal_ || std::find(elements_.begin(), elements_.end(),
95 value) != elements_.end();
96 }
97
98 bool IsEmpty() const { return !is_universal_ && elements_.empty(); }
99
100 bool HasExplicitElements() const { return !elements_.empty(); }
101
102 DiscreteSet Intersection(const DiscreteSet& other) const {
103 if (is_universal_)
104 return other;
105 if (other.is_universal_)
106 return *this;
107 if (IsEmpty() || other.IsEmpty())
108 return EmptySet();
109
110 // Both sets have explicit elements.
111 std::vector<T> intersection;
112 for (const auto& entry : elements_) {
113 auto it =
114 std::find(other.elements_.begin(), other.elements_.end(), entry);
115 if (it != other.elements_.end()) {
116 intersection.push_back(entry);
117 }
118 }
119 return DiscreteSet(std::move(intersection));
120 }
121
122 // Returns a copy of the first element in the set. This is useful as a simple
123 // tie-breaker rule. This applies only to constrained nonempty sets.
124 // Behavior is undefined if the set is empty or universal.
125 T FirstElement() const {
126 DCHECK(HasExplicitElements());
127 return elements_[0];
128 }
129
130 bool is_universal() const { return is_universal_; }
131
132 private:
133 // Creates a universal set.
134 DiscreteSet() : is_universal_(true) {}
135
136 bool is_universal_;
137 std::vector<T> elements_;
138 };
139
140 // This class represents a set of (height, width) screen resolution candidates
141 // determined by width, height and aspect-ratio constraints.
142 // This class supports widths and heights from 0 to kMaxDimension, both
143 // inclusive and aspect ratios from 0.0 to positive infinity, both inclusive.
144 class CONTENT_EXPORT ResolutionSet {
145 public:
146 static constexpr int kMaxDimension = std::numeric_limits<int>::max();
147
148 // Helper class that represents (height, width) points on a plane.
149 // TODO(guidou): Use a generic point/vector class that uses double once it
150 // becomes available (e.g., a gfx::Vector2dD).
151 class CONTENT_EXPORT Point {
152 public:
153 // Creates a (|height|, |width|) point. |height| and |width| must be finite.
154 Point(double height, double width);
155 Point(const Point& other);
156 Point& operator=(const Point& other);
157 ~Point();
158
159 // Accessors.
160 double height() const { return height_; }
161 double width() const { return width_; }
162 double AspectRatio() const { return width_ / height_; }
163
164 // Exact equality/inequality operators.
165 bool operator==(const Point& other) const;
166 bool operator!=(const Point& other) const;
167
168 // Returns true if the coordinates of this point and |other| are
169 // approximately equal.
170 bool IsApproximatelyEqualTo(const Point& other) const;
171
172 // Vector-style addition and subtraction operators.
173 Point operator+(const Point& other) const;
174 Point operator-(const Point& other) const;
175
176 // Returns the dot product between |p1| and |p2|.
177 static double Dot(const Point& p1, const Point& p2);
178
179 // Returns the square Euclidean distance between |p1| and |p2|.
180 static double SquareEuclideanDistance(const Point& p1, const Point& p2);
181
182 // Returns the point in the line segment determined by |s1| and |s2| that
183 // is closest to |p|.
184 static Point ClosestPointInSegment(const Point& p,
185 const Point& s1,
186 const Point& s2);
187
188 private:
189 double height_;
190 double width_;
191 };
192
193 // Creates a set with the maximum supported ranges for width, height and
194 // aspect ratio.
195 ResolutionSet();
196 ResolutionSet(int min_height,
197 int max_height,
198 int min_width,
199 int max_width,
200 double min_aspect_ratio,
201 double max_aspect_ratio);
202 ResolutionSet(const ResolutionSet& other);
203 ResolutionSet& operator=(const ResolutionSet& other);
204 ~ResolutionSet();
205
206 // Getters.
207 int min_height() const { return min_height_; }
208 int max_height() const { return max_height_; }
209 int min_width() const { return min_width_; }
210 int max_width() const { return max_width_; }
211 double min_aspect_ratio() const { return min_aspect_ratio_; }
212 double max_aspect_ratio() const { return max_aspect_ratio_; }
213
214 // Returns true if this set is empty.
215 bool IsEmpty() const;
216
217 // These functions return true if a particular variable causes the set to be
218 // empty.
219 bool IsHeightEmpty() const;
220 bool IsWidthEmpty() const;
221 bool IsAspectRatioEmpty() const;
222
223 // These functions return true if the given point is included in this set.
224 bool ContainsPoint(const Point& point) const;
225 bool ContainsPoint(int height, int width) const;
226
227 // Returns a new set with the intersection of |*this| and |other|.
228 ResolutionSet Intersection(const ResolutionSet& other) const;
229
230 // Returns a point in this (nonempty) set closest to the ideal values for the
231 // height, width and aspectRatio constraints in |constraint_set|.
232 // Note that this function ignores all the other data in |constraint_set|.
233 // Only the ideal height, width and aspect ratio are used, and from now on
234 // referred to as |ideal_height|, |ideal_width| and |ideal_aspect_ratio|
235 // respectively.
236 //
237 // * If all three ideal values are given, |ideal_aspect_ratio| is ignored and
238 // the point closest to (|ideal_height|, |ideal_width|) is returned.
239 // * If two ideal values are given, they are used to determine a single ideal
240 // point, which can be one of:
241 // - (|ideal_height|, |ideal_width|),
242 // - (|ideal_height|, |ideal_height|*|ideal_aspect_ratio|), or
243 // - (|ideal_width| / |ideal_aspect_ratio|, |ideal_width|).
244 // The point in the set closest to the ideal point is returned.
245 // * If a single ideal value is given, a point in the set closest to the line
246 // defined by the ideal value is returned. If there is more than one point
247 // closest to the ideal line, the following tie-breaker rules are used:
248 // - If |ideal_height| is provided, the point closest to
249 // (|ideal_height|, |ideal_height| * kDefaultAspectRatio).
250 // - If |ideal_width| is provided, the point closest to
251 // (|ideal_width| / kDefaultAspectRatio, |ideal_width|).
252 // - If |ideal_aspect_ratio| is provided, the point with largest area among
253 // the points closest to
254 // (kDefaultHeight, kDefaultHeight * aspect_ratio) and
255 // (kDefaultWidth / aspect_ratio, kDefaultWidth),
256 // where aspect_ratio is |ideal_aspect_ratio| if the ideal line intersects
257 // the set, and the closest aspect ratio to |ideal_aspect_ratio| among the
258 // points in the set if no point in the set has an aspect ratio equal to
259 // |ideal_aspect_ratio|.
260 // * If no ideal value is given, proceed as if only |ideal_aspect_ratio| was
261 // provided with a value of kDefaultAspectRatio.
262 //
263 // This is intended to support the implementation of the spec algorithm for
264 // selection of track settings, as defined in
265 // https://w3c.github.io/mediacapture-main/#dfn-selectsettings.
266 //
267 // The main difference between this algorithm and the spec is that when ideal
268 // values are provided, the spec mandates finding a point that minimizes the
269 // sum of custom relative distances for each provided ideal value, while this
270 // algorithm minimizes either the Euclidean distance (sum of square distances)
271 // on a height-width plane for the cases where two or three ideal values are
272 // provided, or the absolute distance for the case with one ideal value.
273 // Also, in the case with three ideal values, this algorithm ignores the
274 // distance to the ideal aspect ratio.
275 // In most cases the difference in the final result should be negligible.
276 // The reason to follow this approach is that optimization in the worst case
277 // is reduced to projection of a point on line segment, which is a simple
278 // operation that provides exact results. Using the distance function of the
279 // spec, which is not continuous, would require complex optimization methods
280 // that do not necessarily guarantee finding the real optimal value.
281 //
282 // This function has undefined behavior if this set is empty.
283 Point SelectClosestPointToIdeal(
284 const blink::WebMediaTrackConstraintSet& constraint_set) const;
285
286 // Utilities that return ResolutionSets constrained on a specific variable.
287 static ResolutionSet FromHeight(int min, int max);
288 static ResolutionSet FromExactHeight(int value);
289 static ResolutionSet FromWidth(int min, int max);
290 static ResolutionSet FromExactWidth(int value);
291 static ResolutionSet FromAspectRatio(double min, double max);
292 static ResolutionSet FromExactAspectRatio(double value);
293
294 // Returns a ResolutionCandidateSet initialized with |constraint_set|'s
295 // width, height and aspectRatio constraints.
296 static ResolutionSet FromConstraintSet(
297 const blink::WebMediaTrackConstraintSet& constraint_set);
298
299 private:
300 FRIEND_TEST_ALL_PREFIXES(MediaStreamConstraintsUtilSetsTest,
301 ResolutionVertices);
302 FRIEND_TEST_ALL_PREFIXES(MediaStreamConstraintsUtilSetsTest,
303 ResolutionPointSetClosestPoint);
304 FRIEND_TEST_ALL_PREFIXES(MediaStreamConstraintsUtilSetsTest,
305 ResolutionLineSetClosestPoint);
306 FRIEND_TEST_ALL_PREFIXES(MediaStreamConstraintsUtilSetsTest,
307 ResolutionGeneralSetClosestPoint);
308 FRIEND_TEST_ALL_PREFIXES(MediaStreamConstraintsUtilSetsTest,
309 ResolutionIdealOutsideSinglePoint);
310
311 // Implements SelectClosestPointToIdeal() for the case when only the ideal
312 // aspect ratio is provided.
313 Point SelectClosestPointToIdealAspectRatio(double ideal_aspect_ratio) const;
314
315 // Returns the closest point in this set to |point|. If |point| is included in
316 // this set, Point is returned. If this set is empty, behavior is undefined.
317 Point ClosestPointTo(const Point& point) const;
318
319 // Returns the vertices of the set that have the property accessed
320 // by |accessor| closest to |value|. The returned vector always has one or two
321 // elements. Behavior is undefined if the set is empty.
322 std::vector<Point> GetClosestVertices(double (Point::*accessor)() const,
323 double value) const;
324
325 // Returns a list of the vertices defined by the constraints on a height-width
326 // Cartesian plane.
327 // If the list is empty, the set is empty.
328 // If the list contains a single point, the set contains a single point.
329 // If the list contains two points, the set is composed of points on a line
330 // segment.
331 // If the list contains three to six points, they are the vertices of a
332 // convex polygon containing all valid points in the set. Each pair of
333 // consecutive vertices (modulo the size of the list) corresponds to a side of
334 // the polygon, with the vertices given in counterclockwise order.
335 // The list cannot contain more than six points.
336 std::vector<Point> ComputeVertices() const;
337
338 // Adds |point| to |vertices| if |point| is included in this candidate set.
339 void TryAddVertex(std::vector<ResolutionSet::Point>* vertices,
340 const ResolutionSet::Point& point) const;
341
342 int min_height_;
343 int max_height_;
344 int min_width_;
345 int max_width_;
346 double min_aspect_ratio_;
347 double max_aspect_ratio_;
348 };
349
350 // Scalar multiplication for Points.
351 ResolutionSet::Point CONTENT_EXPORT operator*(double d,
352 const ResolutionSet::Point& p);
353
354 } // namespace content
355
356 #endif // CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_SETS_H_
OLDNEW
« no previous file with comments | « content/renderer/BUILD.gn ('k') | content/renderer/media/media_stream_constraints_util_sets.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698