OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/media/media_stream_constraints_util_video_content.h" | 5 #include "content/renderer/media/media_stream_constraints_util_video_content.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <utility> | 8 #include <utility> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "content/renderer/media/media_stream_constraints_util_sets.h" | 11 #include "content/renderer/media/media_stream_constraints_util_sets.h" |
12 #include "content/renderer/media/media_stream_video_source.h" | 12 #include "content/renderer/media/media_stream_video_source.h" |
13 #include "media/base/limits.h" | 13 #include "media/base/limits.h" |
14 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" | 14 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" |
15 #include "third_party/WebKit/public/platform/WebString.h" | 15 #include "third_party/WebKit/public/platform/WebString.h" |
16 | 16 |
17 namespace content { | 17 namespace content { |
18 | 18 |
| 19 // TODO(guidou): Change default width and height to larger values. See |
| 20 // http://crbug.com/257097. |
| 21 const int kDefaultScreenCastWidth = MediaStreamVideoSource::kDefaultWidth; |
| 22 const int kDefaultScreenCastHeight = MediaStreamVideoSource::kDefaultHeight; |
| 23 const double kDefaultScreenCastFrameRate = |
| 24 MediaStreamVideoSource::kDefaultFrameRate; |
| 25 const int kMinScreenCastDimension = 1; |
| 26 const int kMaxScreenCastDimension = media::limits::kMaxDimension - 1; |
| 27 |
19 namespace { | 28 namespace { |
20 | 29 |
21 using Point = ResolutionSet::Point; | 30 using Point = ResolutionSet::Point; |
22 using StringSet = DiscreteSet<std::string>; | 31 using StringSet = DiscreteSet<std::string>; |
23 using BoolSet = DiscreteSet<bool>; | 32 using BoolSet = DiscreteSet<bool>; |
24 | 33 |
25 // Hard upper and lower bound frame rates for tab/desktop capture. | 34 // Hard upper and lower bound frame rates for tab/desktop capture. |
26 constexpr double kMaxScreenCastFrameRate = 120.0; | 35 const double kMaxScreenCastFrameRate = 120.0; |
27 constexpr double kMinScreenCastFrameRate = 1.0 / 60.0; | 36 const double kMinScreenCastFrameRate = 1.0 / 60.0; |
28 | 37 |
29 constexpr double kDefaultFrameRate = MediaStreamVideoSource::kDefaultFrameRate; | |
30 | |
31 constexpr int kMinScreenCastDimension = 1; | |
32 constexpr int kMaxScreenCastDimension = media::limits::kMaxDimension - 1; | |
33 constexpr double kMinScreenCastAspectRatio = | 38 constexpr double kMinScreenCastAspectRatio = |
34 static_cast<double>(kMinScreenCastDimension) / | 39 static_cast<double>(kMinScreenCastDimension) / |
35 static_cast<double>(kMaxScreenCastDimension); | 40 static_cast<double>(kMaxScreenCastDimension); |
36 constexpr double kMaxScreenCastAspectRatio = | 41 constexpr double kMaxScreenCastAspectRatio = |
37 static_cast<double>(kMaxScreenCastDimension) / | 42 static_cast<double>(kMaxScreenCastDimension) / |
38 static_cast<double>(kMinScreenCastDimension); | 43 static_cast<double>(kMinScreenCastDimension); |
39 | 44 |
40 StringSet StringSetFromConstraint(const blink::StringConstraint& constraint) { | 45 StringSet StringSetFromConstraint(const blink::StringConstraint& constraint) { |
41 if (!constraint.hasExact()) | 46 if (!constraint.hasExact()) |
42 return StringSet::UniversalSet(); | 47 return StringSet::UniversalSet(); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 int RoundToInt(double d) { | 133 int RoundToInt(double d) { |
129 return static_cast<int>(std::round(d)); | 134 return static_cast<int>(std::round(d)); |
130 } | 135 } |
131 | 136 |
132 gfx::Size ToGfxSize(const Point& point) { | 137 gfx::Size ToGfxSize(const Point& point) { |
133 return gfx::Size(RoundToInt(point.width()), RoundToInt(point.height())); | 138 return gfx::Size(RoundToInt(point.width()), RoundToInt(point.height())); |
134 } | 139 } |
135 | 140 |
136 double SelectFrameRateFromCandidates( | 141 double SelectFrameRateFromCandidates( |
137 const DoubleRangeSet& candidate_set, | 142 const DoubleRangeSet& candidate_set, |
138 const blink::WebMediaTrackConstraintSet& basic_constraint_set) { | 143 const blink::WebMediaTrackConstraintSet& basic_constraint_set, |
| 144 double default_frame_rate) { |
139 double frame_rate = basic_constraint_set.frameRate.hasIdeal() | 145 double frame_rate = basic_constraint_set.frameRate.hasIdeal() |
140 ? basic_constraint_set.frameRate.ideal() | 146 ? basic_constraint_set.frameRate.ideal() |
141 : kDefaultFrameRate; | 147 : default_frame_rate; |
142 if (frame_rate > candidate_set.Max()) | 148 if (frame_rate > candidate_set.Max()) |
143 frame_rate = candidate_set.Max(); | 149 frame_rate = candidate_set.Max(); |
144 else if (frame_rate < candidate_set.Min()) | 150 else if (frame_rate < candidate_set.Min()) |
145 frame_rate = candidate_set.Min(); | 151 frame_rate = candidate_set.Min(); |
146 | 152 |
147 return frame_rate; | 153 return frame_rate; |
148 } | 154 } |
149 | 155 |
150 media::VideoCaptureParams SelectVideoCaptureParamsFromCandidates( | 156 media::VideoCaptureParams SelectVideoCaptureParamsFromCandidates( |
151 const VideoContentCaptureCandidates& candidates, | 157 const VideoContentCaptureCandidates& candidates, |
152 const blink::WebMediaTrackConstraintSet& basic_constraint_set) { | 158 const blink::WebMediaTrackConstraintSet& basic_constraint_set, |
| 159 int default_height, |
| 160 int default_width, |
| 161 double default_frame_rate) { |
153 double requested_frame_rate = SelectFrameRateFromCandidates( | 162 double requested_frame_rate = SelectFrameRateFromCandidates( |
154 candidates.frame_rate_set, basic_constraint_set); | 163 candidates.frame_rate_set, basic_constraint_set, default_frame_rate); |
155 Point requested_resolution = | 164 Point requested_resolution = |
156 candidates.resolution_set.SelectClosestPointToIdeal(basic_constraint_set); | 165 candidates.resolution_set.SelectClosestPointToIdeal( |
| 166 basic_constraint_set, default_height, default_width); |
157 media::VideoCaptureParams params; | 167 media::VideoCaptureParams params; |
158 params.requested_format = media::VideoCaptureFormat( | 168 params.requested_format = media::VideoCaptureFormat( |
159 ToGfxSize(requested_resolution), static_cast<float>(requested_frame_rate), | 169 ToGfxSize(requested_resolution), static_cast<float>(requested_frame_rate), |
160 media::PIXEL_FORMAT_I420); | 170 media::PIXEL_FORMAT_I420); |
161 params.resolution_change_policy = | 171 params.resolution_change_policy = |
162 SelectResolutionPolicyFromCandidates(candidates.resolution_set); | 172 SelectResolutionPolicyFromCandidates(candidates.resolution_set); |
163 // Content capture always uses default power-line frequency. | 173 // Content capture always uses default power-line frequency. |
164 DCHECK(params.IsValid()); | 174 DCHECK(params.IsValid()); |
165 | 175 |
166 return params; | 176 return params; |
(...skipping 18 matching lines...) Expand all Loading... |
185 // The empty string is treated as a default device ID by the browser. | 195 // The empty string is treated as a default device ID by the browser. |
186 if (candidates.is_universal()) { | 196 if (candidates.is_universal()) { |
187 return std::string(); | 197 return std::string(); |
188 } | 198 } |
189 | 199 |
190 // If there are multiple elements that satisfy the constraints, break ties by | 200 // If there are multiple elements that satisfy the constraints, break ties by |
191 // using the element that was specified first. | 201 // using the element that was specified first. |
192 return candidates.FirstElement(); | 202 return candidates.FirstElement(); |
193 } | 203 } |
194 | 204 |
195 rtc::Optional<bool> SelectNoiseReductionFromCandidates( | 205 base::Optional<bool> SelectNoiseReductionFromCandidates( |
196 const BoolSet& candidates, | 206 const BoolSet& candidates, |
197 const blink::WebMediaTrackConstraintSet& basic_constraint_set) { | 207 const blink::WebMediaTrackConstraintSet& basic_constraint_set) { |
198 DCHECK(!candidates.IsEmpty()); | 208 DCHECK(!candidates.IsEmpty()); |
199 if (basic_constraint_set.googNoiseReduction.hasIdeal() && | 209 if (basic_constraint_set.googNoiseReduction.hasIdeal() && |
200 candidates.Contains(basic_constraint_set.googNoiseReduction.ideal())) { | 210 candidates.Contains(basic_constraint_set.googNoiseReduction.ideal())) { |
201 return rtc::Optional<bool>(basic_constraint_set.googNoiseReduction.ideal()); | 211 return base::Optional<bool>( |
| 212 basic_constraint_set.googNoiseReduction.ideal()); |
202 } | 213 } |
203 | 214 |
204 if (candidates.is_universal()) | 215 if (candidates.is_universal()) |
205 return rtc::Optional<bool>(); | 216 return base::Optional<bool>(); |
206 | 217 |
207 // A non-universal BoolSet can have at most one element. | 218 // A non-universal BoolSet can have at most one element. |
208 return rtc::Optional<bool>(candidates.FirstElement()); | 219 return base::Optional<bool>(candidates.FirstElement()); |
209 } | 220 } |
210 | 221 |
211 VideoContentCaptureSourceSelectionResult SelectResultFromCandidates( | 222 VideoCaptureSettings SelectResultFromCandidates( |
212 const VideoContentCaptureCandidates& candidates, | 223 const VideoContentCaptureCandidates& candidates, |
213 const blink::WebMediaTrackConstraintSet& basic_constraint_set) { | 224 const blink::WebMediaTrackConstraintSet& basic_constraint_set) { |
214 std::string device_id = SelectDeviceIDFromCandidates(candidates.device_id_set, | 225 std::string device_id = SelectDeviceIDFromCandidates(candidates.device_id_set, |
215 basic_constraint_set); | 226 basic_constraint_set); |
| 227 // TODO(guidou): Use native screen-capture resolution as default. |
| 228 // http://crbug.com/257097 |
216 media::VideoCaptureParams capture_params = | 229 media::VideoCaptureParams capture_params = |
217 SelectVideoCaptureParamsFromCandidates(candidates, basic_constraint_set); | 230 SelectVideoCaptureParamsFromCandidates( |
| 231 candidates, basic_constraint_set, kDefaultScreenCastHeight, |
| 232 kDefaultScreenCastWidth, kDefaultScreenCastFrameRate); |
218 | 233 |
219 rtc::Optional<bool> noise_reduction = SelectNoiseReductionFromCandidates( | 234 base::Optional<bool> noise_reduction = SelectNoiseReductionFromCandidates( |
220 candidates.noise_reduction_set, basic_constraint_set); | 235 candidates.noise_reduction_set, basic_constraint_set); |
221 | 236 |
222 return VideoContentCaptureSourceSelectionResult( | 237 auto track_adapter_settings = SelectVideoTrackAdapterSettings( |
223 std::move(device_id), noise_reduction, capture_params); | 238 basic_constraint_set, candidates.resolution_set, |
| 239 candidates.frame_rate_set, capture_params.requested_format); |
| 240 |
| 241 return VideoCaptureSettings(std::move(device_id), capture_params, |
| 242 noise_reduction, track_adapter_settings, |
| 243 candidates.frame_rate_set.Min()); |
224 } | 244 } |
225 | 245 |
226 VideoContentCaptureSourceSelectionResult UnsatisfiedConstraintsResult( | 246 VideoCaptureSettings UnsatisfiedConstraintsResult( |
227 const VideoContentCaptureCandidates& candidates, | 247 const VideoContentCaptureCandidates& candidates, |
228 const blink::WebMediaTrackConstraintSet& constraint_set) { | 248 const blink::WebMediaTrackConstraintSet& constraint_set) { |
229 DCHECK(candidates.IsEmpty()); | 249 DCHECK(candidates.IsEmpty()); |
230 if (candidates.resolution_set.IsHeightEmpty()) { | 250 if (candidates.resolution_set.IsHeightEmpty()) { |
231 return VideoContentCaptureSourceSelectionResult( | 251 return VideoCaptureSettings(constraint_set.height.name()); |
232 constraint_set.height.name()); | |
233 } else if (candidates.resolution_set.IsWidthEmpty()) { | 252 } else if (candidates.resolution_set.IsWidthEmpty()) { |
234 return VideoContentCaptureSourceSelectionResult( | 253 return VideoCaptureSettings(constraint_set.width.name()); |
235 constraint_set.width.name()); | |
236 } else if (candidates.resolution_set.IsAspectRatioEmpty()) { | 254 } else if (candidates.resolution_set.IsAspectRatioEmpty()) { |
237 return VideoContentCaptureSourceSelectionResult( | 255 return VideoCaptureSettings(constraint_set.aspectRatio.name()); |
238 constraint_set.aspectRatio.name()); | |
239 } else if (candidates.frame_rate_set.IsEmpty()) { | 256 } else if (candidates.frame_rate_set.IsEmpty()) { |
240 return VideoContentCaptureSourceSelectionResult( | 257 return VideoCaptureSettings(constraint_set.frameRate.name()); |
241 constraint_set.frameRate.name()); | |
242 } else if (candidates.noise_reduction_set.IsEmpty()) { | 258 } else if (candidates.noise_reduction_set.IsEmpty()) { |
243 return VideoContentCaptureSourceSelectionResult( | 259 return VideoCaptureSettings(constraint_set.googNoiseReduction.name()); |
244 constraint_set.googNoiseReduction.name()); | |
245 } else { | 260 } else { |
246 DCHECK(candidates.device_id_set.IsEmpty()); | 261 DCHECK(candidates.device_id_set.IsEmpty()); |
247 return VideoContentCaptureSourceSelectionResult( | 262 return VideoCaptureSettings(constraint_set.deviceId.name()); |
248 constraint_set.deviceId.name()); | |
249 } | 263 } |
250 } | 264 } |
251 | 265 |
252 } // namespace | 266 } // namespace |
253 | 267 |
254 VideoContentCaptureSourceSelectionResult:: | 268 VideoCaptureSettings SelectSettingsVideoContentCapture( |
255 VideoContentCaptureSourceSelectionResult() | |
256 : VideoContentCaptureSourceSelectionResult("") {} | |
257 | |
258 VideoContentCaptureSourceSelectionResult:: | |
259 VideoContentCaptureSourceSelectionResult(const char* failed_constraint_name) | |
260 : failed_constraint_name_(failed_constraint_name) {} | |
261 | |
262 VideoContentCaptureSourceSelectionResult:: | |
263 VideoContentCaptureSourceSelectionResult( | |
264 std::string device_id, | |
265 const rtc::Optional<bool>& noise_reduction, | |
266 media::VideoCaptureParams capture_params) | |
267 : failed_constraint_name_(nullptr), | |
268 device_id_(std::move(device_id)), | |
269 noise_reduction_(noise_reduction), | |
270 capture_params_(capture_params) {} | |
271 | |
272 VideoContentCaptureSourceSelectionResult:: | |
273 VideoContentCaptureSourceSelectionResult( | |
274 const VideoContentCaptureSourceSelectionResult& other) = default; | |
275 VideoContentCaptureSourceSelectionResult:: | |
276 VideoContentCaptureSourceSelectionResult( | |
277 VideoContentCaptureSourceSelectionResult&& other) = default; | |
278 VideoContentCaptureSourceSelectionResult:: | |
279 ~VideoContentCaptureSourceSelectionResult() = default; | |
280 VideoContentCaptureSourceSelectionResult& | |
281 VideoContentCaptureSourceSelectionResult::operator=( | |
282 const VideoContentCaptureSourceSelectionResult& other) = default; | |
283 VideoContentCaptureSourceSelectionResult& | |
284 VideoContentCaptureSourceSelectionResult::operator=( | |
285 VideoContentCaptureSourceSelectionResult&& other) = default; | |
286 | |
287 int VideoContentCaptureSourceSelectionResult::Height() const { | |
288 DCHECK(HasValue()); | |
289 return capture_params_.requested_format.frame_size.height(); | |
290 } | |
291 | |
292 int VideoContentCaptureSourceSelectionResult::Width() const { | |
293 DCHECK(HasValue()); | |
294 return capture_params_.requested_format.frame_size.width(); | |
295 } | |
296 | |
297 float VideoContentCaptureSourceSelectionResult::FrameRate() const { | |
298 DCHECK(HasValue()); | |
299 return capture_params_.requested_format.frame_rate; | |
300 } | |
301 | |
302 media::ResolutionChangePolicy | |
303 VideoContentCaptureSourceSelectionResult::ResolutionChangePolicy() const { | |
304 DCHECK(HasValue()); | |
305 return capture_params_.resolution_change_policy; | |
306 } | |
307 | |
308 VideoContentCaptureSourceSelectionResult | |
309 SelectVideoContentCaptureSourceSettings( | |
310 const blink::WebMediaConstraints& constraints) { | 269 const blink::WebMediaConstraints& constraints) { |
311 VideoContentCaptureCandidates candidates; | 270 VideoContentCaptureCandidates candidates; |
312 candidates.resolution_set = ScreenCastResolutionCapabilities(); | 271 candidates.resolution_set = ScreenCastResolutionCapabilities(); |
313 candidates.frame_rate_set = | 272 candidates.frame_rate_set = |
314 DoubleRangeSet(kMinScreenCastFrameRate, kMaxScreenCastFrameRate); | 273 DoubleRangeSet(kMinScreenCastFrameRate, kMaxScreenCastFrameRate); |
315 // candidates.device_id_set and candidates.noise_reduction_set are | 274 // candidates.device_id_set and candidates.noise_reduction_set are |
316 // automatically initialized with the universal set. | 275 // automatically initialized with the universal set. |
317 | 276 |
318 candidates = candidates.Intersection( | 277 candidates = candidates.Intersection( |
319 VideoContentCaptureCandidates(constraints.basic())); | 278 VideoContentCaptureCandidates(constraints.basic())); |
320 if (candidates.IsEmpty()) | 279 if (candidates.IsEmpty()) |
321 return UnsatisfiedConstraintsResult(candidates, constraints.basic()); | 280 return UnsatisfiedConstraintsResult(candidates, constraints.basic()); |
322 | 281 |
323 for (const auto& advanced_set : constraints.advanced()) { | 282 for (const auto& advanced_set : constraints.advanced()) { |
324 VideoContentCaptureCandidates advanced_candidates(advanced_set); | 283 VideoContentCaptureCandidates advanced_candidates(advanced_set); |
325 VideoContentCaptureCandidates intersection = | 284 VideoContentCaptureCandidates intersection = |
326 candidates.Intersection(advanced_candidates); | 285 candidates.Intersection(advanced_candidates); |
327 if (!intersection.IsEmpty()) | 286 if (!intersection.IsEmpty()) |
328 candidates = std::move(intersection); | 287 candidates = std::move(intersection); |
329 } | 288 } |
330 | 289 |
331 DCHECK(!candidates.IsEmpty()); | 290 DCHECK(!candidates.IsEmpty()); |
332 return SelectResultFromCandidates(candidates, constraints.basic()); | 291 return SelectResultFromCandidates(candidates, constraints.basic()); |
333 } | 292 } |
334 | 293 |
335 } // namespace content | 294 } // namespace content |
OLD | NEW |