Chromium Code Reviews| 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 |