Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: content/renderer/media/media_stream_video_source.cc

Issue 183113004: Make sure MediaStreamVideoSource support cropping. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Crop with origin 0,0 and temporary disable failing test. Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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.
tommi (sloooow) - chröme 2014/03/06 10:14:09 I'm not understanding this. Does this mean that (
perkj_chrome 2014/03/06 12:45:42 Please see new comment.
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
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
178 FilterFormatsByConstraint(optional[i], false, &current_candidates); 183 FilterFormatsByConstraint(optional[i], false, &current_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) {
tommi (sloooow) - chröme 2014/03/06 10:14:09 full variable names
perkj_chrome 2014/03/06 12:45:42 Done.
tommi (sloooow) - chröme 2014/03/06 13:28:50 Thanks... at first I thought the 'd' stood for del
perkj_chrome 2014/03/06 14:22:53 Done.
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)
tommi (sloooow) - chröme 2014/03/06 10:14:09 What if height is specified as mandatory and width
perkj_chrome 2014/03/06 12:45:42 I did that first. The whole think gets kind of com
tommi (sloooow) - chröme 2014/03/06 13:28:50 OK that's probably the safe thing to do. Btw, you
perkj_chrome 2014/03/06 14:22:53 For some reason I get a compile error with const
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
tommi (sloooow) - chröme 2014/03/06 10:14:09 nit: resolutions
perkj_chrome 2014/03/06 12:45:42 Done.
242 // many cameras perform worse at its maximum supported resolution.
tommi (sloooow) - chröme 2014/03/06 10:14:09 its -> their Regarding the performance statement
perkj_chrome 2014/03/06 12:45:42 frame rate is lower etc. Updated comment.
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.
tommi (sloooow) - chröme 2014/03/06 10:14:09 I don't understand this actually :) The method doe
perkj_chrome 2014/03/06 12:45:42 See base::Bind(&ReleaseOriginalFrame, frame)) furt
tommi (sloooow) - chröme 2014/03/06 13:28:50 Ah, I missed that. Can you add something to the c
perkj_chrome 2014/03/06 14:22:53 Done.
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
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.
tommi (sloooow) - chröme 2014/03/06 10:14:09 since you're fixing this you might as well fix has
perkj_chrome 2014/03/06 12:45:42 Done.
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
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->visible_rect().size() != frame_output_size_) {
366 // If |frame| is not the size that is expected, we need to crop it by
367 // providing a new |visible_rect|. The new visible rect must be within the
368 // original |visible_rect|.
369 const int visible_width = std::min(frame_output_size_.width(),
370 frame->visible_rect().width());
371
372 // TODO(perkj): horiz_crop and vert_crop must be 0 until local
373 // rendering can support offsets on media::VideoFrame::visible_rect().
374 // crbug/349450. The effect of this is that the cropped frame originate
tommi (sloooow) - chröme 2014/03/06 10:14:09 nit: originates
perkj_chrome 2014/03/06 12:45:42 Done.
375 // from the top left of the original frame instead of being centered.
376 // Find a new horizontal offset within |frame|.
377 //const int horiz_crop = frame->visible_rect().x() +
378 // ((frame->visible_rect().width() - visible_width) / 2);
tommi (sloooow) - chröme 2014/03/06 10:14:09 align //
perkj_chrome 2014/03/06 12:45:42 Done.
379 // Find a new vertical offset within |frame|.
380 // const int vert_crop = frame->visible_rect().y() +
381 // ((frame->visible_rect().height() - visible_height) / 2);
382 const int horiz_crop = 0;
383 const int vert_crop = 0;
384
385 const int visible_height = std::min(frame_output_size_.height(),
386 frame->visible_rect().height());
387
388 gfx::Rect rect(horiz_crop, vert_crop, visible_width,
389 visible_height);
tommi (sloooow) - chröme 2014/03/06 10:14:09 nit: this should be indented by 4 spaces
perkj_chrome 2014/03/06 12:45:42 Done.
390 video_frame = media::VideoFrame::WrapVideoFrame(
391 frame, rect, base::Bind(&ReleaseOriginalFrame, frame));
392 }
393
394 if ((frame->format() == media::VideoFrame::I420 ||
395 frame->format() == media::VideoFrame::YV12) &&
396 capture_adapter_) {
397 capture_adapter_->OnFrameCaptured(video_frame);
398 }
307 } 399 }
308 400
309 void MediaStreamVideoSource::OnSupportedFormats( 401 void MediaStreamVideoSource::OnSupportedFormats(
310 const media::VideoCaptureFormats& formats) { 402 const media::VideoCaptureFormats& formats) {
311 DCHECK(CalledOnValidThread()); 403 DCHECK(CalledOnValidThread());
312 DCHECK_EQ(RETRIEVING_CAPABILITIES, state_); 404 DCHECK_EQ(RETRIEVING_CAPABILITIES, state_);
313 405
314 supported_formats_ = formats; 406 supported_formats_ = formats;
315 if (!FindBestFormatWithConstraints(supported_formats_, &current_format_, 407 if (!FindBestFormatWithConstraints(supported_formats_,
316 &current_constraints_)) { 408 &current_format_,
409 &frame_output_size_,
410 &current_constraints_)) {
317 FinalizeAddTrack(); 411 FinalizeAddTrack();
318 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded); 412 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded);
319 return; 413 return;
320 } 414 }
321 415
322 state_ = STARTING; 416 state_ = STARTING;
323 DVLOG(3) << "Starting the capturer with" 417 DVLOG(3) << "Starting the capturer with"
324 << " width = " << current_format_.frame_size.width() 418 << " width = " << current_format_.frame_size.width()
325 << " height = " << current_format_.frame_size.height() 419 << " height = " << current_format_.frame_size.height()
326 << " frame rate = " << current_format_.frame_rate; 420 << " frame rate = " << current_format_.frame_rate;
327 421
328 media::VideoCaptureParams params; 422 media::VideoCaptureParams params;
329 params.requested_format = current_format_; 423 params.requested_format = current_format_;
330 StartSourceImpl(params); 424 StartSourceImpl(params);
331 } 425 }
332 426
333 bool MediaStreamVideoSource::FindBestFormatWithConstraints( 427 bool MediaStreamVideoSource::FindBestFormatWithConstraints(
334 const media::VideoCaptureFormats& formats, 428 const media::VideoCaptureFormats& formats,
335 media::VideoCaptureFormat* best_format, 429 media::VideoCaptureFormat* best_format,
430 gfx::Size* frame_output_size,
336 blink::WebMediaConstraints* resulting_constraints) { 431 blink::WebMediaConstraints* resulting_constraints) {
337 // Find the first constraints that we can fulfilled. 432 // Find the first constraints that we can fulfill.
338 for (std::vector<RequestedConstraints>::iterator request_it = 433 for (std::vector<RequestedConstraints>::iterator request_it =
339 requested_constraints_.begin(); 434 requested_constraints_.begin();
340 request_it != requested_constraints_.end(); ++request_it) { 435 request_it != requested_constraints_.end(); ++request_it) {
341 const blink::WebMediaConstraints& requested_constraints = 436 const blink::WebMediaConstraints& requested_constraints =
342 request_it->constraints; 437 request_it->constraints;
343 438
344 media::VideoCaptureFormats filtered_formats = 439 media::VideoCaptureFormats filtered_formats =
345 FilterFormats(requested_constraints, formats); 440 FilterFormats(requested_constraints, formats);
346 if (filtered_formats.size() > 0) { 441 if (filtered_formats.size() > 0) {
347 // A request with constraints that can be fulfilled. 442 // A request with constraints that can be fulfilled.
348 *best_format = GetBestCaptureFormat(filtered_formats); 443 GetBestCaptureFormat(filtered_formats,
444 requested_constraints,
445 best_format,
446 frame_output_size);
349 *resulting_constraints= requested_constraints; 447 *resulting_constraints= requested_constraints;
350 return true; 448 return true;
351 } 449 }
352 } 450 }
353 return false; 451 return false;
354 } 452 }
355 453
356 void MediaStreamVideoSource::OnStartDone(bool success) { 454 void MediaStreamVideoSource::OnStartDone(bool success) {
357 DCHECK(CalledOnValidThread()); 455 DCHECK(CalledOnValidThread());
358 DVLOG(3) << "OnStartDone({success =" << success << "})"; 456 DVLOG(3) << "OnStartDone({success =" << success << "})";
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 MediaStreamVideoSource::RequestedConstraints::RequestedConstraints( 494 MediaStreamVideoSource::RequestedConstraints::RequestedConstraints(
397 const blink::WebMediaConstraints& constraints, 495 const blink::WebMediaConstraints& constraints,
398 const ConstraintsCallback& callback) 496 const ConstraintsCallback& callback)
399 : constraints(constraints), callback(callback) { 497 : constraints(constraints), callback(callback) {
400 } 498 }
401 499
402 MediaStreamVideoSource::RequestedConstraints::~RequestedConstraints() { 500 MediaStreamVideoSource::RequestedConstraints::~RequestedConstraints() {
403 } 501 }
404 502
405 } // namespace content 503 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698