| 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 |