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

Add support for resizeMode in MediaStreamTrack.getSettings()

This CL exposes the current resizeMode setting to the Web Platform.
As of this CL, the resizeMode is 'none' if the track resolution
corresponds to the native resolution of the video source, without any
resolution adjustment. It is 'crop-and-rescale' if rescaling is
necessary.

The resizeMode currently cannot be set explicitly with getUserMedia() or
applyConstraints(), but this functionality will be added in a follow-up
CL.

Drive-by: Add separate WPT tests for all getSettings() properties.

Intent to Ship:
https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/V2srjdzRCXE

Bug: 854980
Change-Id: Id4c683e6b2f228b17cf2354cb7fc589ca9e593a6
Reviewed-on: https://chromium-review.googlesource.com/c/1307448
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Reviewed-by: default avatarHenrik Boström <hbos@chromium.org>
Reviewed-by: default avatarPhilip Jägenstedt <foolip@chromium.org>
Cr-Commit-Position: refs/heads/master@{#604562}
parent 7523c4b7
...@@ -382,6 +382,11 @@ void MediaStreamVideoTrack::GetSettings( ...@@ -382,6 +382,11 @@ void MediaStreamVideoTrack::GetSettings(
settings.video_kind = GetVideoKindForFormat(*format); settings.video_kind = GetVideoKindForFormat(*format);
} }
settings.facing_mode = ToWebFacingMode(source_->device().video_facing); settings.facing_mode = ToWebFacingMode(source_->device().video_facing);
settings.resize_mode = blink::WebString::FromASCII(
std::string(adapter_settings().target_size()
? blink::WebMediaStreamTrack::kResizeModeRescale
: blink::WebMediaStreamTrack::kResizeModeNone));
const base::Optional<CameraCalibration> calibration = const base::Optional<CameraCalibration> calibration =
source_->device().camera_calibration; source_->device().camera_calibration;
if (calibration) { if (calibration) {
......
...@@ -71,40 +71,146 @@ ...@@ -71,40 +71,146 @@
var stream = await navigator.mediaDevices.getUserMedia(constraints); var stream = await navigator.mediaDevices.getUserMedia(constraints);
assert_equals(stream.getTracks()[0].getSettings().groupId, assert_equals(stream.getTracks()[0].getSettings().groupId,
device.groupId); device.groupId);
assert_true(device.groupId.length > 0); assert_greater_than(device.groupId.length, 0);
} }
}); });
}, 'groupId is correctly reported by getSettings() for all devices'); }, 'groupId is correctly reported by getSettings() for all devices');
promise_test(t => { async function createAudioStreamAndGetSettings(t) {
return navigator.mediaDevices.getUserMedia({audio: true}).then(stream => { const stream = await navigator.mediaDevices.getUserMedia({audio: true});
let settings = stream.getAudioTracks()[0].getSettings(); t.add_cleanup(() => stream.getAudioTracks()[0].stop());
return stream.getAudioTracks()[0].getSettings();
}
promise_test(async t => {
const settings = await createAudioStreamAndGetSettings(t);
assert_equals(typeof(settings.deviceId), "string", assert_equals(typeof(settings.deviceId), "string",
"deviceId should exist and it should be a string."); "deviceId should exist and it should be a string.");
}, 'deviceId is reported by getSettings() for getUserMedia() audio tracks');
promise_test(async t => {
const settings = await createAudioStreamAndGetSettings(t);
assert_equals(typeof(settings.groupId), "string", assert_equals(typeof(settings.groupId), "string",
"groupId should exist and it should be a string."); "groupId should exist and it should be a string.");
}, 'groupId is reported by getSettings() for getUserMedia() audio tracks');
promise_test(async t => {
const settings = await createAudioStreamAndGetSettings(t);
assert_equals(typeof(settings.volume), "number", assert_equals(typeof(settings.volume), "number",
"volume should exist and it should be a number."); "volume should exist and it should be a number.");
assert_true(settings.volume >= 0.0 && settings.volume <= 1.0, assert_between_inclusive(settings.volume, 0.0, 1.0);
"volume should be a number in the range [0.0, 1.0]."); }, 'volume is reported by getSettings() for getUserMedia() audio tracks');
promise_test(async t => {
const settings = await createAudioStreamAndGetSettings(t);
assert_equals(typeof(settings.sampleRate), "number", assert_equals(typeof(settings.sampleRate), "number",
"sampleRate should exist and it should be a number."); "sampleRate should exist and it should be a number.");
assert_true(settings.sampleRate > 0, "sampleRate should be positive."); assert_greater_than(settings.sampleRate, 0);
}, 'sampleRate is reported by getSettings() for getUserMedia() audio tracks');
promise_test(async t => {
const settings = await createAudioStreamAndGetSettings(t);
assert_equals(typeof(settings.sampleSize), "number", assert_equals(typeof(settings.sampleSize), "number",
"sampleSize should exist and it should be a number."); "sampleSize should exist and it should be a number.");
assert_true(settings.sampleSize > 0, "sampleSize should be positive."); assert_greater_than(settings.sampleSize, 0);
}, 'sampleSize is reported by getSettings() for getUserMedia() audio tracks');
promise_test(async t => {
const settings = await createAudioStreamAndGetSettings(t);
assert_equals(typeof(settings.echoCancellation), "boolean", assert_equals(typeof(settings.echoCancellation), "boolean",
"echoCancellation should exist and it should be a boolean."); "echoCancellation should exist and it should be a boolean.");
}, 'echoCancellation is reported by getSettings() for getUserMedia() audio tracks');
promise_test(async t => {
const settings = await createAudioStreamAndGetSettings(t);
assert_equals(typeof(settings.autoGainControl), "boolean", assert_equals(typeof(settings.autoGainControl), "boolean",
"autoGainControl should exist and it should be a boolean."); "autoGainControl should exist and it should be a boolean.");
}, 'autoGainControl is reported by getSettings() for getUserMedia() audio tracks');
promise_test(async t => {
const settings = await createAudioStreamAndGetSettings(t);
assert_equals(typeof(settings.noiseSuppression), "boolean", assert_equals(typeof(settings.noiseSuppression), "boolean",
"noiseSuppression should exist and it should be a boolean."); "noiseSuppression should exist and it should be a boolean.");
}, 'noiseSuppression is reported by getSettings() for getUserMedia() audio tracks');
promise_test(async t => {
const settings = await createAudioStreamAndGetSettings(t);
assert_equals(typeof(settings.latency), "number", assert_equals(typeof(settings.latency), "number",
"latency should exist and it should be a number."); "latency should exist and it should be a number.");
assert_true(settings.latency >= 0, "latency should not be negative."); assert_greater_than_equal(settings.latency,0);
}, 'latency is reported by getSettings() for getUserMedia() audio tracks');
promise_test(async t => {
const settings = await createAudioStreamAndGetSettings(t);
assert_equals(typeof(settings.channelCount), "number", assert_equals(typeof(settings.channelCount), "number",
"channelCount should exist and it should be a number."); "channelCount should exist and it should be a number.");
assert_true(settings.channelCount > 0, "channelCount should be positive."); assert_greater_than(settings.channelCount, 0);
}); }, 'channelCount is reported by getSettings() for getUserMedia() audio tracks');
}, 'audio properties are reported by getSettings()');
async function createVideoStreamAndGetSettings(t) {
const stream = await navigator.mediaDevices.getUserMedia({video: true});
t.add_cleanup(() => stream.getVideoTracks()[0].stop());
return stream.getVideoTracks()[0].getSettings();
}
promise_test(async t => {
const settings = await createVideoStreamAndGetSettings(t);
assert_equals(typeof(settings.deviceId), "string",
"deviceId should exist and it should be a string.");
}, 'deviceId is reported by getSettings() for getUserMedia() video tracks');
promise_test(async t => {
const settings = await createVideoStreamAndGetSettings(t);
assert_equals(typeof(settings.groupId), "string",
"groupId should exist and it should be a string.");
}, 'groupId is reported by getSettings() for getUserMedia() video tracks');
promise_test(async t => {
const settings = await createVideoStreamAndGetSettings(t);
assert_equals(typeof(settings.width), "number",
"width should exist and it should be a number.");
assert_true(Number.isInteger(settings.width), "width should be an integer.");
assert_greater_than_equal(settings.width, 0);
}, 'width is reported by getSettings() for getUserMedia() video tracks');
promise_test(async t => {
const settings = await createVideoStreamAndGetSettings(t);
assert_equals(typeof(settings.height), "number",
"height should exist and it should be a number.");
assert_true(Number.isInteger(settings.height), "height should be an integer.");
assert_greater_than_equal(settings.height, 0);
}, 'height is reported by getSettings() for getUserMedia() video tracks');
promise_test(async t => {
const settings = await createVideoStreamAndGetSettings(t);
assert_equals(typeof(settings.aspectRatio), "number",
"aspectRatio should exist and it should be a number.");
assert_greater_than_equal(settings.aspectRatio, 0);
}, 'aspectRatio is reported by getSettings() for getUserMedia() video tracks');
promise_test(async t => {
const settings = await createVideoStreamAndGetSettings(t);
assert_equals(typeof(settings.frameRate), "number",
"frameRate should exist and it should be a number.");
assert_greater_than_equal(settings.frameRate, 0);
}, 'frameRate is reported by getSettings() for getUserMedia() video tracks');
promise_test(async t => {
const settings = await createVideoStreamAndGetSettings(t);
// facingMode not treated as mandatory because not all platforms provide
// this information.
if (settings.facingMode) {
assert_equals(typeof(settings.facingMode), "string",
"If facingMode is provided it should be a string.");
assert_in_array(settings.facingMode,
['user', 'environment', 'left', 'right']);
}
}, 'facingMode is reported by getSettings() for getUserMedia() video tracks');
promise_test(async t => {
const settings = await createVideoStreamAndGetSettings(t);
assert_equals(typeof(settings.resizeMode), "string",
"resizeMode should exist and it should be a string.");
assert_in_array(settings.resizeMode, ['none', 'crop-and-scale']);
}, 'resizeMode is reported by getSettings() for getUserMedia() video tracks');
</script> </script>
...@@ -55,6 +55,8 @@ promise_test(function() { ...@@ -55,6 +55,8 @@ promise_test(function() {
assert_true('aspectRatio' in settings, assert_true('aspectRatio' in settings,
'Aspect ratio missing: ' + JSON.stringify(settings)); 'Aspect ratio missing: ' + JSON.stringify(settings));
assert_equals(settings.width / settings.height, settings.aspectRatio); assert_equals(settings.width / settings.height, settings.aspectRatio);
assert_in_array(settings.resizeMode, [ "none", "crop-and-scale" ],
'Invalid resizeMode: ' + JSON.stringify(settings));
}); });
}, 'A video track returns the expected variables'); }, 'A video track returns the expected variables');
......
...@@ -51,6 +51,9 @@ class WebMediaStreamTrack { ...@@ -51,6 +51,9 @@ class WebMediaStreamTrack {
}; };
enum class CursorCaptureType { kNever, kAlways, kMotion }; enum class CursorCaptureType { kNever, kAlways, kMotion };
BLINK_PLATFORM_EXPORT static const char kResizeModeNone[];
BLINK_PLATFORM_EXPORT static const char kResizeModeRescale[];
struct Settings { struct Settings {
bool HasFrameRate() const { return frame_rate >= 0.0; } bool HasFrameRate() const { return frame_rate >= 0.0; }
bool HasWidth() const { return width >= 0; } bool HasWidth() const { return width >= 0; }
...@@ -76,6 +79,7 @@ class WebMediaStreamTrack { ...@@ -76,6 +79,7 @@ class WebMediaStreamTrack {
WebString device_id; WebString device_id;
WebString group_id; WebString group_id;
FacingMode facing_mode = FacingMode::kNone; FacingMode facing_mode = FacingMode::kNone;
WebString resize_mode;
base::Optional<bool> echo_cancellation; base::Optional<bool> echo_cancellation;
base::Optional<bool> auto_gain_control; base::Optional<bool> auto_gain_control;
base::Optional<bool> noise_supression; base::Optional<bool> noise_supression;
......
...@@ -480,6 +480,8 @@ MediaTrackSettings* MediaStreamTrack::getSettings() const { ...@@ -480,6 +480,8 @@ MediaTrackSettings* MediaStreamTrack::getSettings() const {
break; break;
} }
} }
if (!platform_settings.resize_mode.IsNull())
settings->setResizeMode(platform_settings.resize_mode);
if (platform_settings.echo_cancellation) if (platform_settings.echo_cancellation)
settings->setEchoCancellation(*platform_settings.echo_cancellation); settings->setEchoCancellation(*platform_settings.echo_cancellation);
......
...@@ -10,6 +10,7 @@ dictionary MediaTrackSettings { ...@@ -10,6 +10,7 @@ dictionary MediaTrackSettings {
double aspectRatio; double aspectRatio;
double frameRate; double frameRate;
DOMString facingMode; DOMString facingMode;
DOMString resizeMode;
double volume; double volume;
long sampleRate; long sampleRate;
long sampleSize; long sampleSize;
......
...@@ -57,6 +57,9 @@ class TrackDataContainer : public MediaStreamComponent::TrackData { ...@@ -57,6 +57,9 @@ class TrackDataContainer : public MediaStreamComponent::TrackData {
} // namespace } // namespace
const char WebMediaStreamTrack::kResizeModeNone[] = "none";
const char WebMediaStreamTrack::kResizeModeRescale[] = "crop-and-scale";
WebMediaStreamTrack::WebMediaStreamTrack( WebMediaStreamTrack::WebMediaStreamTrack(
MediaStreamComponent* media_stream_component) MediaStreamComponent* media_stream_component)
: private_(media_stream_component) {} : private_(media_stream_component) {}
......
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