| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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_video_source.h" | 5 #include "content/renderer/media/media_stream_video_source.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <string> | 10 #include <string> |
| 11 #include <utility> | 11 #include <utility> |
| 12 | 12 |
| 13 #include "base/feature_list.h" | 13 #include "base/feature_list.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
| 17 #include "base/trace_event/trace_event.h" | 17 #include "base/trace_event/trace_event.h" |
| 18 #include "content/child/child_process.h" | 18 #include "content/child/child_process.h" |
| 19 #include "content/public/common/content_features.h" | 19 #include "content/public/common/content_features.h" |
| 20 #include "content/renderer/media/media_stream_constraints_util_video_device.h" | 20 #include "content/renderer/media/media_stream_constraints_util_video_device.h" |
| 21 #include "content/renderer/media/media_stream_video_track.h" | 21 #include "content/renderer/media/media_stream_video_track.h" |
| 22 #include "content/renderer/media/video_track_adapter.h" | 22 #include "content/renderer/media/video_track_adapter.h" |
| 23 | 23 |
| 24 namespace content { | 24 namespace content { |
| 25 | 25 |
| 26 namespace { | |
| 27 | |
| 28 const char* const kLegalVideoConstraints[] = {"width", | |
| 29 "height", | |
| 30 "aspectRatio", | |
| 31 "frameRate", | |
| 32 "facingMode", | |
| 33 "deviceId", | |
| 34 "groupId", | |
| 35 "mediaStreamSource", | |
| 36 "googNoiseReduction", | |
| 37 "videoKind"}; | |
| 38 | |
| 39 // Returns true if |constraint| has mandatory constraints. | |
| 40 bool HasMandatoryConstraints(const blink::WebMediaConstraints& constraints) { | |
| 41 return constraints.Basic().HasMandatory(); | |
| 42 } | |
| 43 | |
| 44 // Retrieve the desired max width and height from |constraints|. If not set, | |
| 45 // the |desired_width| and |desired_height| are set to | |
| 46 // std::numeric_limits<int>::max(); | |
| 47 // If either max or exact width or height is set as a mandatory constraint, | |
| 48 // the advanced constraints are not checked. | |
| 49 void GetDesiredMaxWidthAndHeight(const blink::WebMediaConstraints& constraints, | |
| 50 int* desired_width, int* desired_height) { | |
| 51 *desired_width = std::numeric_limits<int>::max(); | |
| 52 *desired_height = std::numeric_limits<int>::max(); | |
| 53 | |
| 54 const auto& basic_constraints = constraints.Basic(); | |
| 55 | |
| 56 if (basic_constraints.width.HasMax() || basic_constraints.height.HasMax() || | |
| 57 basic_constraints.width.HasExact() || | |
| 58 basic_constraints.height.HasExact()) { | |
| 59 if (basic_constraints.width.HasMax()) | |
| 60 *desired_width = basic_constraints.width.Max(); | |
| 61 if (basic_constraints.height.HasMax()) | |
| 62 *desired_height = basic_constraints.height.Max(); | |
| 63 // Exact constraints override max constraints if both are specified. | |
| 64 // Specifying both in the same structure is meaningless. | |
| 65 if (basic_constraints.width.HasExact()) | |
| 66 *desired_width = basic_constraints.width.Exact(); | |
| 67 if (basic_constraints.height.HasExact()) | |
| 68 *desired_height = basic_constraints.height.Exact(); | |
| 69 return; | |
| 70 } | |
| 71 | |
| 72 for (const auto& constraint_set : constraints.Advanced()) { | |
| 73 if (constraint_set.width.HasMax()) | |
| 74 *desired_width = constraint_set.width.Max(); | |
| 75 if (constraint_set.height.HasMax()) | |
| 76 *desired_height = constraint_set.height.Max(); | |
| 77 if (constraint_set.width.HasExact()) | |
| 78 *desired_width = constraint_set.width.Exact(); | |
| 79 if (constraint_set.height.HasExact()) | |
| 80 *desired_height = constraint_set.height.Exact(); | |
| 81 } | |
| 82 } | |
| 83 | |
| 84 // Retrieve the desired max and min aspect ratio from |constraints|. If not set, | |
| 85 // the |min_aspect_ratio| is set to 0 and |max_aspect_ratio| is set to | |
| 86 // std::numeric_limits<double>::max(); | |
| 87 // If either min or max aspect ratio is set as a mandatory constraint, the | |
| 88 // optional constraints are not checked. | |
| 89 void GetDesiredMinAndMaxAspectRatio( | |
| 90 const blink::WebMediaConstraints& constraints, | |
| 91 double* min_aspect_ratio, | |
| 92 double* max_aspect_ratio) { | |
| 93 *min_aspect_ratio = 0; | |
| 94 *max_aspect_ratio = std::numeric_limits<double>::max(); | |
| 95 | |
| 96 if (constraints.Basic().aspect_ratio.HasMin() || | |
| 97 constraints.Basic().aspect_ratio.HasMax()) { | |
| 98 if (constraints.Basic().aspect_ratio.HasMin()) | |
| 99 *min_aspect_ratio = constraints.Basic().aspect_ratio.Min(); | |
| 100 if (constraints.Basic().aspect_ratio.HasMax()) | |
| 101 *max_aspect_ratio = constraints.Basic().aspect_ratio.Max(); | |
| 102 return; | |
| 103 // Note - the code will ignore attempts at successive refinement | |
| 104 // of the aspect ratio with advanced constraint. This may be wrong. | |
| 105 } | |
| 106 // Note - the code below will potentially pick min and max from different | |
| 107 // constraint sets, some of which might have been ignored. | |
| 108 for (const auto& constraint_set : constraints.Advanced()) { | |
| 109 if (constraint_set.aspect_ratio.HasMin()) { | |
| 110 *min_aspect_ratio = constraint_set.aspect_ratio.Min(); | |
| 111 break; | |
| 112 } | |
| 113 } | |
| 114 for (const auto& constraint_set : constraints.Advanced()) { | |
| 115 // Advanced constraint sets with max aspect ratio 0 are unsatisfiable and | |
| 116 // must be ignored. | |
| 117 if (constraint_set.aspect_ratio.HasMax() && | |
| 118 constraint_set.aspect_ratio.Max() > 0) { | |
| 119 *max_aspect_ratio = constraint_set.aspect_ratio.Max(); | |
| 120 break; | |
| 121 } | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 // Returns true if |constraints| are fulfilled. |format| can be changed by a | |
| 126 // constraint, e.g. the frame rate can be changed by setting maxFrameRate. | |
| 127 bool UpdateFormatForConstraints( | |
| 128 const blink::WebMediaTrackConstraintSet& constraints, | |
| 129 media::VideoCaptureFormat* format, | |
| 130 std::string* failing_constraint_name) { | |
| 131 DCHECK(format != NULL); | |
| 132 | |
| 133 if (!format->IsValid()) | |
| 134 return false; | |
| 135 | |
| 136 // The width and height are matched based on cropping occuring later: | |
| 137 // min width/height has to be >= the size of the frame (no upscale). | |
| 138 // max width/height just has to be > 0 (we can crop anything too large). | |
| 139 if ((constraints.width.HasMin() && | |
| 140 constraints.width.Min() > format->frame_size.width()) || | |
| 141 (constraints.width.HasMax() && constraints.width.Max() <= 0) || | |
| 142 (constraints.width.HasExact() && | |
| 143 constraints.width.Exact() > format->frame_size.width())) { | |
| 144 *failing_constraint_name = constraints.width.GetName(); | |
| 145 } else if ((constraints.height.HasMin() && | |
| 146 constraints.height.Min() > format->frame_size.height()) || | |
| 147 (constraints.height.HasMax() && constraints.height.Max() <= 0) || | |
| 148 (constraints.height.HasExact() && | |
| 149 constraints.height.Exact() > format->frame_size.height())) { | |
| 150 *failing_constraint_name = constraints.height.GetName(); | |
| 151 } else if (constraints.video_kind.HasExact() && | |
| 152 !constraints.video_kind.Matches(GetVideoKindForFormat(*format))) { | |
| 153 *failing_constraint_name = constraints.video_kind.GetName(); | |
| 154 } else if (!constraints.frame_rate.Matches(format->frame_rate)) { | |
| 155 if (constraints.frame_rate.HasMax()) { | |
| 156 const double value = constraints.frame_rate.Max(); | |
| 157 // TODO(hta): Check if handling of max = 0.0 is relevant. | |
| 158 // (old handling was to set rate to 1.0 if 0.0 was specified) | |
| 159 if (constraints.frame_rate.Matches(value)) { | |
| 160 format->frame_rate = | |
| 161 (format->frame_rate > value) ? value : format->frame_rate; | |
| 162 return true; | |
| 163 } | |
| 164 } | |
| 165 *failing_constraint_name = constraints.frame_rate.GetName(); | |
| 166 } else { | |
| 167 return true; | |
| 168 } | |
| 169 | |
| 170 DCHECK(!failing_constraint_name->empty()); | |
| 171 return false; | |
| 172 } | |
| 173 | |
| 174 // Removes media::VideoCaptureFormats from |formats| that don't meet | |
| 175 // |constraints|. | |
| 176 void FilterFormatsByConstraints( | |
| 177 const blink::WebMediaTrackConstraintSet& constraints, | |
| 178 media::VideoCaptureFormats* formats, | |
| 179 std::string* failing_constraint_name) { | |
| 180 media::VideoCaptureFormats::iterator format_it = formats->begin(); | |
| 181 while (format_it != formats->end()) { | |
| 182 // Modify |format_it| to fulfill the constraint if possible. | |
| 183 // Delete it otherwise. | |
| 184 if (!UpdateFormatForConstraints(constraints, &(*format_it), | |
| 185 failing_constraint_name)) { | |
| 186 DVLOG(2) << "Format filter: Discarding format " | |
| 187 << format_it->frame_size.width() << "x" | |
| 188 << format_it->frame_size.height() << "@" | |
| 189 << format_it->frame_rate; | |
| 190 format_it = formats->erase(format_it); | |
| 191 } else { | |
| 192 ++format_it; | |
| 193 } | |
| 194 } | |
| 195 } | |
| 196 | |
| 197 // Returns the media::VideoCaptureFormats that matches |constraints|. | |
| 198 // If the return value is empty, and the reason is a specific constraint, | |
| 199 // |unsatisfied_constraint| returns the name of the constraint. | |
| 200 media::VideoCaptureFormats FilterFormats( | |
| 201 const blink::WebMediaConstraints& constraints, | |
| 202 const media::VideoCaptureFormats& supported_formats, | |
| 203 std::string* unsatisfied_constraint) { | |
| 204 if (constraints.IsNull()) | |
| 205 return supported_formats; | |
| 206 | |
| 207 const auto& basic = constraints.Basic(); | |
| 208 | |
| 209 // Do some checks that won't be done when filtering candidates. | |
| 210 | |
| 211 if (basic.width.HasMin() && basic.width.HasMax() && | |
| 212 basic.width.Min() > basic.width.Max()) { | |
| 213 *unsatisfied_constraint = basic.width.GetName(); | |
| 214 return media::VideoCaptureFormats(); | |
| 215 } | |
| 216 | |
| 217 if (basic.height.HasMin() && basic.height.HasMax() && | |
| 218 basic.height.Min() > basic.height.Max()) { | |
| 219 *unsatisfied_constraint = basic.height.GetName(); | |
| 220 return media::VideoCaptureFormats(); | |
| 221 } | |
| 222 | |
| 223 double max_aspect_ratio; | |
| 224 double min_aspect_ratio; | |
| 225 GetDesiredMinAndMaxAspectRatio(constraints, | |
| 226 &min_aspect_ratio, | |
| 227 &max_aspect_ratio); | |
| 228 | |
| 229 if (min_aspect_ratio > max_aspect_ratio || max_aspect_ratio < 0.05f) { | |
| 230 DLOG(WARNING) << "Wrong requested aspect ratio: min " << min_aspect_ratio | |
| 231 << " max " << max_aspect_ratio; | |
| 232 *unsatisfied_constraint = basic.aspect_ratio.GetName(); | |
| 233 return media::VideoCaptureFormats(); | |
| 234 } | |
| 235 | |
| 236 std::vector<std::string> temp( | |
| 237 &kLegalVideoConstraints[0], | |
| 238 &kLegalVideoConstraints[sizeof(kLegalVideoConstraints) / | |
| 239 sizeof(kLegalVideoConstraints[0])]); | |
| 240 std::string failing_name; | |
| 241 if (basic.HasMandatoryOutsideSet(temp, failing_name)) { | |
| 242 *unsatisfied_constraint = failing_name; | |
| 243 return media::VideoCaptureFormats(); | |
| 244 } | |
| 245 | |
| 246 media::VideoCaptureFormats candidates = supported_formats; | |
| 247 FilterFormatsByConstraints(basic, &candidates, unsatisfied_constraint); | |
| 248 | |
| 249 if (candidates.empty()) | |
| 250 return candidates; | |
| 251 | |
| 252 // Ok - all mandatory checked and we still have candidates. | |
| 253 // Let's try filtering using the advanced constraints. The advanced | |
| 254 // constraints must be filtered in the order they occur in |advanced|. | |
| 255 // But if a constraint produce zero candidates, the constraint is ignored and | |
| 256 // the next constraint is tested. | |
| 257 // http://w3c.github.io/mediacapture-main/getusermedia.html#dfn-selectsettings | |
| 258 for (const auto& constraint_set : constraints.Advanced()) { | |
| 259 media::VideoCaptureFormats current_candidates = candidates; | |
| 260 std::string unsatisfied_constraint; | |
| 261 FilterFormatsByConstraints(constraint_set, ¤t_candidates, | |
| 262 &unsatisfied_constraint); | |
| 263 if (!current_candidates.empty()) | |
| 264 candidates = current_candidates; | |
| 265 } | |
| 266 | |
| 267 // We have done as good as we can to filter the supported resolutions. | |
| 268 return candidates; | |
| 269 } | |
| 270 | |
| 271 media::VideoCaptureFormat GetBestFormatBasedOnArea( | |
| 272 const media::VideoCaptureFormats& formats, | |
| 273 int area) { | |
| 274 DCHECK(!formats.empty()); | |
| 275 const media::VideoCaptureFormat* best_format = nullptr; | |
| 276 int best_diff = std::numeric_limits<int>::max(); | |
| 277 for (const auto& format : formats) { | |
| 278 const int diff = abs(area - format.frame_size.GetArea()); | |
| 279 if (diff < best_diff) { | |
| 280 best_diff = diff; | |
| 281 best_format = &format; | |
| 282 } | |
| 283 } | |
| 284 DVLOG(3) << "GetBestFormatBasedOnArea chose format " | |
| 285 << media::VideoCaptureFormat::ToString(*best_format); | |
| 286 return *best_format; | |
| 287 } | |
| 288 | |
| 289 // Find the format that best matches the default video size. | |
| 290 // This algorithm is chosen since a resolution must be picked even if no | |
| 291 // constraints are provided. We don't just select the maximum supported | |
| 292 // resolution since higher resolutions cost more in terms of complexity and | |
| 293 // many cameras have lower frame rate and have more noise in the image at | |
| 294 // their maximum supported resolution. | |
| 295 media::VideoCaptureFormat GetBestCaptureFormat( | |
| 296 const media::VideoCaptureFormats& formats, | |
| 297 const blink::WebMediaConstraints& constraints) { | |
| 298 DCHECK(!formats.empty()); | |
| 299 | |
| 300 int max_width; | |
| 301 int max_height; | |
| 302 GetDesiredMaxWidthAndHeight(constraints, &max_width, &max_height); | |
| 303 const int area = | |
| 304 std::min(max_width, | |
| 305 static_cast<int>(MediaStreamVideoSource::kDefaultWidth)) * | |
| 306 std::min(max_height, | |
| 307 static_cast<int>(MediaStreamVideoSource::kDefaultHeight)); | |
| 308 | |
| 309 return GetBestFormatBasedOnArea(formats, area); | |
| 310 } | |
| 311 | |
| 312 } // anonymous namespace | |
| 313 | |
| 314 bool IsOldVideoConstraints() { | |
| 315 return base::FeatureList::IsEnabled( | |
| 316 features::kMediaStreamOldVideoConstraints); | |
| 317 } | |
| 318 | |
| 319 // static | 26 // static |
| 320 MediaStreamVideoSource* MediaStreamVideoSource::GetVideoSource( | 27 MediaStreamVideoSource* MediaStreamVideoSource::GetVideoSource( |
| 321 const blink::WebMediaStreamSource& source) { | 28 const blink::WebMediaStreamSource& source) { |
| 322 if (source.IsNull() || | 29 if (source.IsNull() || |
| 323 source.GetType() != blink::WebMediaStreamSource::kTypeVideo) { | 30 source.GetType() != blink::WebMediaStreamSource::kTypeVideo) { |
| 324 return nullptr; | 31 return nullptr; |
| 325 } | 32 } |
| 326 return static_cast<MediaStreamVideoSource*>(source.GetExtraData()); | 33 return static_cast<MediaStreamVideoSource*>(source.GetExtraData()); |
| 327 } | 34 } |
| 328 | 35 |
| 329 MediaStreamVideoSource::MediaStreamVideoSource() | 36 MediaStreamVideoSource::MediaStreamVideoSource() |
| 330 : state_(NEW), | 37 : state_(NEW), |
| 331 track_adapter_( | 38 track_adapter_( |
| 332 new VideoTrackAdapter(ChildProcess::current()->io_task_runner())), | 39 new VideoTrackAdapter(ChildProcess::current()->io_task_runner())), |
| 333 weak_factory_(this) {} | 40 weak_factory_(this) {} |
| 334 | 41 |
| 335 MediaStreamVideoSource::~MediaStreamVideoSource() { | 42 MediaStreamVideoSource::~MediaStreamVideoSource() { |
| 336 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 43 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 337 } | 44 } |
| 338 | 45 |
| 339 void MediaStreamVideoSource::AddTrackLegacy( | |
| 340 MediaStreamVideoTrack* track, | |
| 341 const VideoCaptureDeliverFrameCB& frame_callback, | |
| 342 const blink::WebMediaConstraints& constraints, | |
| 343 const ConstraintsCallback& callback) { | |
| 344 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| 345 DCHECK(IsOldVideoConstraints()); | |
| 346 DCHECK(!constraints.IsNull()); | |
| 347 DCHECK(std::find(tracks_.begin(), tracks_.end(), track) == tracks_.end()); | |
| 348 tracks_.push_back(track); | |
| 349 secure_tracker_.Add(track, true); | |
| 350 | |
| 351 track_descriptors_.push_back( | |
| 352 TrackDescriptor(track, frame_callback, constraints, callback)); | |
| 353 | |
| 354 switch (state_) { | |
| 355 case NEW: { | |
| 356 // Tab capture and Screen capture needs the maximum requested height | |
| 357 // and width to decide on the resolution. | |
| 358 // NOTE: Optional constraints are deliberately ignored. | |
| 359 int max_requested_width = 0; | |
| 360 if (constraints.Basic().width.HasMax()) | |
| 361 max_requested_width = constraints.Basic().width.Max(); | |
| 362 | |
| 363 int max_requested_height = 0; | |
| 364 if (constraints.Basic().height.HasMax()) | |
| 365 max_requested_height = constraints.Basic().height.Max(); | |
| 366 | |
| 367 double max_requested_frame_rate = kDefaultFrameRate; | |
| 368 if (constraints.Basic().frame_rate.HasMax()) | |
| 369 max_requested_frame_rate = constraints.Basic().frame_rate.Max(); | |
| 370 | |
| 371 state_ = RETRIEVING_CAPABILITIES; | |
| 372 GetCurrentSupportedFormats( | |
| 373 max_requested_width, | |
| 374 max_requested_height, | |
| 375 max_requested_frame_rate, | |
| 376 base::Bind(&MediaStreamVideoSource::OnSupportedFormats, | |
| 377 weak_factory_.GetWeakPtr())); | |
| 378 | |
| 379 break; | |
| 380 } | |
| 381 case STARTING: | |
| 382 case RETRIEVING_CAPABILITIES: { | |
| 383 // The |callback| will be triggered once the source has started or | |
| 384 // the capabilities have been retrieved. | |
| 385 break; | |
| 386 } | |
| 387 case ENDED: | |
| 388 case STARTED: { | |
| 389 // Currently, reconfiguring the source is not supported. | |
| 390 FinalizeAddTrackLegacy(); | |
| 391 } | |
| 392 } | |
| 393 } | |
| 394 | |
| 395 void MediaStreamVideoSource::AddTrack( | 46 void MediaStreamVideoSource::AddTrack( |
| 396 MediaStreamVideoTrack* track, | 47 MediaStreamVideoTrack* track, |
| 397 const VideoTrackAdapterSettings& track_adapter_settings, | 48 const VideoTrackAdapterSettings& track_adapter_settings, |
| 398 const VideoCaptureDeliverFrameCB& frame_callback, | 49 const VideoCaptureDeliverFrameCB& frame_callback, |
| 399 const ConstraintsCallback& callback) { | 50 const ConstraintsCallback& callback) { |
| 400 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 51 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 401 DCHECK(std::find(tracks_.begin(), tracks_.end(), track) == tracks_.end()); | 52 DCHECK(std::find(tracks_.begin(), tracks_.end(), track) == tracks_.end()); |
| 402 tracks_.push_back(track); | 53 tracks_.push_back(track); |
| 403 secure_tracker_.Add(track, true); | 54 secure_tracker_.Add(track, true); |
| 404 | 55 |
| 405 track_descriptors_.push_back(TrackDescriptor( | 56 track_descriptors_.push_back(TrackDescriptor( |
| 406 track, frame_callback, | 57 track, frame_callback, |
| 407 base::MakeUnique<VideoTrackAdapterSettings>(track_adapter_settings), | 58 base::MakeUnique<VideoTrackAdapterSettings>(track_adapter_settings), |
| 408 callback)); | 59 callback)); |
| 409 | 60 |
| 410 switch (state_) { | 61 switch (state_) { |
| 411 case NEW: { | 62 case NEW: { |
| 412 state_ = STARTING; | 63 state_ = STARTING; |
| 413 blink::WebMediaConstraints ignored_constraints; | 64 blink::WebMediaConstraints ignored_constraints; |
| 414 StartSourceImpl( | 65 StartSourceImpl( |
| 415 media::VideoCaptureFormat() /* ignored */, ignored_constraints, | 66 media::VideoCaptureFormat() /* ignored */, ignored_constraints, |
| 416 base::Bind(&VideoTrackAdapter::DeliverFrameOnIO, track_adapter_)); | 67 base::Bind(&VideoTrackAdapter::DeliverFrameOnIO, track_adapter_)); |
| 417 break; | 68 break; |
| 418 } | 69 } |
| 419 case STARTING: { | 70 case STARTING: { |
| 420 break; | 71 break; |
| 421 } | 72 } |
| 422 case RETRIEVING_CAPABILITIES: { | |
| 423 NOTREACHED(); | |
| 424 break; | |
| 425 } | |
| 426 case ENDED: | 73 case ENDED: |
| 427 case STARTED: { | 74 case STARTED: { |
| 428 // Currently, reconfiguring the source is not supported. | 75 // Currently, reconfiguring the source is not supported. |
| 429 FinalizeAddTrack(); | 76 FinalizeAddTrack(); |
| 430 } | 77 } |
| 431 } | 78 } |
| 432 } | 79 } |
| 433 | 80 |
| 434 void MediaStreamVideoSource::RemoveTrack(MediaStreamVideoTrack* video_track) { | 81 void MediaStreamVideoSource::RemoveTrack(MediaStreamVideoTrack* video_track) { |
| 435 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 82 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 } | 125 } |
| 479 | 126 |
| 480 base::SingleThreadTaskRunner* MediaStreamVideoSource::io_task_runner() const { | 127 base::SingleThreadTaskRunner* MediaStreamVideoSource::io_task_runner() const { |
| 481 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 128 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 482 return track_adapter_->io_task_runner(); | 129 return track_adapter_->io_task_runner(); |
| 483 } | 130 } |
| 484 | 131 |
| 485 base::Optional<media::VideoCaptureFormat> | 132 base::Optional<media::VideoCaptureFormat> |
| 486 MediaStreamVideoSource::GetCurrentFormat() const { | 133 MediaStreamVideoSource::GetCurrentFormat() const { |
| 487 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 134 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 488 if (IsOldVideoConstraints()) { | 135 return GetCurrentFormatImpl(); |
| 489 if (state_ == STARTING || state_ == STARTED) | |
| 490 return current_format_; | |
| 491 return base::Optional<media::VideoCaptureFormat>(); | |
| 492 } else { | |
| 493 return GetCurrentFormatImpl(); | |
| 494 } | |
| 495 } | 136 } |
| 496 | 137 |
| 497 base::Optional<media::VideoCaptureFormat> | 138 base::Optional<media::VideoCaptureFormat> |
| 498 MediaStreamVideoSource::GetCurrentFormatImpl() const { | 139 MediaStreamVideoSource::GetCurrentFormatImpl() const { |
| 499 return base::Optional<media::VideoCaptureFormat>(); | 140 return base::Optional<media::VideoCaptureFormat>(); |
| 500 } | 141 } |
| 501 | 142 |
| 502 void MediaStreamVideoSource::DoStopSource() { | 143 void MediaStreamVideoSource::DoStopSource() { |
| 503 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 144 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 504 DVLOG(3) << "DoStopSource()"; | 145 DVLOG(3) << "DoStopSource()"; |
| 505 if (state_ == ENDED) | 146 if (state_ == ENDED) |
| 506 return; | 147 return; |
| 507 track_adapter_->StopFrameMonitoring(); | 148 track_adapter_->StopFrameMonitoring(); |
| 508 StopSourceImpl(); | 149 StopSourceImpl(); |
| 509 state_ = ENDED; | 150 state_ = ENDED; |
| 510 SetReadyState(blink::WebMediaStreamSource::kReadyStateEnded); | 151 SetReadyState(blink::WebMediaStreamSource::kReadyStateEnded); |
| 511 } | 152 } |
| 512 | 153 |
| 513 void MediaStreamVideoSource::OnSupportedFormats( | |
| 514 const media::VideoCaptureFormats& formats) { | |
| 515 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| 516 DCHECK(IsOldVideoConstraints()); | |
| 517 DCHECK_EQ(RETRIEVING_CAPABILITIES, state_); | |
| 518 | |
| 519 supported_formats_ = formats; | |
| 520 blink::WebMediaConstraints fulfilled_constraints; | |
| 521 if (!FindBestFormatWithConstraints(supported_formats_, | |
| 522 ¤t_format_, | |
| 523 &fulfilled_constraints)) { | |
| 524 SetReadyState(blink::WebMediaStreamSource::kReadyStateEnded); | |
| 525 DVLOG(3) << "OnSupportedFormats failed to find an usable format"; | |
| 526 // This object can be deleted after calling FinalizeAddTrack. See comment | |
| 527 // in the header file. | |
| 528 FinalizeAddTrackLegacy(); | |
| 529 return; | |
| 530 } | |
| 531 | |
| 532 state_ = STARTING; | |
| 533 DVLOG(3) << "Starting the capturer with " | |
| 534 << media::VideoCaptureFormat::ToString(current_format_); | |
| 535 | |
| 536 StartSourceImpl( | |
| 537 current_format_, | |
| 538 fulfilled_constraints, | |
| 539 base::Bind(&VideoTrackAdapter::DeliverFrameOnIO, track_adapter_)); | |
| 540 } | |
| 541 | |
| 542 bool MediaStreamVideoSource::FindBestFormatWithConstraints( | |
| 543 const media::VideoCaptureFormats& formats, | |
| 544 media::VideoCaptureFormat* best_format, | |
| 545 blink::WebMediaConstraints* fulfilled_constraints) { | |
| 546 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| 547 DVLOG(3) << "MediaStreamVideoSource::FindBestFormatWithConstraints " | |
| 548 << "with " << formats.size() << " formats"; | |
| 549 // Find the first track descriptor that can fulfil the constraints. | |
| 550 for (const auto& track : track_descriptors_) { | |
| 551 const blink::WebMediaConstraints& track_constraints = track.constraints; | |
| 552 | |
| 553 // If the source doesn't support capability enumeration it is still ok if | |
| 554 // no mandatory constraints have been specified. That just means that | |
| 555 // we will start with whatever format is native to the source. | |
| 556 if (formats.empty() && !HasMandatoryConstraints(track_constraints)) { | |
| 557 DVLOG(3) << "No mandatory constraints and no formats"; | |
| 558 *fulfilled_constraints = track_constraints; | |
| 559 *best_format = media::VideoCaptureFormat(); | |
| 560 return true; | |
| 561 } | |
| 562 std::string unsatisfied_constraint; | |
| 563 const media::VideoCaptureFormats filtered_formats = | |
| 564 FilterFormats(track_constraints, formats, &unsatisfied_constraint); | |
| 565 if (filtered_formats.empty()) | |
| 566 continue; | |
| 567 | |
| 568 // A request with constraints that can be fulfilled. | |
| 569 *fulfilled_constraints = track_constraints; | |
| 570 media::VideoCaptureFormat best_format_candidate = | |
| 571 GetBestCaptureFormat(filtered_formats, track_constraints); | |
| 572 if (!best_format_candidate.IsValid()) | |
| 573 continue; | |
| 574 | |
| 575 *best_format = best_format_candidate; | |
| 576 DVLOG(3) << "Found a track that matches the constraints"; | |
| 577 return true; | |
| 578 } | |
| 579 DVLOG(3) << "No usable format found"; | |
| 580 return false; | |
| 581 } | |
| 582 | |
| 583 void MediaStreamVideoSource::OnStartDone(MediaStreamRequestResult result) { | 154 void MediaStreamVideoSource::OnStartDone(MediaStreamRequestResult result) { |
| 584 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 155 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 585 DVLOG(3) << "OnStartDone({result =" << result << "})"; | 156 DVLOG(3) << "OnStartDone({result =" << result << "})"; |
| 586 if (result == MEDIA_DEVICE_OK) { | 157 if (result == MEDIA_DEVICE_OK) { |
| 587 DCHECK_EQ(STARTING, state_); | 158 DCHECK_EQ(STARTING, state_); |
| 588 state_ = STARTED; | 159 state_ = STARTED; |
| 589 SetReadyState(blink::WebMediaStreamSource::kReadyStateLive); | 160 SetReadyState(blink::WebMediaStreamSource::kReadyStateLive); |
| 590 double frame_rate = | 161 double frame_rate = |
| 591 GetCurrentFormat() ? GetCurrentFormat()->frame_rate : 0.0; | 162 GetCurrentFormat() ? GetCurrentFormat()->frame_rate : 0.0; |
| 592 track_adapter_->StartFrameMonitoring( | 163 track_adapter_->StartFrameMonitoring( |
| 593 frame_rate, base::Bind(&MediaStreamVideoSource::SetMutedState, | 164 frame_rate, base::Bind(&MediaStreamVideoSource::SetMutedState, |
| 594 weak_factory_.GetWeakPtr())); | 165 weak_factory_.GetWeakPtr())); |
| 595 } else { | 166 } else { |
| 596 StopSource(); | 167 StopSource(); |
| 597 } | 168 } |
| 598 | 169 |
| 599 // This object can be deleted after calling FinalizeAddTrack. See comment in | 170 // This object can be deleted after calling FinalizeAddTrack. See comment in |
| 600 // the header file. | 171 // the header file. |
| 601 if (IsOldVideoConstraints()) | 172 FinalizeAddTrack(); |
| 602 FinalizeAddTrackLegacy(); | |
| 603 else | |
| 604 FinalizeAddTrack(); | |
| 605 } | |
| 606 | |
| 607 void MediaStreamVideoSource::FinalizeAddTrackLegacy() { | |
| 608 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| 609 DCHECK(IsOldVideoConstraints()); | |
| 610 const media::VideoCaptureFormats formats(1, current_format_); | |
| 611 | |
| 612 std::vector<TrackDescriptor> track_descriptors; | |
| 613 track_descriptors.swap(track_descriptors_); | |
| 614 for (const auto& track : track_descriptors) { | |
| 615 MediaStreamRequestResult result = MEDIA_DEVICE_OK; | |
| 616 std::string unsatisfied_constraint; | |
| 617 | |
| 618 if (HasMandatoryConstraints(track.constraints) && | |
| 619 FilterFormats(track.constraints, formats, &unsatisfied_constraint) | |
| 620 .empty()) { | |
| 621 result = MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED; | |
| 622 DVLOG(3) << "FinalizeAddTrackLegacy() ignoring device on constraint " | |
| 623 << unsatisfied_constraint; | |
| 624 } | |
| 625 | |
| 626 if (state_ != STARTED && result == MEDIA_DEVICE_OK) | |
| 627 result = MEDIA_DEVICE_TRACK_START_FAILURE; | |
| 628 | |
| 629 if (result == MEDIA_DEVICE_OK) { | |
| 630 int max_width; | |
| 631 int max_height; | |
| 632 GetDesiredMaxWidthAndHeight(track.constraints, &max_width, &max_height); | |
| 633 double max_aspect_ratio; | |
| 634 double min_aspect_ratio; | |
| 635 GetDesiredMinAndMaxAspectRatio(track.constraints, | |
| 636 &min_aspect_ratio, | |
| 637 &max_aspect_ratio); | |
| 638 double max_frame_rate = 0.0f; | |
| 639 // Note: Optional and ideal constraints are ignored; this is | |
| 640 // purely a hard max limit. | |
| 641 if (track.constraints.Basic().frame_rate.HasMax()) | |
| 642 max_frame_rate = track.constraints.Basic().frame_rate.Max(); | |
| 643 | |
| 644 track_adapter_->AddTrack( | |
| 645 track.track, track.frame_callback, | |
| 646 VideoTrackAdapterSettings(max_width, max_height, min_aspect_ratio, | |
| 647 max_aspect_ratio, max_frame_rate, | |
| 648 base::Optional<gfx::Size>())); | |
| 649 // Calculate resulting frame size if the source delivers frames | |
| 650 // according to the current format. Note: Format may change later. | |
| 651 gfx::Size desired_size; | |
| 652 VideoTrackAdapter::CalculateTargetSize( | |
| 653 false /* is_rotated */, current_format_.frame_size, | |
| 654 gfx::Size(max_width, max_height), min_aspect_ratio, max_aspect_ratio, | |
| 655 &desired_size); | |
| 656 track.track->SetTargetSizeAndFrameRate( | |
| 657 desired_size.width(), desired_size.height(), max_frame_rate); | |
| 658 } | |
| 659 | |
| 660 DVLOG(3) << "FinalizeAddTrackLegacy() result " << result; | |
| 661 | |
| 662 if (!track.callback.is_null()) | |
| 663 track.callback.Run(this, result, | |
| 664 blink::WebString::FromUTF8(unsatisfied_constraint)); | |
| 665 } | |
| 666 } | 173 } |
| 667 | 174 |
| 668 void MediaStreamVideoSource::FinalizeAddTrack() { | 175 void MediaStreamVideoSource::FinalizeAddTrack() { |
| 669 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 176 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 670 DCHECK(!IsOldVideoConstraints()); | |
| 671 std::vector<TrackDescriptor> track_descriptors; | 177 std::vector<TrackDescriptor> track_descriptors; |
| 672 track_descriptors.swap(track_descriptors_); | 178 track_descriptors.swap(track_descriptors_); |
| 673 for (const auto& track : track_descriptors) { | 179 for (const auto& track : track_descriptors) { |
| 674 MediaStreamRequestResult result = MEDIA_DEVICE_OK; | 180 MediaStreamRequestResult result = MEDIA_DEVICE_OK; |
| 675 if (state_ != STARTED) | 181 if (state_ != STARTED) |
| 676 result = MEDIA_DEVICE_TRACK_START_FAILURE; | 182 result = MEDIA_DEVICE_TRACK_START_FAILURE; |
| 677 | 183 |
| 678 if (result == MEDIA_DEVICE_OK) { | 184 if (result == MEDIA_DEVICE_OK) { |
| 679 track_adapter_->AddTrack(track.track, track.frame_callback, | 185 track_adapter_->AddTrack(track.track, track.frame_callback, |
| 680 *track.adapter_settings); | 186 *track.adapter_settings); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 717 if (!Owner().IsNull()) { | 223 if (!Owner().IsNull()) { |
| 718 Owner().SetReadyState(muted_state | 224 Owner().SetReadyState(muted_state |
| 719 ? blink::WebMediaStreamSource::kReadyStateMuted | 225 ? blink::WebMediaStreamSource::kReadyStateMuted |
| 720 : blink::WebMediaStreamSource::kReadyStateLive); | 226 : blink::WebMediaStreamSource::kReadyStateLive); |
| 721 } | 227 } |
| 722 } | 228 } |
| 723 | 229 |
| 724 MediaStreamVideoSource::TrackDescriptor::TrackDescriptor( | 230 MediaStreamVideoSource::TrackDescriptor::TrackDescriptor( |
| 725 MediaStreamVideoTrack* track, | 231 MediaStreamVideoTrack* track, |
| 726 const VideoCaptureDeliverFrameCB& frame_callback, | 232 const VideoCaptureDeliverFrameCB& frame_callback, |
| 727 const blink::WebMediaConstraints& constraints, | |
| 728 const ConstraintsCallback& callback) | |
| 729 : track(track), | |
| 730 frame_callback(frame_callback), | |
| 731 constraints(constraints), | |
| 732 callback(callback) { | |
| 733 DCHECK(IsOldVideoConstraints()); | |
| 734 } | |
| 735 | |
| 736 MediaStreamVideoSource::TrackDescriptor::TrackDescriptor( | |
| 737 MediaStreamVideoTrack* track, | |
| 738 const VideoCaptureDeliverFrameCB& frame_callback, | |
| 739 std::unique_ptr<VideoTrackAdapterSettings> adapter_settings, | 233 std::unique_ptr<VideoTrackAdapterSettings> adapter_settings, |
| 740 const ConstraintsCallback& callback) | 234 const ConstraintsCallback& callback) |
| 741 : track(track), | 235 : track(track), |
| 742 frame_callback(frame_callback), | 236 frame_callback(frame_callback), |
| 743 adapter_settings(std::move(adapter_settings)), | 237 adapter_settings(std::move(adapter_settings)), |
| 744 callback(callback) { | 238 callback(callback) {} |
| 745 DCHECK(!IsOldVideoConstraints()); | |
| 746 } | |
| 747 | 239 |
| 748 MediaStreamVideoSource::TrackDescriptor::TrackDescriptor( | 240 MediaStreamVideoSource::TrackDescriptor::TrackDescriptor( |
| 749 TrackDescriptor&& other) = default; | 241 TrackDescriptor&& other) = default; |
| 750 MediaStreamVideoSource::TrackDescriptor& | 242 MediaStreamVideoSource::TrackDescriptor& |
| 751 MediaStreamVideoSource::TrackDescriptor::operator=( | 243 MediaStreamVideoSource::TrackDescriptor::operator=( |
| 752 MediaStreamVideoSource::TrackDescriptor&& other) = default; | 244 MediaStreamVideoSource::TrackDescriptor&& other) = default; |
| 753 | 245 |
| 754 MediaStreamVideoSource::TrackDescriptor::~TrackDescriptor() { | 246 MediaStreamVideoSource::TrackDescriptor::~TrackDescriptor() { |
| 755 } | 247 } |
| 756 | 248 |
| 757 } // namespace content | 249 } // namespace content |
| OLD | NEW |