Chromium Code Reviews| 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 <limits> | 8 #include <limits> |
| 8 #include <string> | 9 #include <string> |
| 9 | 10 |
| 10 #include "base/logging.h" | 11 #include "base/logging.h" |
| 11 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
| 12 #include "content/renderer/media/media_stream_dependency_factory.h" | 13 #include "content/renderer/media/media_stream_dependency_factory.h" |
| 13 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h" | 14 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h" |
| 14 | 15 |
| 15 namespace content { | 16 namespace content { |
| 16 | 17 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 29 const int MediaStreamVideoSource::kDefaultFrameRate = 30; | 30 const int MediaStreamVideoSource::kDefaultFrameRate = 30; |
| 30 | 31 |
| 31 namespace { | 32 namespace { |
| 32 // Constraints keys for http://dev.w3.org/2011/webrtc/editor/getusermedia.html | 33 // Constraints keys for http://dev.w3.org/2011/webrtc/editor/getusermedia.html |
| 33 const char kSourceId[] = "sourceId"; | 34 const char kSourceId[] = "sourceId"; |
| 34 | 35 |
| 35 // Google-specific key prefix. Constraints with this prefix are ignored if they | 36 // Google-specific key prefix. Constraints with this prefix are ignored if they |
| 36 // are unknown. | 37 // are unknown. |
| 37 const char kGooglePrefix[] = "goog"; | 38 const char kGooglePrefix[] = "goog"; |
| 38 | 39 |
| 40 // MediaStreamVideoSource supports cropping of video frames but only up to | |
| 41 // kMaxCropFactor. | |
| 42 const int kMaxCropFactor = 2; | |
| 43 | |
| 39 // Returns true if |constraint| is fulfilled. |format| can be changed | 44 // Returns true if |constraint| is fulfilled. |format| can be changed |
| 40 // changed by a constraint. Ie - the frame rate can be changed by setting | 45 // changed by a constraint. Ie - the frame rate can be changed by setting |
| 41 // maxFrameRate. | 46 // maxFrameRate. |
| 42 bool UpdateFormatForConstraint( | 47 bool UpdateFormatForConstraint( |
| 43 const blink::WebMediaConstraint& constraint, | 48 const blink::WebMediaConstraint& constraint, |
| 44 bool mandatory, | 49 bool mandatory, |
| 45 media::VideoCaptureFormat* format) { | 50 media::VideoCaptureFormat* format) { |
| 46 DCHECK(format != NULL); | 51 DCHECK(format != NULL); |
| 47 | 52 |
| 48 if (!format->IsValid()) | 53 if (!format->IsValid()) |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 89 | 94 |
| 90 int value; | 95 int value; |
| 91 if (!base::StringToInt(constraint_value, &value)) { | 96 if (!base::StringToInt(constraint_value, &value)) { |
| 92 DLOG(WARNING) << "Can't parse MediaStream constraint. Name:" | 97 DLOG(WARNING) << "Can't parse MediaStream constraint. Name:" |
| 93 << constraint_name << " Value:" << constraint_value; | 98 << constraint_name << " Value:" << constraint_value; |
| 94 return false; | 99 return false; |
| 95 } | 100 } |
| 96 if (constraint_name == MediaStreamVideoSource::kMinWidth) { | 101 if (constraint_name == MediaStreamVideoSource::kMinWidth) { |
| 97 return (value <= format->frame_size.width()); | 102 return (value <= format->frame_size.width()); |
| 98 } else if (constraint_name == MediaStreamVideoSource::kMaxWidth) { | 103 } else if (constraint_name == MediaStreamVideoSource::kMaxWidth) { |
| 99 return (value >= format->frame_size.width()); | 104 return (value * kMaxCropFactor >= format->frame_size.width()); |
| 100 } else if (constraint_name == MediaStreamVideoSource::kMinHeight) { | 105 } else if (constraint_name == MediaStreamVideoSource::kMinHeight) { |
| 101 return (value <= format->frame_size.height()); | 106 return (value <= format->frame_size.height()); |
| 102 } else if (constraint_name == MediaStreamVideoSource::kMaxHeight) { | 107 } else if (constraint_name == MediaStreamVideoSource::kMaxHeight) { |
| 103 return (value >= format->frame_size.height()); | 108 return (value * kMaxCropFactor >= format->frame_size.height()); |
| 104 } else if (constraint_name == MediaStreamVideoSource::kMinFrameRate) { | 109 } else if (constraint_name == MediaStreamVideoSource::kMinFrameRate) { |
| 105 return (value <= format->frame_rate); | 110 return (value <= format->frame_rate); |
| 106 } else if (constraint_name == MediaStreamVideoSource::kMaxFrameRate) { | 111 } else if (constraint_name == MediaStreamVideoSource::kMaxFrameRate) { |
| 107 if (value == 0) { | 112 if (value == 0) { |
| 108 // The frame rate is set by constraint. | 113 // The frame rate is set by constraint. |
| 109 // Don't allow 0 as frame rate if it is a mandatory constraint. | 114 // Don't allow 0 as frame rate if it is a mandatory constraint. |
| 110 // Set the frame rate to 1 if it is not mandatory. | 115 // Set the frame rate to 1 if it is not mandatory. |
| 111 if (mandatory) { | 116 if (mandatory) { |
| 112 return false; | 117 return false; |
| 113 } else { | 118 } else { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 178 FilterFormatsByConstraint(optional[i], false, ¤t_candidates); | 183 FilterFormatsByConstraint(optional[i], false, ¤t_candidates); |
| 179 if (!current_candidates.empty()) { | 184 if (!current_candidates.empty()) { |
| 180 candidates = current_candidates; | 185 candidates = current_candidates; |
| 181 } | 186 } |
| 182 } | 187 } |
| 183 | 188 |
| 184 // We have done as good as we can to filter the supported resolutions. | 189 // We have done as good as we can to filter the supported resolutions. |
| 185 return candidates; | 190 return candidates; |
| 186 } | 191 } |
| 187 | 192 |
| 188 // Find the format that best matches the default video size. | 193 // Retrieve the desired max width and height from |constraints|. |
| 189 // This algorithm is chosen since a resolution must be picked even if no | 194 void GetDesiredMaxWidthAndHeight(const blink::WebMediaConstraints& constraints, |
| 190 // constraints are provided. We don't just select the maximum supported | 195 int* dw, int* dh) { |
| 191 // resolution since higher resolution cost more in terms of complexity and | 196 bool mandatory_found = false; |
| 192 // many cameras perform worse at its maximum supported resolution. | 197 blink::WebString width; |
| 193 const media::VideoCaptureFormat& GetBestCaptureFormat( | 198 if (constraints.getMandatoryConstraintValue( |
| 194 const media::VideoCaptureFormats& formats) { | 199 MediaStreamVideoSource::kMaxWidth, width)) { |
| 195 DCHECK(!formats.empty()); | 200 base::StringToInt(width.utf8(), dw); |
| 201 mandatory_found = true; | |
| 202 } | |
| 203 blink::WebString height; | |
| 204 if (constraints.getMandatoryConstraintValue( | |
| 205 MediaStreamVideoSource::kMaxHeight, height)) { | |
| 206 base::StringToInt(height.utf8(), dh); | |
| 207 mandatory_found = true; | |
| 208 } | |
| 209 if (mandatory_found) | |
| 210 return; | |
| 196 | 211 |
| 197 int default_area = | 212 if (constraints.getOptionalConstraintValue( |
| 198 MediaStreamVideoSource::kDefaultWidth * | 213 MediaStreamVideoSource::kMaxWidth, width)) { |
| 199 MediaStreamVideoSource::kDefaultHeight; | 214 base::StringToInt(width.utf8(), dw); |
| 215 } | |
| 216 if (constraints.getOptionalConstraintValue( | |
| 217 MediaStreamVideoSource::kMaxHeight, height)) { | |
| 218 base::StringToInt(height.utf8(), dh); | |
| 219 } | |
| 220 } | |
| 200 | 221 |
| 222 const media::VideoCaptureFormat& GetBestFormatBasedOnArea( | |
| 223 const media::VideoCaptureFormats& formats, | |
| 224 int area) { | |
| 201 media::VideoCaptureFormats::const_iterator it = formats.begin(); | 225 media::VideoCaptureFormats::const_iterator it = formats.begin(); |
| 202 media::VideoCaptureFormats::const_iterator best_it = formats.begin(); | 226 media::VideoCaptureFormats::const_iterator best_it = formats.begin(); |
| 203 int best_diff = std::numeric_limits<int>::max(); | 227 int best_diff = std::numeric_limits<int>::max(); |
| 204 for (; it != formats.end(); ++it) { | 228 for (; it != formats.end(); ++it) { |
| 205 int diff = abs(default_area - | 229 int diff = abs(area - it->frame_size.width() * it->frame_size.height()); |
| 206 it->frame_size.width() * it->frame_size.height()); | |
| 207 if (diff < best_diff) { | 230 if (diff < best_diff) { |
| 208 best_diff = diff; | 231 best_diff = diff; |
| 209 best_it = it; | 232 best_it = it; |
| 210 } | 233 } |
| 211 } | 234 } |
| 212 return *best_it; | 235 return *best_it; |
| 213 } | 236 } |
| 214 | 237 |
| 238 // Find the format that best matches the default video size. | |
| 239 // This algorithm is chosen since a resolution must be picked even if no | |
| 240 // constraints are provided. We don't just select the maximum supported | |
| 241 // resolution since higher resolution cost more in terms of complexity and | |
| 242 // many cameras perform worse at its maximum supported resolution. | |
| 243 void GetBestCaptureFormat( | |
| 244 const media::VideoCaptureFormats& formats, | |
| 245 const blink::WebMediaConstraints& constraints, | |
| 246 media::VideoCaptureFormat* capture_format, | |
| 247 gfx::Size* frame_output_size) { | |
| 248 DCHECK(!formats.empty()); | |
| 249 DCHECK(frame_output_size); | |
| 250 | |
| 251 int max_width = std::numeric_limits<int>::max(); | |
| 252 int max_height = std::numeric_limits<int>::max();; | |
| 253 GetDesiredMaxWidthAndHeight(constraints, &max_width, &max_height); | |
| 254 | |
| 255 *capture_format = GetBestFormatBasedOnArea( | |
| 256 formats, | |
| 257 std::min(max_width, MediaStreamVideoSource::kDefaultWidth) * | |
| 258 std::min(max_height, MediaStreamVideoSource::kDefaultHeight)); | |
| 259 | |
| 260 *frame_output_size = capture_format->frame_size; | |
| 261 if (max_width < frame_output_size->width()) | |
| 262 frame_output_size->set_width(max_width); | |
| 263 if (max_height < frame_output_size->height()) | |
| 264 frame_output_size->set_height(max_height); | |
| 265 } | |
| 266 | |
| 267 // Empty method used for keeping a reference to the original media::VideoFrame | |
| 268 // in MediaStreamVideoSource::DeliverVideoFrame if cropping is needed. | |
| 269 void ReleaseOriginalFrame( | |
| 270 const scoped_refptr<media::VideoFrame>& frame) { | |
| 271 } | |
| 272 | |
| 215 } // anonymous namespace | 273 } // anonymous namespace |
| 216 | 274 |
| 217 MediaStreamVideoSource::MediaStreamVideoSource( | 275 MediaStreamVideoSource::MediaStreamVideoSource( |
| 218 MediaStreamDependencyFactory* factory) | 276 MediaStreamDependencyFactory* factory) |
| 219 : state_(NEW), | 277 : state_(NEW), |
| 220 factory_(factory), | 278 factory_(factory), |
| 221 capture_adapter_(NULL) { | 279 capture_adapter_(NULL) { |
| 222 DCHECK(factory_); | 280 DCHECK(factory_); |
| 223 } | 281 } |
| 224 | 282 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 248 | 306 |
| 249 state_ = RETRIEVING_CAPABILITIES; | 307 state_ = RETRIEVING_CAPABILITIES; |
| 250 GetCurrentSupportedFormats(max_requested_width, | 308 GetCurrentSupportedFormats(max_requested_width, |
| 251 max_requested_height); | 309 max_requested_height); |
| 252 | 310 |
| 253 break; | 311 break; |
| 254 } | 312 } |
| 255 case STARTING: | 313 case STARTING: |
| 256 case RETRIEVING_CAPABILITIES: { | 314 case RETRIEVING_CAPABILITIES: { |
| 257 // The |callback| will be triggered once the delegate has started or | 315 // The |callback| will be triggered once the delegate has started or |
| 258 // the capabilitites has been retrieved. | 316 // the capabilities has been retrieved. |
| 259 break; | 317 break; |
| 260 } | 318 } |
| 261 case ENDED: | 319 case ENDED: |
| 262 case STARTED: { | 320 case STARTED: { |
| 263 // Currently, reconfiguring the source is not supported. | 321 // Currently, reconfiguring the source is not supported. |
| 264 FinalizeAddTrack(); | 322 FinalizeAddTrack(); |
| 265 } | 323 } |
| 266 } | 324 } |
| 267 } | 325 } |
| 268 | 326 |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 295 } | 353 } |
| 296 | 354 |
| 297 void MediaStreamVideoSource::DoStopSource() { | 355 void MediaStreamVideoSource::DoStopSource() { |
| 298 DVLOG(3) << "DoStopSource()"; | 356 DVLOG(3) << "DoStopSource()"; |
| 299 StopSourceImpl(); | 357 StopSourceImpl(); |
| 300 state_ = ENDED; | 358 state_ = ENDED; |
| 301 } | 359 } |
| 302 | 360 |
| 303 void MediaStreamVideoSource::DeliverVideoFrame( | 361 void MediaStreamVideoSource::DeliverVideoFrame( |
| 304 const scoped_refptr<media::VideoFrame>& frame) { | 362 const scoped_refptr<media::VideoFrame>& frame) { |
| 305 if (capture_adapter_) | 363 scoped_refptr<media::VideoFrame> video_frame(frame); |
| 306 capture_adapter_->OnFrameCaptured(frame); | 364 |
| 365 if (frame->coded_size() != frame_output_size_) { | |
| 366 const int visible_width = std::min(frame_output_size_.width(), | |
| 367 frame->coded_size().width()); | |
| 368 const int horiz_crop = | |
| 369 ((frame->coded_size().width() - visible_width) / 2) & ~1; | |
|
Jói
2014/03/05 15:57:10
Why do you have the & ~1 bit, which (unless my min
perkj_chrome
2014/03/06 09:14:42
Good question- I dont' understand either why setti
| |
| 370 | |
| 371 const int visible_height = std::min(frame_output_size_.height(), | |
| 372 frame->coded_size().height()); | |
| 373 const int vert_crop = | |
| 374 ((frame->coded_size().height() - visible_height) / 2) & ~1; | |
| 375 | |
| 376 gfx::Rect rect(horiz_crop, vert_crop, visible_width, | |
| 377 visible_height); | |
| 378 video_frame = media::VideoFrame::WrapVideoFrame( | |
| 379 frame, rect, base::Bind(&ReleaseOriginalFrame, frame)); | |
| 380 } | |
| 381 | |
| 382 if ((frame->format() == media::VideoFrame::I420 || | |
| 383 frame->format() == media::VideoFrame::YV12) && | |
| 384 capture_adapter_) { | |
| 385 capture_adapter_->OnFrameCaptured(video_frame); | |
| 386 } | |
| 307 } | 387 } |
| 308 | 388 |
| 309 void MediaStreamVideoSource::OnSupportedFormats( | 389 void MediaStreamVideoSource::OnSupportedFormats( |
| 310 const media::VideoCaptureFormats& formats) { | 390 const media::VideoCaptureFormats& formats) { |
| 311 DCHECK(CalledOnValidThread()); | 391 DCHECK(CalledOnValidThread()); |
| 312 DCHECK_EQ(RETRIEVING_CAPABILITIES, state_); | 392 DCHECK_EQ(RETRIEVING_CAPABILITIES, state_); |
| 313 | 393 |
| 314 supported_formats_ = formats; | 394 supported_formats_ = formats; |
| 315 if (!FindBestFormatWithConstraints(supported_formats_, ¤t_format_, | 395 if (!FindBestFormatWithConstraints(supported_formats_, |
| 316 ¤t_constraints_)) { | 396 ¤t_format_, |
| 397 &frame_output_size_, | |
| 398 ¤t_constraints_)) { | |
| 317 FinalizeAddTrack(); | 399 FinalizeAddTrack(); |
| 318 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded); | 400 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded); |
| 319 return; | 401 return; |
| 320 } | 402 } |
| 321 | 403 |
| 322 state_ = STARTING; | 404 state_ = STARTING; |
| 323 DVLOG(3) << "Starting the capturer with" | 405 DVLOG(3) << "Starting the capturer with" |
| 324 << " width = " << current_format_.frame_size.width() | 406 << " width = " << current_format_.frame_size.width() |
| 325 << " height = " << current_format_.frame_size.height() | 407 << " height = " << current_format_.frame_size.height() |
| 326 << " frame rate = " << current_format_.frame_rate; | 408 << " frame rate = " << current_format_.frame_rate; |
| 327 | 409 |
| 328 media::VideoCaptureParams params; | 410 media::VideoCaptureParams params; |
| 329 params.requested_format = current_format_; | 411 params.requested_format = current_format_; |
| 330 StartSourceImpl(params); | 412 StartSourceImpl(params); |
| 331 } | 413 } |
| 332 | 414 |
| 333 bool MediaStreamVideoSource::FindBestFormatWithConstraints( | 415 bool MediaStreamVideoSource::FindBestFormatWithConstraints( |
| 334 const media::VideoCaptureFormats& formats, | 416 const media::VideoCaptureFormats& formats, |
| 335 media::VideoCaptureFormat* best_format, | 417 media::VideoCaptureFormat* best_format, |
| 418 gfx::Size* frame_output_size, | |
| 336 blink::WebMediaConstraints* resulting_constraints) { | 419 blink::WebMediaConstraints* resulting_constraints) { |
| 337 // Find the first constraints that we can fulfilled. | 420 // Find the first constraints that we can fulfill. |
| 338 for (std::vector<RequestedConstraints>::iterator request_it = | 421 for (std::vector<RequestedConstraints>::iterator request_it = |
| 339 requested_constraints_.begin(); | 422 requested_constraints_.begin(); |
| 340 request_it != requested_constraints_.end(); ++request_it) { | 423 request_it != requested_constraints_.end(); ++request_it) { |
| 341 const blink::WebMediaConstraints& requested_constraints = | 424 const blink::WebMediaConstraints& requested_constraints = |
| 342 request_it->constraints; | 425 request_it->constraints; |
| 343 | 426 |
| 344 media::VideoCaptureFormats filtered_formats = | 427 media::VideoCaptureFormats filtered_formats = |
| 345 FilterFormats(requested_constraints, formats); | 428 FilterFormats(requested_constraints, formats); |
| 346 if (filtered_formats.size() > 0) { | 429 if (filtered_formats.size() > 0) { |
| 347 // A request with constraints that can be fulfilled. | 430 // A request with constraints that can be fulfilled. |
| 348 *best_format = GetBestCaptureFormat(filtered_formats); | 431 GetBestCaptureFormat(filtered_formats, |
| 432 requested_constraints, | |
| 433 best_format, | |
| 434 frame_output_size); | |
| 349 *resulting_constraints= requested_constraints; | 435 *resulting_constraints= requested_constraints; |
| 350 return true; | 436 return true; |
| 351 } | 437 } |
| 352 } | 438 } |
| 353 return false; | 439 return false; |
| 354 } | 440 } |
| 355 | 441 |
| 356 void MediaStreamVideoSource::OnStartDone(bool success) { | 442 void MediaStreamVideoSource::OnStartDone(bool success) { |
| 357 DCHECK(CalledOnValidThread()); | 443 DCHECK(CalledOnValidThread()); |
| 358 DVLOG(3) << "OnStartDone({success =" << success << "})"; | 444 DVLOG(3) << "OnStartDone({success =" << success << "})"; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 396 MediaStreamVideoSource::RequestedConstraints::RequestedConstraints( | 482 MediaStreamVideoSource::RequestedConstraints::RequestedConstraints( |
| 397 const blink::WebMediaConstraints& constraints, | 483 const blink::WebMediaConstraints& constraints, |
| 398 const ConstraintsCallback& callback) | 484 const ConstraintsCallback& callback) |
| 399 : constraints(constraints), callback(callback) { | 485 : constraints(constraints), callback(callback) { |
| 400 } | 486 } |
| 401 | 487 |
| 402 MediaStreamVideoSource::RequestedConstraints::~RequestedConstraints() { | 488 MediaStreamVideoSource::RequestedConstraints::~RequestedConstraints() { |
| 403 } | 489 } |
| 404 | 490 |
| 405 } // namespace content | 491 } // namespace content |
| OLD | NEW |