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 #include "content/renderer/media/media_stream_constraints_util_video_source.h" | |
6 | |
7 #include <algorithm> | |
8 #include <utility> | |
9 | |
10 #include "base/optional.h" | |
11 #include "content/renderer/media/media_stream_video_source.h" | |
12 #include "content/renderer/media/mock_constraint_factory.h" | |
13 #include "testing/gtest/include/gtest/gtest.h" | |
14 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" | |
15 | |
16 namespace content { | |
17 | |
18 namespace { | |
19 | |
20 const char kDeviceID1[] = "fake_device_1"; | |
21 const char kDeviceID2[] = "fake_device_2"; | |
22 const char kDeviceID3[] = "fake_device_3"; | |
23 } | |
24 | |
25 class MediaStreamConstraintsUtilVideoSourceTest : public testing::Test { | |
26 public: | |
27 void SetUp() override { | |
28 ::mojom::VideoInputDeviceCapabilitiesPtr device = | |
29 ::mojom::VideoInputDeviceCapabilities::New(); | |
30 device->device_id = kDeviceID1; | |
31 device->facing_mode = ::mojom::FacingMode::NONE; | |
32 device->formats = { | |
33 media::VideoCaptureFormat(gfx::Size(200, 200), 40.0f, | |
34 media::PIXEL_FORMAT_I420), | |
35 // This entry is is the closest to defaults. | |
36 media::VideoCaptureFormat(gfx::Size(500, 500), 40.0f, | |
37 media::PIXEL_FORMAT_I420), | |
38 media::VideoCaptureFormat(gfx::Size(1000, 1000), 20.0f, | |
39 media::PIXEL_FORMAT_I420), | |
40 }; | |
41 capabilities_.device_capabilities.push_back(std::move(device)); | |
42 | |
43 device = ::mojom::VideoInputDeviceCapabilities::New(); | |
44 device->device_id = kDeviceID2; | |
45 device->facing_mode = ::mojom::FacingMode::ENVIRONMENT; | |
46 device->formats = { | |
47 media::VideoCaptureFormat(gfx::Size(40, 30), 20.0f, | |
48 media::PIXEL_FORMAT_I420), | |
49 media::VideoCaptureFormat(gfx::Size(320, 240), 30.0f, | |
50 media::PIXEL_FORMAT_I420), | |
51 // This format has defaults for all settings | |
52 media::VideoCaptureFormat( | |
53 gfx::Size(MediaStreamVideoSource::kDefaultWidth, | |
54 MediaStreamVideoSource::kDefaultHeight), | |
55 MediaStreamVideoSource::kDefaultFrameRate, | |
56 media::PIXEL_FORMAT_I420), | |
57 media::VideoCaptureFormat(gfx::Size(800, 600), 20.0f, | |
58 media::PIXEL_FORMAT_I420), | |
59 }; | |
60 capabilities_.device_capabilities.push_back(std::move(device)); | |
61 | |
62 device = ::mojom::VideoInputDeviceCapabilities::New(); | |
63 device->device_id = kDeviceID3; | |
64 device->facing_mode = ::mojom::FacingMode::USER; | |
65 device->formats = { | |
66 media::VideoCaptureFormat(gfx::Size(320, 240), 10.0f, | |
67 media::PIXEL_FORMAT_I420), | |
68 media::VideoCaptureFormat(gfx::Size(640, 480), 10.0f, | |
69 media::PIXEL_FORMAT_I420), | |
70 // This format has defaults for all settings | |
71 media::VideoCaptureFormat( | |
72 gfx::Size(MediaStreamVideoSource::kDefaultWidth, | |
73 MediaStreamVideoSource::kDefaultHeight), | |
74 MediaStreamVideoSource::kDefaultFrameRate, | |
75 media::PIXEL_FORMAT_I420), | |
76 media::VideoCaptureFormat(gfx::Size(1280, 720), 60.0f, | |
77 media::PIXEL_FORMAT_I420), | |
78 media::VideoCaptureFormat(gfx::Size(1920, 1080), 60.0f, | |
79 media::PIXEL_FORMAT_I420), | |
80 media::VideoCaptureFormat(gfx::Size(2304, 1536), 10.0f, | |
81 media::PIXEL_FORMAT_I420), | |
82 }; | |
83 capabilities_.device_capabilities.push_back(std::move(device)); | |
84 | |
85 capabilities_.power_line_capabilities = { | |
86 media::PowerLineFrequency::FREQUENCY_DEFAULT, | |
87 media::PowerLineFrequency::FREQUENCY_50HZ, | |
88 media::PowerLineFrequency::FREQUENCY_60HZ, | |
89 }; | |
90 | |
91 default_device_ = capabilities_.device_capabilities[0].get(); | |
92 low_res_device_ = capabilities_.device_capabilities[1].get(); | |
93 high_res_device_ = capabilities_.device_capabilities[2].get(); | |
94 default_closest_format_ = &default_device_->formats[1]; | |
95 low_res_closest_format_ = &low_res_device_->formats[2]; | |
96 high_res_closest_format_ = &high_res_device_->formats[2]; | |
97 high_res_highest_format_ = &high_res_device_->formats[5]; | |
98 } | |
99 | |
100 protected: | |
101 void SelectSettings() { | |
hta - Chromium
2017/02/02 00:32:39
As a matter of style, wouldn't it be prettier if S
Guido Urdaneta
2017/02/02 11:35:39
Done.
| |
102 blink::WebMediaConstraints constraints = | |
103 constraint_factory_.CreateWebMediaConstraints(); | |
104 result_ = SelectVideoCaptureSourceSettings(capabilities_, constraints); | |
105 } | |
106 | |
107 VideoCaptureCapabilities capabilities_; | |
108 const mojom::VideoInputDeviceCapabilities* default_device_; | |
109 const mojom::VideoInputDeviceCapabilities* low_res_device_; | |
110 const mojom::VideoInputDeviceCapabilities* high_res_device_; | |
111 // Closest formats to the default settings. | |
112 const media::VideoCaptureFormat* default_closest_format_; | |
113 const media::VideoCaptureFormat* low_res_closest_format_; | |
114 const media::VideoCaptureFormat* high_res_closest_format_; | |
115 const media::VideoCaptureFormat* high_res_highest_format_; | |
116 | |
117 MockConstraintFactory constraint_factory_; | |
118 VideoCaptureSourceSelectionResult result_; | |
119 }; | |
120 | |
121 // The overconstrained tests verify that failure of any single required | |
122 // constraint results in failure to select a candidate. | |
123 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnDeviceID) { | |
124 constraint_factory_.Reset(); | |
125 constraint_factory_.basic().deviceId.setExact( | |
126 blink::WebString::fromASCII("NONEXSISTING")); | |
127 SelectSettings(); | |
128 EXPECT_FALSE(result_.has_value()); | |
129 EXPECT_EQ(constraint_factory_.basic().deviceId.name(), | |
130 result_.failed_constraint_name); | |
131 } | |
132 | |
133 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnFacingMode) { | |
134 constraint_factory_.Reset(); | |
135 // No device in |capabilities_| has facing mode equal to LEFT. | |
136 constraint_factory_.basic().facingMode.setExact( | |
137 blink::WebString::fromASCII("left")); | |
138 SelectSettings(); | |
139 EXPECT_FALSE(result_.has_value()); | |
140 EXPECT_EQ(constraint_factory_.basic().facingMode.name(), | |
141 result_.failed_constraint_name); | |
142 } | |
143 | |
144 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnHeight) { | |
145 constraint_factory_.Reset(); | |
146 constraint_factory_.basic().height.setExact(123467890); | |
147 SelectSettings(); | |
148 EXPECT_FALSE(result_.has_value()); | |
149 EXPECT_EQ(constraint_factory_.basic().height.name(), | |
150 result_.failed_constraint_name); | |
151 | |
152 constraint_factory_.Reset(); | |
153 constraint_factory_.basic().height.setMin(123467890); | |
154 SelectSettings(); | |
155 EXPECT_FALSE(result_.has_value()); | |
156 EXPECT_EQ(constraint_factory_.basic().height.name(), | |
157 result_.failed_constraint_name); | |
158 | |
159 constraint_factory_.Reset(); | |
160 constraint_factory_.basic().height.setMax(0); | |
161 SelectSettings(); | |
162 EXPECT_FALSE(result_.has_value()); | |
163 EXPECT_EQ(constraint_factory_.basic().height.name(), | |
164 result_.failed_constraint_name); | |
165 } | |
166 | |
167 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnWidth) { | |
168 constraint_factory_.Reset(); | |
169 constraint_factory_.basic().width.setExact(123467890); | |
170 SelectSettings(); | |
171 EXPECT_FALSE(result_.has_value()); | |
172 EXPECT_EQ(constraint_factory_.basic().width.name(), | |
173 result_.failed_constraint_name); | |
174 | |
175 constraint_factory_.Reset(); | |
176 constraint_factory_.basic().width.setMin(123467890); | |
177 SelectSettings(); | |
178 EXPECT_FALSE(result_.has_value()); | |
179 EXPECT_EQ(constraint_factory_.basic().width.name(), | |
180 result_.failed_constraint_name); | |
181 | |
182 constraint_factory_.Reset(); | |
183 constraint_factory_.basic().width.setMax(0); | |
184 SelectSettings(); | |
185 EXPECT_FALSE(result_.has_value()); | |
186 EXPECT_EQ(constraint_factory_.basic().width.name(), | |
187 result_.failed_constraint_name); | |
188 } | |
189 | |
190 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, | |
191 OverconstrainedOnAspectRatio) { | |
192 constraint_factory_.Reset(); | |
193 constraint_factory_.basic().aspectRatio.setExact(123467890.0); | |
194 SelectSettings(); | |
195 EXPECT_FALSE(result_.has_value()); | |
196 EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(), | |
197 result_.failed_constraint_name); | |
198 | |
199 constraint_factory_.Reset(); | |
200 constraint_factory_.basic().aspectRatio.setMin(123467890.0); | |
201 SelectSettings(); | |
202 EXPECT_FALSE(result_.has_value()); | |
203 EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(), | |
204 result_.failed_constraint_name); | |
205 | |
206 constraint_factory_.Reset(); | |
207 constraint_factory_.basic().aspectRatio.setMax(0.0); | |
hta - Chromium
2017/02/02 00:32:39
This might cause an "illegal parameter" some day.
Guido Urdaneta
2017/02/02 11:35:39
Done. 0.01 works (minimum supported is 0.05).
| |
208 SelectSettings(); | |
209 EXPECT_FALSE(result_.has_value()); | |
210 EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(), | |
211 result_.failed_constraint_name); | |
212 } | |
213 | |
214 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnFrameRate) { | |
215 constraint_factory_.Reset(); | |
216 constraint_factory_.basic().frameRate.setExact(123467890.0); | |
217 SelectSettings(); | |
218 EXPECT_FALSE(result_.has_value()); | |
219 EXPECT_EQ(constraint_factory_.basic().frameRate.name(), | |
220 result_.failed_constraint_name); | |
221 | |
222 constraint_factory_.Reset(); | |
223 constraint_factory_.basic().frameRate.setMin(123467890.0); | |
224 SelectSettings(); | |
225 EXPECT_FALSE(result_.has_value()); | |
226 EXPECT_EQ(constraint_factory_.basic().frameRate.name(), | |
227 result_.failed_constraint_name); | |
228 | |
229 constraint_factory_.Reset(); | |
230 constraint_factory_.basic().frameRate.setMax(0.0); | |
231 SelectSettings(); | |
232 EXPECT_FALSE(result_.has_value()); | |
233 EXPECT_EQ(constraint_factory_.basic().frameRate.name(), | |
234 result_.failed_constraint_name); | |
235 } | |
236 | |
237 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, | |
238 OverconstrainedOnPowerLineFrequency) { | |
239 constraint_factory_.Reset(); | |
240 constraint_factory_.basic().googPowerLineFrequency.setExact(123467890); | |
241 SelectSettings(); | |
242 EXPECT_FALSE(result_.has_value()); | |
243 EXPECT_EQ(constraint_factory_.basic().googPowerLineFrequency.name(), | |
244 result_.failed_constraint_name); | |
245 | |
246 constraint_factory_.Reset(); | |
247 constraint_factory_.basic().googPowerLineFrequency.setMin(123467890); | |
248 SelectSettings(); | |
249 EXPECT_FALSE(result_.has_value()); | |
250 EXPECT_EQ(constraint_factory_.basic().googPowerLineFrequency.name(), | |
251 result_.failed_constraint_name); | |
252 | |
253 constraint_factory_.Reset(); | |
254 constraint_factory_.basic().googPowerLineFrequency.setMax(-1); | |
255 SelectSettings(); | |
256 EXPECT_FALSE(result_.has_value()); | |
257 EXPECT_EQ(constraint_factory_.basic().googPowerLineFrequency.name(), | |
258 result_.failed_constraint_name); | |
259 } | |
260 | |
261 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, Unconstrained) { | |
hta - Chromium
2017/02/02 00:32:39
As a matter of style, I'd put the successful test
Guido Urdaneta
2017/02/02 11:35:39
Done. Changed the order to:
1. Unconstrained
2. Ov
| |
262 constraint_factory_.Reset(); | |
263 SelectSettings(); | |
264 EXPECT_TRUE(result_.has_value()); | |
265 // Should select the default device with closest-to-default settings. | |
266 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
267 EXPECT_EQ(default_device_->facing_mode, result_.settings.facing_mode()); | |
268 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
269 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
270 } | |
271 | |
272 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryDeviceID) { | |
273 constraint_factory_.Reset(); | |
274 constraint_factory_.basic().deviceId.setExact( | |
275 blink::WebString::fromASCII(default_device_->device_id)); | |
276 SelectSettings(); | |
277 EXPECT_TRUE(result_.has_value()); | |
278 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
279 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
280 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
281 EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, | |
282 result_.settings.power_line_frequency()); | |
283 | |
284 constraint_factory_.basic().deviceId.setExact( | |
285 blink::WebString::fromASCII(low_res_device_->device_id)); | |
286 SelectSettings(); | |
287 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
288 EXPECT_EQ(media::VideoCaptureFormat::ToString(*low_res_closest_format_), | |
289 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
290 EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, | |
291 result_.settings.power_line_frequency()); | |
292 | |
293 constraint_factory_.basic().deviceId.setExact( | |
294 blink::WebString::fromASCII(high_res_device_->device_id)); | |
295 SelectSettings(); | |
296 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
297 EXPECT_EQ(media::VideoCaptureFormat::ToString(*high_res_closest_format_), | |
298 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
299 EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, | |
300 result_.settings.power_line_frequency()); | |
301 } | |
302 | |
303 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryFacingMode) { | |
304 constraint_factory_.Reset(); | |
305 constraint_factory_.basic().facingMode.setExact( | |
306 blink::WebString::fromASCII("environment")); | |
307 SelectSettings(); | |
308 EXPECT_TRUE(result_.has_value()); | |
309 EXPECT_EQ(::mojom::FacingMode::ENVIRONMENT, result_.settings.facing_mode()); | |
310 // Only the low-res device supports environment facing mode. Should select | |
311 // default settings for everything else. | |
312 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
313 EXPECT_EQ(media::VideoCaptureFormat::ToString(*low_res_closest_format_), | |
314 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
315 EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, | |
316 result_.settings.power_line_frequency()); | |
317 | |
318 constraint_factory_.basic().facingMode.setExact( | |
319 blink::WebString::fromASCII("user")); | |
320 SelectSettings(); | |
321 EXPECT_TRUE(result_.has_value()); | |
322 EXPECT_EQ(::mojom::FacingMode::USER, result_.settings.facing_mode()); | |
323 // Only the high-res device supports user facing mode. Should select default | |
324 // settings for everything else. | |
325 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
326 EXPECT_EQ(media::VideoCaptureFormat::ToString(*high_res_closest_format_), | |
327 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
328 EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, | |
329 result_.settings.power_line_frequency()); | |
330 } | |
331 | |
332 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryPowerLineFrequency) { | |
333 constraint_factory_.Reset(); | |
334 const media::PowerLineFrequency kPowerLineFrequencies[] = { | |
335 media::PowerLineFrequency::FREQUENCY_50HZ, | |
336 media::PowerLineFrequency::FREQUENCY_60HZ}; | |
337 for (auto power_line_frequency : kPowerLineFrequencies) { | |
338 constraint_factory_.basic().googPowerLineFrequency.setExact( | |
339 static_cast<long>(power_line_frequency)); | |
340 SelectSettings(); | |
341 EXPECT_TRUE(result_.has_value()); | |
342 EXPECT_EQ(power_line_frequency, result_.settings.power_line_frequency()); | |
343 // The default device and settings closest to the default should be | |
344 // selected. | |
345 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
346 EXPECT_EQ(default_device_->facing_mode, result_.settings.facing_mode()); | |
347 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
348 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
349 } | |
350 } | |
351 | |
352 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryExactHeight) { | |
353 constraint_factory_.Reset(); | |
354 const int kHeight = MediaStreamVideoSource::kDefaultHeight; | |
355 constraint_factory_.basic().height.setExact(kHeight); | |
356 SelectSettings(); | |
357 EXPECT_TRUE(result_.has_value()); | |
358 // All devices in |capabilities_| support the requested height. The algorithm | |
359 // should prefer the first device that supports the requested height natively, | |
360 // which is the low-res device. | |
361 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
362 EXPECT_EQ(kHeight, result_.settings.GetHeight()); | |
363 | |
364 const int kLargeHeight = 1500; | |
365 constraint_factory_.basic().height.setExact(kLargeHeight); | |
366 SelectSettings(); | |
367 EXPECT_TRUE(result_.has_value()); | |
368 // Only the high-res device at the highest resolution supports the requested | |
369 // height, even if not natively. | |
370 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
371 EXPECT_EQ(media::VideoCaptureFormat::ToString(*high_res_highest_format_), | |
372 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
373 } | |
374 | |
375 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMinHeight) { | |
376 constraint_factory_.Reset(); | |
377 const int kHeight = MediaStreamVideoSource::kDefaultHeight; | |
378 constraint_factory_.basic().height.setMin(kHeight); | |
379 SelectSettings(); | |
380 EXPECT_TRUE(result_.has_value()); | |
381 // All devices in |capabilities_| support the requested height range. The | |
382 // algorithm should prefer the default device. | |
383 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
384 EXPECT_LE(kHeight, result_.settings.GetHeight()); | |
385 | |
386 const int kLargeHeight = 1500; | |
387 constraint_factory_.basic().height.setMin(kLargeHeight); | |
388 SelectSettings(); | |
389 EXPECT_TRUE(result_.has_value()); | |
390 // Only the high-res device at the highest resolution supports the requested | |
391 // height range. | |
392 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
393 EXPECT_EQ(media::VideoCaptureFormat::ToString(*high_res_highest_format_), | |
394 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
395 } | |
396 | |
397 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMaxHeight) { | |
398 constraint_factory_.Reset(); | |
399 const int kLowHeight = 20; | |
400 constraint_factory_.basic().height.setMax(kLowHeight); | |
401 SelectSettings(); | |
402 EXPECT_TRUE(result_.has_value()); | |
403 // All devices in |capabilities_| support the requested height range. The | |
404 // algorithm should prefer the settings that natively exceed the requested | |
405 // maximum by the lowest amount. In this case it is the low-res device. | |
406 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
407 EXPECT_EQ(media::VideoCaptureFormat::ToString(low_res_device_->formats[0]), | |
408 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
409 } | |
410 | |
411 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryHeightRange) { | |
412 constraint_factory_.Reset(); | |
413 { | |
414 const int kMinHeight = 480; | |
415 const int kMaxHeight = 720; | |
416 constraint_factory_.basic().height.setMin(kMinHeight); | |
417 constraint_factory_.basic().height.setMax(kMaxHeight); | |
418 SelectSettings(); | |
419 EXPECT_TRUE(result_.has_value()); | |
420 EXPECT_GE(result_.settings.GetHeight(), kMinHeight); | |
421 EXPECT_LE(result_.settings.GetHeight(), kMaxHeight); | |
422 // All devices in |capabilities_| support the constraint range. The | |
423 // algorithm should prefer the default device since it has at least one | |
424 // native format (the closest-to-default format) included in the requested | |
425 // range. | |
426 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
427 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
428 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
429 } | |
430 | |
431 { | |
432 const int kMinHeight = 550; | |
433 const int kMaxHeight = 650; | |
434 constraint_factory_.basic().height.setMin(kMinHeight); | |
435 constraint_factory_.basic().height.setMax(kMaxHeight); | |
436 SelectSettings(); | |
437 EXPECT_TRUE(result_.has_value()); | |
438 EXPECT_GE(result_.settings.GetHeight(), kMinHeight); | |
439 EXPECT_LE(result_.settings.GetHeight(), kMaxHeight); | |
440 // In this case, the algorithm should prefer the low-res device since it is | |
441 // the first device with a native format (800x600) included in the requested | |
442 // range. | |
443 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
444 EXPECT_EQ(800, result_.settings.GetWidth()); | |
445 EXPECT_EQ(600, result_.settings.GetHeight()); | |
446 } | |
447 | |
448 { | |
449 const int kMinHeight = 700; | |
450 const int kMaxHeight = 800; | |
451 constraint_factory_.basic().height.setMin(kMinHeight); | |
452 constraint_factory_.basic().height.setMax(kMaxHeight); | |
453 SelectSettings(); | |
454 EXPECT_TRUE(result_.has_value()); | |
455 EXPECT_GE(result_.settings.GetHeight(), kMinHeight); | |
456 EXPECT_LE(result_.settings.GetHeight(), kMaxHeight); | |
457 // In this case, the algorithm should prefer the high-res device since it is | |
458 // the only device with a native format (1280x720) included in the requested | |
459 // range. | |
460 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
461 EXPECT_EQ(1280, result_.settings.GetWidth()); | |
462 EXPECT_EQ(720, result_.settings.GetHeight()); | |
463 } | |
464 } | |
465 | |
466 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, IdealHeight) { | |
467 constraint_factory_.Reset(); | |
468 { | |
469 const int kIdealHeight = 480; | |
470 constraint_factory_.basic().height.setIdeal(kIdealHeight); | |
471 SelectSettings(); | |
472 EXPECT_TRUE(result_.has_value()); | |
473 // The algorithm should select the first device that supports the ideal | |
474 // height natively. | |
475 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
476 EXPECT_EQ(kIdealHeight, result_.settings.GetHeight()); | |
477 } | |
478 | |
479 { | |
480 const int kIdealHeight = 481; | |
481 constraint_factory_.basic().height.setIdeal(kIdealHeight); | |
482 SelectSettings(); | |
483 EXPECT_TRUE(result_.has_value()); | |
484 // In this case, the default device is selected because it can satisfy the | |
485 // ideal at a lower cost than the other devices (500 vs 600 or 720). | |
486 // Note that a native resolution of 480 is further from the ideal than | |
487 // 500 cropped to 480. | |
488 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
489 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
490 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
491 } | |
492 | |
493 { | |
494 const int kIdealHeight = 1079; | |
495 constraint_factory_.basic().height.setIdeal(kIdealHeight); | |
496 SelectSettings(); | |
497 EXPECT_TRUE(result_.has_value()); | |
498 // In this case, the high-res device has two configurations that satisfy | |
499 // the ideal value (1920x1080 and 2304x1536). Select the one with shortest | |
500 // native distance to the ideal value (1920x1080). | |
501 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
502 EXPECT_EQ(1920, result_.settings.GetWidth()); | |
503 EXPECT_EQ(1080, result_.settings.GetHeight()); | |
504 } | |
505 | |
506 { | |
507 const int kIdealHeight = 1200; | |
508 constraint_factory_.basic().height.setIdeal(kIdealHeight); | |
509 SelectSettings(); | |
510 EXPECT_TRUE(result_.has_value()); | |
511 // The algorithm must the select the only device that can satisfy the ideal, | |
512 // which is the high-res device at the highest resolution. | |
513 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
514 EXPECT_EQ(media::VideoCaptureFormat::ToString(*high_res_highest_format_), | |
515 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
516 } | |
517 } | |
518 | |
519 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryExactWidth) { | |
520 constraint_factory_.Reset(); | |
521 const int kWidth = 640; | |
522 constraint_factory_.basic().width.setExact(kWidth); | |
523 SelectSettings(); | |
524 EXPECT_TRUE(result_.has_value()); | |
525 // All devices in |capabilities_| support the requested width. The algorithm | |
526 // should prefer the first device that supports the requested width natively, | |
527 // which is the low-res device. | |
528 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
529 EXPECT_EQ(kWidth, result_.settings.GetWidth()); | |
530 | |
531 const int kLargeWidth = 2000; | |
532 constraint_factory_.basic().width.setExact(kLargeWidth); | |
533 SelectSettings(); | |
534 EXPECT_TRUE(result_.has_value()); | |
535 EXPECT_LE(kLargeWidth, result_.settings.GetWidth()); | |
536 // Only the high-res device at the highest resolution supports the requested | |
537 // width, even if not natively. | |
538 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
539 EXPECT_EQ(media::VideoCaptureFormat::ToString(*high_res_highest_format_), | |
540 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
541 } | |
542 | |
543 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMinWidth) { | |
544 constraint_factory_.Reset(); | |
545 const int kWidth = 640; | |
546 constraint_factory_.basic().width.setMin(kWidth); | |
547 SelectSettings(); | |
548 EXPECT_TRUE(result_.has_value()); | |
549 // All devices in |capabilities_| support the requested width range. The | |
550 // algorithm should prefer the default device at 1000x1000, which is the | |
551 // first configuration that satisfies the minimum width. | |
552 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
553 EXPECT_LE(kWidth, result_.settings.GetWidth()); | |
554 EXPECT_EQ(1000, result_.settings.GetWidth()); | |
555 EXPECT_EQ(1000, result_.settings.GetHeight()); | |
556 | |
557 const int kLargeWidth = 2000; | |
558 constraint_factory_.basic().width.setMin(kLargeWidth); | |
559 SelectSettings(); | |
560 EXPECT_TRUE(result_.has_value()); | |
561 // Only the high-res device at the highest resolution supports the requested | |
562 // minimum width. | |
563 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
564 EXPECT_LE(kLargeWidth, result_.settings.GetWidth()); | |
565 EXPECT_EQ(media::VideoCaptureFormat::ToString(*high_res_highest_format_), | |
566 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
567 } | |
568 | |
569 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMaxWidth) { | |
570 constraint_factory_.Reset(); | |
571 const int kLowWidth = 30; | |
572 constraint_factory_.basic().width.setMax(kLowWidth); | |
573 SelectSettings(); | |
574 EXPECT_TRUE(result_.has_value()); | |
575 // All devices in |capabilities_| support the requested width range. The | |
576 // algorithm should prefer the settings that natively exceed the requested | |
577 // maximum by the lowest amount. In this case it is the low-res device at its | |
578 // lowest resolution. | |
579 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
580 EXPECT_EQ(media::VideoCaptureFormat::ToString(low_res_device_->formats[0]), | |
581 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
582 } | |
583 | |
584 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryWidthRange) { | |
585 constraint_factory_.Reset(); | |
586 { | |
587 const int kMinWidth = 640; | |
588 const int kMaxWidth = 1280; | |
589 constraint_factory_.basic().width.setMin(kMinWidth); | |
590 constraint_factory_.basic().width.setMax(kMaxWidth); | |
591 SelectSettings(); | |
592 EXPECT_TRUE(result_.has_value()); | |
593 EXPECT_GE(result_.settings.GetWidth(), kMinWidth); | |
594 EXPECT_LE(result_.settings.GetWidth(), kMaxWidth); | |
595 // All devices in |capabilities_| support the constraint range. The | |
596 // algorithm should prefer the default device since it has at least one | |
597 // native format (1000x1000) included in the requested range. | |
598 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
599 EXPECT_EQ(1000, result_.settings.GetWidth()); | |
600 EXPECT_EQ(1000, result_.settings.GetHeight()); | |
601 } | |
602 | |
603 { | |
604 const int kMinWidth = 750; | |
605 const int kMaxWidth = 850; | |
606 constraint_factory_.basic().width.setMin(kMinWidth); | |
607 constraint_factory_.basic().width.setMax(kMaxWidth); | |
608 SelectSettings(); | |
609 EXPECT_TRUE(result_.has_value()); | |
610 EXPECT_GE(result_.settings.GetWidth(), kMinWidth); | |
611 EXPECT_LE(result_.settings.GetWidth(), kMaxWidth); | |
612 // In this case, the algorithm should prefer the low-res device since it is | |
613 // the first device with a native format (800x600) included in the requested | |
614 // range. | |
615 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
616 EXPECT_EQ(800, result_.settings.GetWidth()); | |
617 EXPECT_EQ(600, result_.settings.GetHeight()); | |
618 } | |
619 | |
620 { | |
621 const int kMinWidth = 1900; | |
622 const int kMaxWidth = 2000; | |
623 constraint_factory_.basic().width.setMin(kMinWidth); | |
624 constraint_factory_.basic().width.setMax(kMaxWidth); | |
625 SelectSettings(); | |
626 EXPECT_TRUE(result_.has_value()); | |
627 EXPECT_GE(result_.settings.GetWidth(), kMinWidth); | |
628 EXPECT_LE(result_.settings.GetWidth(), kMaxWidth); | |
629 // In this case, the algorithm should prefer the high-res device since it is | |
630 // the only device with a native format (1920x1080) included in the | |
631 // requested range. | |
632 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
633 EXPECT_EQ(1920, result_.settings.GetWidth()); | |
634 EXPECT_EQ(1080, result_.settings.GetHeight()); | |
635 } | |
636 } | |
637 | |
638 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, IdealWidth) { | |
639 constraint_factory_.Reset(); | |
640 { | |
641 const int kIdealWidth = 320; | |
642 constraint_factory_.basic().width.setIdeal(kIdealWidth); | |
643 SelectSettings(); | |
644 EXPECT_TRUE(result_.has_value()); | |
645 // The algorithm should select the first device that supports the ideal | |
646 // width natively, which is the low-res device at 320x240. | |
647 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
648 EXPECT_EQ(kIdealWidth, result_.settings.GetWidth()); | |
649 } | |
650 | |
651 { | |
652 const int kIdealWidth = 321; | |
653 constraint_factory_.basic().width.setIdeal(kIdealWidth); | |
654 SelectSettings(); | |
655 EXPECT_TRUE(result_.has_value()); | |
656 // In this case, the default device is selected because it can satisfy the | |
657 // ideal at a lower cost than the other devices (500 vs 640). | |
658 // Note that a native resolution of 320 is further from the ideal value of | |
659 // 321 than 500 cropped to 321. | |
660 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
661 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
662 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
663 } | |
664 | |
665 { | |
666 const int kIdealWidth = 2000; | |
667 constraint_factory_.basic().width.setIdeal(kIdealWidth); | |
668 SelectSettings(); | |
669 EXPECT_TRUE(result_.has_value()); | |
670 // The algorithm must the select the only device that can satisfy the ideal. | |
671 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
672 EXPECT_EQ(media::VideoCaptureFormat::ToString(*high_res_highest_format_), | |
673 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
674 } | |
675 | |
676 { | |
677 const int kIdealWidth = 3000; | |
678 constraint_factory_.basic().width.setIdeal(kIdealWidth); | |
679 SelectSettings(); | |
680 EXPECT_TRUE(result_.has_value()); | |
681 // The algorithm must the select the device and setting with less distance | |
682 // to the ideal. | |
683 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
684 EXPECT_EQ(media::VideoCaptureFormat::ToString(*high_res_highest_format_), | |
685 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
686 } | |
687 } | |
688 | |
689 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryExactFrameRate) { | |
690 constraint_factory_.Reset(); | |
691 const double kFrameRate = MediaStreamVideoSource::kDefaultFrameRate; | |
692 constraint_factory_.basic().frameRate.setExact(kFrameRate); | |
693 SelectSettings(); | |
694 EXPECT_TRUE(result_.has_value()); | |
695 // All devices in |capabilities_| support the requested frame rate. The | |
696 // algorithm should prefer the first device that supports the requested frame | |
697 // rate natively, which is the low-res device at 640x480x30Hz. | |
698 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
699 EXPECT_EQ(kFrameRate, result_.settings.GetFrameRate()); | |
700 EXPECT_EQ(640, result_.settings.GetWidth()); | |
701 EXPECT_EQ(480, result_.settings.GetHeight()); | |
702 | |
703 const double kLargeFrameRate = 50; | |
704 constraint_factory_.basic().frameRate.setExact(kLargeFrameRate); | |
705 SelectSettings(); | |
706 EXPECT_TRUE(result_.has_value()); | |
707 // Only the high-res device supports the requested frame rate, even if not | |
708 // natively. The least expensive configuration that supports the requested | |
709 // frame rate is 1280x720x60Hz. | |
710 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
711 EXPECT_EQ(60.0, result_.settings.GetFrameRate()); | |
712 EXPECT_EQ(1280, result_.settings.GetWidth()); | |
713 EXPECT_EQ(720, result_.settings.GetHeight()); | |
714 } | |
715 | |
716 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMinFrameRate) { | |
717 constraint_factory_.Reset(); | |
718 const double kFrameRate = MediaStreamVideoSource::kDefaultFrameRate; | |
719 constraint_factory_.basic().frameRate.setMin(kFrameRate); | |
720 SelectSettings(); | |
721 EXPECT_TRUE(result_.has_value()); | |
722 // All devices in |capabilities_| support the requested frame-rate range. The | |
723 // algorithm should prefer the default device. | |
724 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
725 // The format closest to the default satisfies the constraint. | |
726 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
727 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
728 | |
729 const double kLargeFrameRate = 50; | |
730 constraint_factory_.basic().frameRate.setMin(kLargeFrameRate); | |
731 SelectSettings(); | |
732 EXPECT_TRUE(result_.has_value()); | |
733 // Only the high-res device supports the requested frame-rate range. | |
734 // The least expensive configuration is 1280x720x60Hz. | |
735 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
736 EXPECT_LE(kLargeFrameRate, result_.settings.GetFrameRate()); | |
737 EXPECT_EQ(1280, result_.settings.GetWidth()); | |
738 EXPECT_EQ(720, result_.settings.GetHeight()); | |
739 } | |
740 | |
741 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMaxFrameRate) { | |
742 constraint_factory_.Reset(); | |
743 const double kLowFrameRate = 10; | |
744 constraint_factory_.basic().frameRate.setMax(kLowFrameRate); | |
745 SelectSettings(); | |
746 EXPECT_TRUE(result_.has_value()); | |
747 // All devices in |capabilities_| support the requested frame-rate range. The | |
748 // algorithm should prefer the settings that natively exceed the requested | |
749 // maximum by the lowest amount. In this case it is the high-res device with | |
750 // default resolution . | |
751 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
752 EXPECT_EQ(kLowFrameRate, result_.settings.GetFrameRate()); | |
753 EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, | |
754 result_.settings.GetHeight()); | |
755 EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result_.settings.GetWidth()); | |
756 } | |
757 | |
758 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryFrameRateRange) { | |
759 constraint_factory_.Reset(); | |
760 { | |
761 const double kMinFrameRate = 10; | |
762 const double kMaxFrameRate = 40; | |
763 constraint_factory_.basic().frameRate.setMin(kMinFrameRate); | |
764 constraint_factory_.basic().frameRate.setMax(kMaxFrameRate); | |
765 SelectSettings(); | |
766 EXPECT_TRUE(result_.has_value()); | |
767 EXPECT_LE(kMinFrameRate, result_.settings.GetFrameRate()); | |
768 EXPECT_GE(kMaxFrameRate, result_.settings.GetFrameRate()); | |
769 // All devices in |capabilities_| support the constraint range. The | |
770 // algorithm should prefer the default device since its closest-to-default | |
771 // format has a frame rate included in the requested range. | |
772 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
773 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
774 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
775 } | |
776 | |
777 { | |
778 const double kMinFrameRate = 25; | |
779 const double kMaxFrameRate = 35; | |
780 constraint_factory_.basic().frameRate.setMin(kMinFrameRate); | |
781 constraint_factory_.basic().frameRate.setMax(kMaxFrameRate); | |
782 SelectSettings(); | |
783 EXPECT_TRUE(result_.has_value()); | |
784 EXPECT_GE(result_.settings.GetFrameRate(), kMinFrameRate); | |
785 EXPECT_LE(result_.settings.GetFrameRate(), kMaxFrameRate); | |
786 // In this case, the algorithm should prefer the low-res device since it is | |
787 // the first device with a native frame rate included in the requested | |
788 // range. The default resolution should be preferred as secondary criterion. | |
789 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
790 EXPECT_EQ(media::VideoCaptureFormat::ToString(*low_res_closest_format_), | |
791 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
792 } | |
793 | |
794 { | |
795 const double kMinFrameRate = 50; | |
796 const double kMaxFrameRate = 70; | |
797 constraint_factory_.basic().frameRate.setMin(kMinFrameRate); | |
798 constraint_factory_.basic().frameRate.setMax(kMaxFrameRate); | |
799 SelectSettings(); | |
800 EXPECT_TRUE(result_.has_value()); | |
801 EXPECT_GE(result_.settings.GetFrameRate(), kMinFrameRate); | |
802 EXPECT_LE(result_.settings.GetFrameRate(), kMaxFrameRate); | |
803 // In this case, the algorithm should prefer the high-res device since it is | |
804 // the only device with a native format included in the requested range. | |
805 // The 1280x720 resolution should be selected due to closeness to default | |
806 // settings, which is the second tie-breaker criterion that applies. | |
807 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
808 EXPECT_EQ(1280, result_.settings.GetWidth()); | |
809 EXPECT_EQ(720, result_.settings.GetHeight()); | |
810 } | |
811 } | |
812 | |
813 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, IdealFrameRate) { | |
814 constraint_factory_.Reset(); | |
815 { | |
816 const double kIdealFrameRate = MediaStreamVideoSource::kDefaultFrameRate; | |
817 constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate); | |
818 SelectSettings(); | |
819 EXPECT_TRUE(result_.has_value()); | |
820 // The algorithm should select the first configuration that supports the | |
821 // ideal frame rate natively, which is the low-res device. Default | |
822 // resolution should be selected as secondary criterion. | |
823 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
824 EXPECT_EQ(media::VideoCaptureFormat::ToString(*low_res_closest_format_), | |
825 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
826 } | |
827 | |
828 { | |
829 const double kIdealFrameRate = 31; | |
830 constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate); | |
831 SelectSettings(); | |
832 EXPECT_TRUE(result_.has_value()); | |
833 // In this case, the default device is selected because it can satisfy the | |
834 // ideal at a lower cost than the other devices (40 vs 60). | |
835 // Note that a native frame rate of 30 is further from the ideal than | |
836 // 31 adjusted to 30. | |
837 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
838 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
839 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
840 } | |
841 | |
842 { | |
843 const double kIdealFrameRate = 55; | |
844 constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate); | |
845 SelectSettings(); | |
846 EXPECT_TRUE(result_.has_value()); | |
847 // The high-res device format 1280x720x60.0 must be selected because its | |
848 // frame rate can satisfy the ideal frame rate and has resolution closest | |
849 // to the default. | |
850 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
851 EXPECT_EQ(1280, result_.settings.GetWidth()); | |
852 EXPECT_EQ(720, result_.settings.GetHeight()); | |
853 EXPECT_EQ(60, result_.settings.GetFrameRate()); | |
854 } | |
855 | |
856 { | |
857 const double kIdealFrameRate = 100; | |
858 constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate); | |
859 SelectSettings(); | |
860 EXPECT_TRUE(result_.has_value()); | |
861 // The algorithm must select settings with frame rate closest to the ideal. | |
862 // The high-res device format 1280x720x60.0 must be selected because its | |
863 // frame rate it closest to the ideal value and it has resolution closest to | |
864 // the default. | |
865 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
866 EXPECT_EQ(1280, result_.settings.GetWidth()); | |
867 EXPECT_EQ(720, result_.settings.GetHeight()); | |
868 EXPECT_EQ(60, result_.settings.GetFrameRate()); | |
869 } | |
870 } | |
871 | |
872 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryExactAspectRatio) { | |
873 constraint_factory_.Reset(); | |
874 const double kAspectRatio = 4.0 / 3.0; | |
875 constraint_factory_.basic().aspectRatio.setExact(kAspectRatio); | |
876 SelectSettings(); | |
877 EXPECT_TRUE(result_.has_value()); | |
878 double min_width = 1.0; | |
879 double max_width = result_.settings.GetWidth(); | |
880 double min_height = 1.0; | |
881 double max_height = result_.settings.GetHeight(); | |
882 double min_aspect_ratio = min_width / max_height; | |
883 double max_aspect_ratio = max_width / min_height; | |
884 // The requested aspect ratio must be within the supported range. | |
885 EXPECT_GE(kAspectRatio, min_aspect_ratio); | |
886 EXPECT_LE(kAspectRatio, max_aspect_ratio); | |
887 // All devices in |capabilities_| support the requested aspect ratio. | |
888 // The algorithm should prefer the first device that supports the requested | |
889 // aspect ratio. | |
890 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
891 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
892 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
893 | |
894 const long kMinWidth = 500; | |
895 const long kMaxWidth = 1000; | |
896 const long kMaxHeight = 500; | |
897 constraint_factory_.basic().height.setMax(kMaxHeight); | |
898 constraint_factory_.basic().width.setMin(kMinWidth); | |
899 constraint_factory_.basic().width.setMax(kMaxWidth); | |
900 constraint_factory_.basic().aspectRatio.setExact(kAspectRatio); | |
901 SelectSettings(); | |
902 EXPECT_TRUE(result_.has_value()); | |
903 min_width = std::max(1L, kMinWidth); | |
904 max_width = std::min(result_.settings.GetWidth(), kMaxWidth); | |
905 min_height = 1.0; | |
906 max_height = std::min(result_.settings.GetHeight(), kMaxHeight); | |
907 min_aspect_ratio = min_width / max_height; | |
908 max_aspect_ratio = max_width / min_height; | |
909 // The requested aspect ratio must be within the supported range. | |
910 EXPECT_GE(kAspectRatio, min_aspect_ratio); | |
911 EXPECT_LE(kAspectRatio, max_aspect_ratio); | |
912 // The default device can support the requested aspect ratio with the default | |
913 // settings (500x500) using cropping. | |
914 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
915 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
916 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
917 | |
918 const long kMinHeight = 480; | |
919 constraint_factory_.basic().height.setMin(kMinHeight); | |
920 constraint_factory_.basic().height.setMax(kMaxHeight); | |
921 constraint_factory_.basic().width.setMin(kMinWidth); | |
922 constraint_factory_.basic().width.setMax(kMaxWidth); | |
923 constraint_factory_.basic().aspectRatio.setExact(kAspectRatio); | |
924 SelectSettings(); | |
925 EXPECT_TRUE(result_.has_value()); | |
926 min_width = std::max(1L, kMinWidth); | |
927 max_width = std::min(result_.settings.GetWidth(), kMaxWidth); | |
928 min_height = std::max(1L, kMinHeight); | |
929 max_height = std::min(result_.settings.GetHeight(), kMaxHeight); | |
930 min_aspect_ratio = min_width / max_height; | |
931 max_aspect_ratio = max_width / min_height; | |
932 // The requested aspect ratio must be within the supported range. | |
933 EXPECT_GE(kAspectRatio, min_aspect_ratio); | |
934 EXPECT_LE(kAspectRatio, max_aspect_ratio); | |
935 // Given resolution constraints, the default device with closest-to-default | |
936 // settings cannot satisfy the required aspect ratio. | |
937 // The first device that can do it is the low-res device with a native | |
938 // resolution of 640x480. Higher resolutions for the default device are more | |
939 // penalized by the constraints than the default native resolution of the | |
940 // low-res device. | |
941 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
942 EXPECT_EQ(media::VideoCaptureFormat::ToString(*low_res_closest_format_), | |
943 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
944 } | |
945 | |
946 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMinAspectRatio) { | |
947 constraint_factory_.Reset(); | |
948 const double kAspectRatio = 4.0 / 3.0; | |
949 constraint_factory_.basic().aspectRatio.setMin(kAspectRatio); | |
950 SelectSettings(); | |
951 EXPECT_TRUE(result_.has_value()); | |
952 double max_width = result_.settings.GetWidth(); | |
953 double min_height = 1.0; | |
954 double max_aspect_ratio = max_width / min_height; | |
955 // Minimum constraint aspect ratio must be less than or equal to the maximum | |
956 // supported by the source. | |
957 EXPECT_LE(kAspectRatio, max_aspect_ratio); | |
958 // All devices in |capabilities_| support the requested aspect-ratio range. | |
959 // The algorithm should prefer the first device that supports the requested | |
960 // aspect-ratio range, which in this case is the default device. | |
961 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
962 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
963 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
964 | |
965 const long kMinWidth = 500; | |
966 const long kMaxWidth = 1000; | |
967 const long kMinHeight = 480; | |
968 const long kMaxHeight = 500; | |
969 constraint_factory_.basic().width.setMin(kMinWidth); | |
970 constraint_factory_.basic().width.setMax(kMaxWidth); | |
971 constraint_factory_.basic().height.setMin(kMinHeight); | |
972 constraint_factory_.basic().height.setMax(kMaxHeight); | |
973 constraint_factory_.basic().aspectRatio.setMin(kAspectRatio); | |
974 SelectSettings(); | |
975 EXPECT_TRUE(result_.has_value()); | |
976 max_width = std::min(result_.settings.GetWidth(), kMaxWidth); | |
977 min_height = std::max(1L, kMinHeight); | |
978 max_aspect_ratio = max_width / min_height; | |
979 // Minimum constraint aspect ratio must be less than or equal to the minimum | |
980 // supported by the source. | |
981 EXPECT_LE(kAspectRatio, max_aspect_ratio); | |
982 // Given resolution constraints, the default device with closest-to-default | |
983 // settings cannot satisfy the required minimum aspect ratio (maximum would | |
984 // be 500/480). The first device that can is the low-res device with a native | |
985 // resolution of 640x480. | |
986 // Higher resolutions for the default device are more penalized by the | |
987 // constraints than the default native resolution of the low-res device. | |
988 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
989 EXPECT_EQ(media::VideoCaptureFormat::ToString(*low_res_closest_format_), | |
990 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
991 } | |
992 | |
993 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMaxAspectRatio) { | |
994 constraint_factory_.Reset(); | |
995 const double kAspectRatio = 0.5; | |
996 constraint_factory_.basic().aspectRatio.setMax(kAspectRatio); | |
997 SelectSettings(); | |
998 EXPECT_TRUE(result_.has_value()); | |
999 double min_width = 1.0; | |
1000 double max_height = result_.settings.GetHeight(); | |
1001 double min_aspect_ratio = min_width / max_height; | |
1002 // Minimum constraint aspect ratio must be less than or equal to the maximum | |
1003 // supported by the source. | |
1004 EXPECT_GE(kAspectRatio, min_aspect_ratio); | |
1005 // All devices in |capabilities_| support the requested aspect-ratio range. | |
1006 // The algorithm should prefer the first device that supports the requested | |
1007 // aspect-ratio range, which in this case is the default device. | |
1008 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
1009 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
1010 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
1011 | |
1012 const long kExactWidth = 360; | |
1013 const long kMinHeight = 360; | |
1014 const long kMaxHeight = 720; | |
1015 constraint_factory_.basic().width.setExact(kExactWidth); | |
1016 constraint_factory_.basic().height.setMin(kMinHeight); | |
1017 constraint_factory_.basic().height.setMax(kMaxHeight); | |
1018 constraint_factory_.basic().aspectRatio.setMax(kAspectRatio); | |
1019 SelectSettings(); | |
1020 EXPECT_TRUE(result_.has_value()); | |
1021 min_width = std::max(1L, kExactWidth); | |
1022 max_height = std::min(result_.settings.GetHeight(), kMaxHeight); | |
1023 min_aspect_ratio = min_width / max_height; | |
1024 // Minimum constraint aspect ratio must be less than or equal to the minimum | |
1025 // supported by the source. | |
1026 EXPECT_GE(kAspectRatio, min_aspect_ratio); | |
1027 // Given resolution constraints, the default device with closest-to-default | |
1028 // settings cannot satisfy the required maximum aspect ratio (maximum would | |
1029 // be 360/500). | |
1030 // The high-res device with a native resolution of 1280x720 can support | |
1031 // 360x720 with cropping with less penalty than the default device at | |
1032 // 1000x1000. | |
1033 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
1034 EXPECT_EQ(1280, result_.settings.GetWidth()); | |
1035 EXPECT_EQ(720, result_.settings.GetHeight()); | |
1036 } | |
1037 | |
1038 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryAspectRatioRange) { | |
1039 constraint_factory_.Reset(); | |
1040 { | |
1041 const double kMinAspectRatio = 0.5; | |
1042 const double kMaxAspectRatio = 1.0; | |
1043 | |
1044 constraint_factory_.basic().aspectRatio.setMin(kMinAspectRatio); | |
1045 constraint_factory_.basic().aspectRatio.setMax(kMaxAspectRatio); | |
1046 SelectSettings(); | |
1047 EXPECT_TRUE(result_.has_value()); | |
1048 double min_width = 1.0; | |
1049 double max_width = result_.settings.GetWidth(); | |
1050 double min_height = 1.0; | |
1051 double max_height = result_.settings.GetHeight(); | |
1052 double min_aspect_ratio = min_width / max_height; | |
1053 double max_aspect_ratio = max_width / min_height; | |
1054 // Constraint aspect-ratio range must have nonempty intersection with | |
1055 // supported range. | |
1056 EXPECT_LE(kMinAspectRatio, max_aspect_ratio); | |
1057 EXPECT_GE(kMaxAspectRatio, min_aspect_ratio); | |
1058 // All devices in |capabilities_| support the requested aspect-ratio range. | |
1059 // The algorithm should prefer the first device that supports the requested | |
1060 // aspect-ratio range, which in this case is the default device. | |
1061 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
1062 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
1063 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
1064 } | |
1065 | |
1066 { | |
1067 const double kMinAspectRatio = 3.0; | |
1068 const double kMaxAspectRatio = 4.0; | |
1069 | |
1070 const long kExactHeight = 600; | |
1071 constraint_factory_.Reset(); | |
1072 constraint_factory_.basic().height.setMin(kExactHeight); | |
1073 constraint_factory_.basic().aspectRatio.setMin(kMinAspectRatio); | |
1074 constraint_factory_.basic().aspectRatio.setMax(kMaxAspectRatio); | |
1075 SelectSettings(); | |
1076 EXPECT_TRUE(result_.has_value()); | |
1077 double min_width = 1.0; | |
1078 double max_width = result_.settings.GetWidth(); | |
1079 double min_height = 1.0; | |
1080 double max_height = result_.settings.GetHeight(); | |
1081 double min_aspect_ratio = min_width / max_height; | |
1082 double max_aspect_ratio = max_width / min_height; | |
1083 // Constraint aspect-ratio range must have nonempty intersection with | |
1084 // supported range. | |
1085 EXPECT_LE(kMinAspectRatio, max_aspect_ratio); | |
1086 EXPECT_GE(kMaxAspectRatio, min_aspect_ratio); | |
1087 // The only device that supports the resolution and aspect ratio constraint | |
1088 // is the high-res device. The 1920x1080 is the least expensive format. | |
1089 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
1090 EXPECT_EQ(1920, result_.settings.GetWidth()); | |
1091 EXPECT_EQ(1080, result_.settings.GetHeight()); | |
1092 } | |
1093 } | |
1094 | |
1095 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, IdealAspectRatio) { | |
1096 constraint_factory_.Reset(); | |
1097 { | |
1098 const double kIdealAspectRatio = 0.5; | |
1099 constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); | |
1100 SelectSettings(); | |
1101 EXPECT_TRUE(result_.has_value()); | |
1102 double min_width = 1.0; | |
1103 double max_width = result_.settings.GetWidth(); | |
1104 double min_height = 1.0; | |
1105 double max_height = result_.settings.GetHeight(); | |
1106 double min_aspect_ratio = min_width / max_height; | |
1107 double max_aspect_ratio = max_width / min_height; | |
1108 // All devices in |capabilities_| support the ideal aspect-ratio. | |
1109 // The algorithm should prefer the default device with closest-to-default | |
1110 // settings. | |
1111 EXPECT_LE(kIdealAspectRatio, max_aspect_ratio); | |
1112 EXPECT_GE(kIdealAspectRatio, min_aspect_ratio); | |
1113 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
1114 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
1115 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
1116 } | |
1117 | |
1118 { | |
1119 const double kIdealAspectRatio = 1500.0; | |
1120 constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); | |
1121 SelectSettings(); | |
1122 EXPECT_TRUE(result_.has_value()); | |
1123 // The only device that supports the ideal aspect ratio is the high-res | |
1124 // device. The least expensive way to support it with the 1920x1080 format | |
1125 // cropped to 1500x1. | |
1126 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
1127 EXPECT_EQ(1920, result_.settings.GetWidth()); | |
1128 EXPECT_EQ(1080, result_.settings.GetHeight()); | |
1129 } | |
1130 | |
1131 { | |
1132 const double kIdealAspectRatio = 2000.0; | |
1133 constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); | |
1134 SelectSettings(); | |
1135 EXPECT_TRUE(result_.has_value()); | |
1136 // The only device that supports the ideal aspect ratio is the high-res | |
1137 // device with its highest resolution, cropped to 2000x1. | |
1138 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
1139 EXPECT_EQ(media::VideoCaptureFormat::ToString(*high_res_highest_format_), | |
1140 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
1141 } | |
1142 | |
1143 { | |
1144 const double kIdealAspectRatio = 4000.0; | |
1145 constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); | |
1146 SelectSettings(); | |
1147 EXPECT_TRUE(result_.has_value()); | |
1148 // The configuration closest to the ideal aspect ratio is is the high-res | |
1149 // device with its highest resolution, cropped to 2304x1. | |
1150 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
1151 EXPECT_EQ(media::VideoCaptureFormat::ToString(*high_res_highest_format_), | |
1152 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
1153 } | |
1154 | |
1155 { | |
1156 const double kIdealAspectRatio = 2.0; | |
1157 constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); | |
1158 constraint_factory_.basic().height.setExact(400); | |
1159 SelectSettings(); | |
1160 EXPECT_TRUE(result_.has_value()); | |
1161 // The first device to support the ideal aspect ratio and the resolution | |
1162 // constraint is the low-res device. The 800x600 format cropped to 800x400 | |
1163 // is the lest expensive way to achieve it. | |
1164 EXPECT_EQ(low_res_device_->device_id, result_.settings.device_id()); | |
1165 EXPECT_EQ(800, result_.settings.GetWidth()); | |
1166 EXPECT_EQ(600, result_.settings.GetHeight()); | |
1167 } | |
1168 | |
1169 { | |
1170 const double kIdealAspectRatio = 3.0; | |
1171 constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); | |
1172 constraint_factory_.basic().height.setExact(400); | |
1173 SelectSettings(); | |
1174 EXPECT_TRUE(result_.has_value()); | |
1175 // The only device that supports the ideal aspect ratio and the resolution | |
1176 // constraint is the high-res device. The 1280x720 cropped to 1200x400 is | |
1177 // the lest expensive way to achieve it. | |
1178 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
1179 EXPECT_EQ(1280, result_.settings.GetWidth()); | |
1180 EXPECT_EQ(720, result_.settings.GetHeight()); | |
1181 } | |
1182 } | |
1183 | |
1184 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, AdvancedExactResolution) { | |
1185 { | |
1186 constraint_factory_.Reset(); | |
1187 blink::WebMediaTrackConstraintSet& advanced1 = | |
1188 constraint_factory_.AddAdvanced(); | |
1189 advanced1.width.setExact(4000); | |
1190 advanced1.height.setExact(4000); | |
1191 blink::WebMediaTrackConstraintSet& advanced2 = | |
1192 constraint_factory_.AddAdvanced(); | |
1193 advanced2.width.setExact(3000); | |
1194 advanced2.height.setExact(3000); | |
1195 SelectSettings(); | |
1196 // No device supports the advanced constraint sets. | |
1197 // Tie-breaker rule that applies is closeness to default settings. | |
1198 EXPECT_EQ(default_device_->device_id, result_.settings.device_id()); | |
1199 EXPECT_EQ(media::VideoCaptureFormat::ToString(*default_closest_format_), | |
1200 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
1201 | |
1202 blink::WebMediaTrackConstraintSet& advanced3 = | |
1203 constraint_factory_.AddAdvanced(); | |
1204 advanced3.width.setExact(1920); | |
1205 advanced3.height.setExact(1080); | |
1206 SelectSettings(); | |
1207 EXPECT_TRUE(result_.has_value()); | |
1208 // The high-res device natively supports the third advanced constraint set | |
1209 // and should be selected. | |
1210 // First tie-breaker rule that applies is support for advanced constraints | |
1211 // that appear first. Second tie-breaker rule is custom distance to advanced | |
1212 // constraint sets that appear first. | |
1213 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
1214 EXPECT_EQ(1920, result_.settings.GetWidth()); | |
1215 EXPECT_EQ(1080, result_.settings.GetHeight()); | |
1216 | |
1217 blink::WebMediaTrackConstraintSet& advanced4 = | |
1218 constraint_factory_.AddAdvanced(); | |
1219 advanced4.width.setExact(640); | |
1220 advanced4.height.setExact(480); | |
1221 SelectSettings(); | |
1222 EXPECT_TRUE(result_.has_value()); | |
1223 // First tie-breaker rule that applies is support for advanced constraints | |
1224 // that appear first, which leaves out configurations that only support the | |
1225 // fourth advanced constraint set in favor of configurations that support | |
1226 // the third set. | |
1227 // Second tie-breaker rule is custom distance to advanced constraint sets | |
1228 // that appear first. | |
1229 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
1230 EXPECT_EQ(1920, result_.settings.GetWidth()); | |
1231 EXPECT_EQ(1080, result_.settings.GetHeight()); | |
1232 | |
1233 constraint_factory_.basic().width.setIdeal(800); | |
1234 constraint_factory_.basic().height.setIdeal(600); | |
1235 SelectSettings(); | |
1236 EXPECT_TRUE(result_.has_value()); | |
1237 // The ideal value is supported by the same configuration, so nothing | |
1238 // changes. | |
1239 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
1240 EXPECT_EQ(1920, result_.settings.GetWidth()); | |
1241 EXPECT_EQ(1080, result_.settings.GetHeight()); | |
1242 | |
1243 constraint_factory_.basic().width.setIdeal(2000); | |
1244 constraint_factory_.basic().height.setIdeal(1500); | |
1245 SelectSettings(); | |
1246 EXPECT_TRUE(result_.has_value()); | |
1247 // The closest configuration to the ideal resolution is the high-res device | |
1248 // at the highest resolution. | |
1249 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
1250 EXPECT_EQ(media::VideoCaptureFormat::ToString(*high_res_highest_format_), | |
1251 media::VideoCaptureFormat::ToString(result_.settings.format())); | |
1252 } | |
1253 } | |
1254 | |
1255 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, | |
1256 AdvancedResolutionAndFrameRate) { | |
1257 { | |
1258 constraint_factory_.Reset(); | |
1259 blink::WebMediaTrackConstraintSet& advanced1 = | |
1260 constraint_factory_.AddAdvanced(); | |
1261 advanced1.width.setExact(1920); | |
1262 advanced1.height.setExact(1080); | |
1263 blink::WebMediaTrackConstraintSet& advanced2 = | |
1264 constraint_factory_.AddAdvanced(); | |
1265 advanced2.frameRate.setExact(60.0); | |
1266 blink::WebMediaTrackConstraintSet& advanced3 = | |
1267 constraint_factory_.AddAdvanced(); | |
1268 advanced3.width.setExact(2304); | |
1269 advanced3.height.setExact(1536); | |
1270 SelectSettings(); | |
1271 EXPECT_TRUE(result_.has_value()); | |
1272 // The high-res device is the only one that satisfies the first advanced | |
1273 // set. 2304x1536x10.0 satisfies sets 1 and 3, while 1920x1080x60.0 | |
1274 // satisfies sets 1, and 2. The latter must be selected, regardless of | |
1275 // any other criteria. | |
1276 EXPECT_EQ(high_res_device_->device_id, result_.settings.device_id()); | |
1277 EXPECT_EQ(1920, result_.settings.GetWidth()); | |
1278 EXPECT_EQ(1080, result_.settings.GetHeight()); | |
1279 EXPECT_EQ(60.0, result_.settings.GetFrameRate()); | |
1280 } | |
1281 } | |
1282 | |
1283 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, NoDevicesNoConstraints) { | |
1284 VideoCaptureCapabilities capabilities; | |
1285 constraint_factory_.Reset(); | |
1286 auto result = SelectVideoCaptureSourceSettings( | |
1287 capabilities, constraint_factory_.CreateWebMediaConstraints()); | |
1288 EXPECT_FALSE(result.has_value()); | |
1289 EXPECT_TRUE(std::string(result.failed_constraint_name).empty()); | |
1290 } | |
1291 | |
1292 TEST_F(MediaStreamConstraintsUtilVideoSourceTest, NoDevicesWithConstraints) { | |
1293 VideoCaptureCapabilities capabilities; | |
1294 constraint_factory_.Reset(); | |
1295 constraint_factory_.basic().height.setExact(100); | |
1296 auto result = SelectVideoCaptureSourceSettings( | |
1297 capabilities, constraint_factory_.CreateWebMediaConstraints()); | |
1298 EXPECT_FALSE(result.has_value()); | |
1299 EXPECT_TRUE(std::string(result.failed_constraint_name).empty()); | |
1300 } | |
1301 | |
1302 } // namespace content | |
OLD | NEW |