Commit bd09ecb2 authored by Guido Urdaneta's avatar Guido Urdaneta Committed by Commit Bot

Rewrite SelectSettingsVideoDeviceCapture()

The rewrite simplifies the code and serves as preparation for addition
of resizeMode support.
The only behavior change is in tie-breaking among candidates that are
equally good at satisfying constraints.
The new approach uses a single tie braking distance that combines the
ideal value and the allowed range, whereas the old code used separate
distances for allowed ranges and ideal values.

This CL is in preparation for resizeMode support.

Bug: 854980
Change-Id: Ie90d5aa8fe029ca1848bf19c232523bab91beadf
Reviewed-on: https://chromium-review.googlesource.com/c/1277797Reviewed-by: default avatarHenrik Boström <hbos@chromium.org>
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600365}
parent 6aadaadb
......@@ -59,11 +59,14 @@ struct CONTENT_EXPORT VideoDeviceCaptureCapabilities {
// but it is customized to account for differences between sources and tracks,
// and to break ties when multiple source settings are equally good according to
// the spec algorithm.
// In this algorithm, a candidate source is defined as a specific video input
// device opened with a specific resolution and frame rate, together with a
// specific noise-reduction setting.
// The main difference between a source and a track with regards to the spec
// algorithm is that a candidate source can support a range of values for some
// properties while a candidate track supports a single value. For example,
// cropping allows a source with native resolution AxB to support the range of
// resolutions from 1x1 to AxB.
// cropping and rescaling allows a source with native resolution AxB to support
// the range of resolutions from 1x1 to AxB.
// Only candidates that satisfy the basic constraint set are valid. If no
// candidate can satisfy the basic constraint set, this function returns
// a result without value and with the name of a failed constraint accessible
......@@ -72,9 +75,9 @@ struct CONTENT_EXPORT VideoDeviceCaptureCapabilities {
// result with a valid value.
// If there are no candidates at all, this function returns a result without
// value and an empty failed constraint name.
// The criteria to decide if a valid candidate is better than another one are as
// follows:
// 1. Given advanced constraint sets A[0],A[1]...,A[n], candidate C1 is better
// The criteria to decide if a valid candidate source (i.e., one that satisfies
// the basic constraint set) is better than another one are as follows: 1. Given
// advanced constraint sets A[0],A[1]...,A[n], candidate C1 is better
// than candidate C2 if C1 supports the first advanced set for which C1's
// support is different than C2's support.
// Examples:
......@@ -85,26 +88,20 @@ struct CONTENT_EXPORT VideoDeviceCaptureCapabilities {
// 2. C1 is better than C2 if C1 has a smaller fitness distance than C2. The
// fitness distance depends on the ability of the candidate to support ideal
// values in the basic constraint set. This is the final criterion defined in
// the spec.
// the spec. According to spec, all candidates that share the same fitness
// distance are equally acceptable, but this implementation has additional
// criteria to break ties.
// 3. C1 is better than C2 if C1 has a lower Chromium-specific custom distance
// from the basic constraint set. This custom distance is the sum of various
// constraint-specific custom distances.
// For example, if the constraint set specifies a resolution of exactly
// 1000x1000 for a track, then a candidate with a resolution of 1200x1200
// is better than a candidate with a resolution of 2000x2000. Both settings
// satisfy the constraint set because cropping can be used to produce the
// track setting of 1000x1000, but 1200x1200 is considered better because it
// has lower resource usage. The same criteria applies for each advanced
// constraint set.
// 4. C1 is better than C2 if its native settings have a smaller fitness
// distance. For example, if the ideal resolution is 1000x1000 and C1 has a
// native resolution of 1200x1200, while C2 has a native resolution of
// 2000x2000, then C1 is better because it can support the ideal value with
// lower resource usage. Both C1 and C2 are better than a candidate C3 with
// a native resolution of 999x999, since C3 has a nonzero distance to the
// ideal value and thus has worse fitness according to step 2, even if C3's
// native fitness is better than C1's and C2's.
// 5. C1 is better than C2 if its settings are closer to certain default
// from the basic constraint set that penalizes the amount of resolution and
// frame-rate adjustment required to satisfy the range and ideal value
// specified by width, height and frameRate constraints.
// For example, if constraints specify a resolution of exactly 1000x1000 for
// a track, then a candidate with a native resolution of 1200x1200
// is better than a candidate with a native resolution of 2000x2000. Both
// settings satisfy the constraint set because rescaling can be used to
// produce the track setting of 1000x1000, but 1200x1200 is considered better
// because it has lower resource usage.
// 4. C1 is better than C2 if its settings are closer to certain default
// settings that include the device ID, noise reduction, resolution,
// and frame rate, in that order. Note that there is no default facing mode
// or aspect ratio.
......
......@@ -1493,7 +1493,7 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryAspectRatioRange) {
const double kMinAspectRatio = 3.0;
const double kMaxAspectRatio = 4.0;
const long kMinHeight = 600;
const int kMinHeight = 600;
constraint_factory_.Reset();
constraint_factory_.basic().height.SetMin(kMinHeight);
constraint_factory_.basic().aspect_ratio.SetMin(kMinAspectRatio);
......@@ -1721,9 +1721,8 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
advanced4.width.SetMax(1000);
advanced4.height.SetMax(1000);
result = SelectSettings();
// Even though the default device supports the resolution in the fourth
// advanced natively, having better support for the previous sets has
// precedence, so the high-res device is selected.
// The fourth advanced set does not change the allowed range set by previous
// sets, so the selection is the same as in the previous case.
EXPECT_TRUE(result.HasValue());
EXPECT_EQ(high_res_device_->device_id, result.device_id());
EXPECT_EQ(640, result.Width());
......@@ -1738,19 +1737,23 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
constraint_factory_.basic().height.SetIdeal(100);
result = SelectSettings();
EXPECT_TRUE(result.HasValue());
// The high-res device at 600x400@10Hz supports all advanced sets and is
// better at supporting the ideal value.
// It beats 320x240@30Hz because the penalty for the native frame rate takes
// precedence over the native fitness distance.
// Both support standard fitness distance equally, since 600x400 can be
// cropped to 320x240.
EXPECT_EQ(high_res_device_->device_id, result.device_id());
EXPECT_EQ(600, result.Width());
EXPECT_EQ(400, result.Height());
// The allowed resolution range set by constraints is [320x240-640x480], but
// since the ideal resolution is 100x100, the preferred resolution in the
// allowed range is 320x240.
// With regards to frame rate, the maximum allowed is 10Hz.
// This means that the track should be configured as 320x240@10Hz.
// The low-res device at 320x240@30Hz is selected over the high-res device
// at 640x400@10Hz because the distance between 320x240@30Hz and 320x240@10Hz
// is lower than the distance between 640x400@10Hz and 320x240@10Hz.
// Both candidates support standard fitness distance equally, since both can
// use adjusments to produce 320x240@10Hz.
EXPECT_EQ(low_res_device_->device_id, result.device_id());
EXPECT_EQ(320, result.Width());
EXPECT_EQ(240, result.Height());
EXPECT_EQ(320, result.track_adapter_settings().max_width);
EXPECT_EQ(240, result.track_adapter_settings().max_height);
EXPECT_EQ(320.0 / 400.0, result.track_adapter_settings().min_aspect_ratio);
EXPECT_EQ(600.0 / 240.0, result.track_adapter_settings().max_aspect_ratio);
EXPECT_EQ(320.0 / 240.0, result.track_adapter_settings().min_aspect_ratio);
EXPECT_EQ(320.0 / 240.0, result.track_adapter_settings().max_aspect_ratio);
CheckTrackAdapterSettingsEqualsFrameRate(result, 10.0);
constraint_factory_.basic().width.SetIdeal(2000);
......@@ -2176,6 +2179,37 @@ TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
CheckTrackAdapterSettingsEqualsFormat(result);
}
TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
AdvancedContradictoryDeviceIDAndResolution) {
constraint_factory_.Reset();
blink::WebMediaTrackConstraintSet& advanced1 =
constraint_factory_.AddAdvanced();
advanced1.device_id.SetExact(
{blink::WebString::FromASCII(low_res_device_->device_id)});
blink::WebMediaTrackConstraintSet& advanced2 =
constraint_factory_.AddAdvanced();
advanced2.device_id.SetExact(
{blink::WebString::FromASCII(high_res_device_->device_id)});
advanced2.width.SetMax(50);
advanced2.height.SetMax(50);
blink::WebMediaTrackConstraintSet& advanced3 =
constraint_factory_.AddAdvanced();
advanced3.width.SetExact(800);
advanced3.height.SetExact(600);
auto result = SelectSettings();
EXPECT_TRUE(result.HasValue());
// The second advanced set must be ignored because it contradicts the first
// set, but the third set must be applied.
EXPECT_EQ(result.device_id(), low_res_device_->device_id);
EXPECT_EQ(result.Width(), 800);
EXPECT_EQ(result.track_adapter_settings().max_width, 800);
EXPECT_EQ(result.Height(), 600);
EXPECT_EQ(result.track_adapter_settings().max_height, 600);
}
TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
AdvancedContradictoryGroupID) {
constraint_factory_.Reset();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment