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

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: Removed extra spaces in content_unittests 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. Ie - if a constraint is set to maxHeight 360, an original
42 // input frame height of max 360 * kMaxCropFactor pixels is accepted.
43 const int kMaxCropFactor = 2;
44
39 // Returns true if |constraint| is fulfilled. |format| can be changed 45 // Returns true if |constraint| is fulfilled. |format| can be changed
40 // changed by a constraint. Ie - the frame rate can be changed by setting 46 // changed by a constraint. Ie - the frame rate can be changed by setting
41 // maxFrameRate. 47 // maxFrameRate.
42 bool UpdateFormatForConstraint( 48 bool UpdateFormatForConstraint(
43 const blink::WebMediaConstraint& constraint, 49 const blink::WebMediaConstraint& constraint,
44 bool mandatory, 50 bool mandatory,
45 media::VideoCaptureFormat* format) { 51 media::VideoCaptureFormat* format) {
46 DCHECK(format != NULL); 52 DCHECK(format != NULL);
47 53
48 if (!format->IsValid()) 54 if (!format->IsValid())
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 95
90 int value; 96 int value;
91 if (!base::StringToInt(constraint_value, &value)) { 97 if (!base::StringToInt(constraint_value, &value)) {
92 DLOG(WARNING) << "Can't parse MediaStream constraint. Name:" 98 DLOG(WARNING) << "Can't parse MediaStream constraint. Name:"
93 << constraint_name << " Value:" << constraint_value; 99 << constraint_name << " Value:" << constraint_value;
94 return false; 100 return false;
95 } 101 }
96 if (constraint_name == MediaStreamVideoSource::kMinWidth) { 102 if (constraint_name == MediaStreamVideoSource::kMinWidth) {
97 return (value <= format->frame_size.width()); 103 return (value <= format->frame_size.width());
98 } else if (constraint_name == MediaStreamVideoSource::kMaxWidth) { 104 } else if (constraint_name == MediaStreamVideoSource::kMaxWidth) {
99 return (value >= format->frame_size.width()); 105 return (value * kMaxCropFactor >= format->frame_size.width());
100 } else if (constraint_name == MediaStreamVideoSource::kMinHeight) { 106 } else if (constraint_name == MediaStreamVideoSource::kMinHeight) {
101 return (value <= format->frame_size.height()); 107 return (value <= format->frame_size.height());
102 } else if (constraint_name == MediaStreamVideoSource::kMaxHeight) { 108 } else if (constraint_name == MediaStreamVideoSource::kMaxHeight) {
103 return (value >= format->frame_size.height()); 109 return (value * kMaxCropFactor >= format->frame_size.height());
104 } else if (constraint_name == MediaStreamVideoSource::kMinFrameRate) { 110 } else if (constraint_name == MediaStreamVideoSource::kMinFrameRate) {
105 return (value <= format->frame_rate); 111 return (value <= format->frame_rate);
106 } else if (constraint_name == MediaStreamVideoSource::kMaxFrameRate) { 112 } else if (constraint_name == MediaStreamVideoSource::kMaxFrameRate) {
107 if (value == 0) { 113 if (value == 0) {
108 // The frame rate is set by constraint. 114 // The frame rate is set by constraint.
109 // Don't allow 0 as frame rate if it is a mandatory constraint. 115 // 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. 116 // Set the frame rate to 1 if it is not mandatory.
111 if (mandatory) { 117 if (mandatory) {
112 return false; 118 return false;
113 } else { 119 } else {
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 FilterFormatsByConstraint(optional[i], false, &current_candidates); 184 FilterFormatsByConstraint(optional[i], false, &current_candidates);
179 if (!current_candidates.empty()) { 185 if (!current_candidates.empty()) {
180 candidates = current_candidates; 186 candidates = current_candidates;
181 } 187 }
182 } 188 }
183 189
184 // We have done as good as we can to filter the supported resolutions. 190 // We have done as good as we can to filter the supported resolutions.
185 return candidates; 191 return candidates;
186 } 192 }
187 193
188 // Find the format that best matches the default video size. 194 bool GetConstraintValue(const blink::WebMediaConstraints& constraints,
189 // This algorithm is chosen since a resolution must be picked even if no 195 bool mandatory, const blink::WebString& name,
190 // constraints are provided. We don't just select the maximum supported 196 int* value) {
191 // resolution since higher resolution cost more in terms of complexity and 197 blink::WebString value_str;
192 // many cameras perform worse at its maximum supported resolution. 198 bool ret = mandatory ?
193 const media::VideoCaptureFormat& GetBestCaptureFormat( 199 constraints.getMandatoryConstraintValue(name, value_str) :
194 const media::VideoCaptureFormats& formats) { 200 constraints.getOptionalConstraintValue(name, value_str);
195 DCHECK(!formats.empty()); 201 if (ret)
202 base::StringToInt(value_str.utf8(), value);
203 return ret;
204 }
196 205
197 int default_area = 206 // Retrieve the desired max width and height from |constraints|.
198 MediaStreamVideoSource::kDefaultWidth * 207 void GetDesiredMaxWidthAndHeight(const blink::WebMediaConstraints& constraints,
199 MediaStreamVideoSource::kDefaultHeight; 208 int* desired_width, int* desired_height) {
209 bool mandatory = GetConstraintValue(constraints, true,
210 MediaStreamVideoSource::kMaxWidth,
211 desired_width);
212 mandatory |= GetConstraintValue(constraints, true,
213 MediaStreamVideoSource::kMaxHeight,
214 desired_height);
215 if (mandatory)
216 return;
200 217
218 GetConstraintValue(constraints, false, MediaStreamVideoSource::kMaxWidth,
219 desired_width);
220 GetConstraintValue(constraints, false, MediaStreamVideoSource::kMaxHeight,
221 desired_height);
222 }
223
224 const media::VideoCaptureFormat& GetBestFormatBasedOnArea(
225 const media::VideoCaptureFormats& formats,
226 int area) {
201 media::VideoCaptureFormats::const_iterator it = formats.begin(); 227 media::VideoCaptureFormats::const_iterator it = formats.begin();
202 media::VideoCaptureFormats::const_iterator best_it = formats.begin(); 228 media::VideoCaptureFormats::const_iterator best_it = formats.begin();
203 int best_diff = std::numeric_limits<int>::max(); 229 int best_diff = std::numeric_limits<int>::max();
204 for (; it != formats.end(); ++it) { 230 for (; it != formats.end(); ++it) {
205 int diff = abs(default_area - 231 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) { 232 if (diff < best_diff) {
208 best_diff = diff; 233 best_diff = diff;
209 best_it = it; 234 best_it = it;
210 } 235 }
211 } 236 }
212 return *best_it; 237 return *best_it;
213 } 238 }
214 239
240 // Find the format that best matches the default video size.
241 // This algorithm is chosen since a resolution must be picked even if no
242 // constraints are provided. We don't just select the maximum supported
243 // resolution since higher resolutions cost more in terms of complexity and
244 // many cameras have lower frame rate and have more noise in the image at
245 // their maximum supported resolution.
246 void GetBestCaptureFormat(
247 const media::VideoCaptureFormats& formats,
248 const blink::WebMediaConstraints& constraints,
249 media::VideoCaptureFormat* capture_format,
250 gfx::Size* frame_output_size) {
251 DCHECK(!formats.empty());
252 DCHECK(frame_output_size);
253
254 int max_width = std::numeric_limits<int>::max();
255 int max_height = std::numeric_limits<int>::max();;
256 GetDesiredMaxWidthAndHeight(constraints, &max_width, &max_height);
257
258 *capture_format = GetBestFormatBasedOnArea(
259 formats,
260 std::min(max_width, MediaStreamVideoSource::kDefaultWidth) *
261 std::min(max_height, MediaStreamVideoSource::kDefaultHeight));
262
263 *frame_output_size = capture_format->frame_size;
264 if (max_width < frame_output_size->width())
265 frame_output_size->set_width(max_width);
266 if (max_height < frame_output_size->height())
267 frame_output_size->set_height(max_height);
268 }
269
270 // Empty method used for keeping a reference to the original media::VideoFrame
271 // in MediaStreamVideoSource::DeliverVideoFrame if cropping is needed.
272 // The reference to |frame| is kept in the closure that calls this method.
273 void ReleaseOriginalFrame(
274 const scoped_refptr<media::VideoFrame>& frame) {
275 }
276
215 } // anonymous namespace 277 } // anonymous namespace
216 278
217 MediaStreamVideoSource::MediaStreamVideoSource( 279 MediaStreamVideoSource::MediaStreamVideoSource(
218 MediaStreamDependencyFactory* factory) 280 MediaStreamDependencyFactory* factory)
219 : state_(NEW), 281 : state_(NEW),
220 factory_(factory), 282 factory_(factory),
221 capture_adapter_(NULL) { 283 capture_adapter_(NULL) {
222 DCHECK(factory_); 284 DCHECK(factory_);
223 } 285 }
224 286
225 MediaStreamVideoSource::~MediaStreamVideoSource() { 287 MediaStreamVideoSource::~MediaStreamVideoSource() {
226 } 288 }
227 289
228 void MediaStreamVideoSource::AddTrack( 290 void MediaStreamVideoSource::AddTrack(
229 const blink::WebMediaStreamTrack& track, 291 const blink::WebMediaStreamTrack& track,
230 const blink::WebMediaConstraints& constraints, 292 const blink::WebMediaConstraints& constraints,
231 const ConstraintsCallback& callback) { 293 const ConstraintsCallback& callback) {
232 DCHECK(CalledOnValidThread()); 294 DCHECK(CalledOnValidThread());
233 requested_constraints_.push_back(RequestedConstraints(constraints, 295 requested_constraints_.push_back(RequestedConstraints(constraints,
234 callback)); 296 callback));
235 switch (state_) { 297 switch (state_) {
236 case NEW: { 298 case NEW: {
237 // Tab capture and Screen capture needs the maximum requested height 299 // Tab capture and Screen capture needs the maximum requested height
238 // and width to decide on the resolution. 300 // and width to decide on the resolution.
239 blink::WebString max_width;
240 int max_requested_width = 0; 301 int max_requested_width = 0;
241 if (constraints.getMandatoryConstraintValue(kMaxWidth, max_width)) 302 GetConstraintValue(constraints, true, kMaxWidth, &max_requested_width);
242 base::StringToInt(max_width.utf8(), &max_requested_width);
243 303
244 int max_requested_height = 0; 304 int max_requested_height = 0;
245 blink::WebString max_height; 305 GetConstraintValue(constraints, true, kMaxHeight, &max_requested_height);
246 if (constraints.getMandatoryConstraintValue(kMaxHeight, max_height))
247 base::StringToInt(max_height.utf8(), &max_requested_height);
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 have 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
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 originates
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);
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, visible_height);
389 video_frame = media::VideoFrame::WrapVideoFrame(
390 frame, rect, base::Bind(&ReleaseOriginalFrame, frame));
391 }
392
393 if ((frame->format() == media::VideoFrame::I420 ||
394 frame->format() == media::VideoFrame::YV12) &&
395 capture_adapter_) {
396 capture_adapter_->OnFrameCaptured(video_frame);
397 }
307 } 398 }
308 399
309 void MediaStreamVideoSource::OnSupportedFormats( 400 void MediaStreamVideoSource::OnSupportedFormats(
310 const media::VideoCaptureFormats& formats) { 401 const media::VideoCaptureFormats& formats) {
311 DCHECK(CalledOnValidThread()); 402 DCHECK(CalledOnValidThread());
312 DCHECK_EQ(RETRIEVING_CAPABILITIES, state_); 403 DCHECK_EQ(RETRIEVING_CAPABILITIES, state_);
313 404
314 supported_formats_ = formats; 405 supported_formats_ = formats;
315 if (!FindBestFormatWithConstraints(supported_formats_, &current_format_, 406 if (!FindBestFormatWithConstraints(supported_formats_,
316 &current_constraints_)) { 407 &current_format_,
408 &frame_output_size_,
409 &current_constraints_)) {
317 FinalizeAddTrack(); 410 FinalizeAddTrack();
318 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded); 411 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded);
319 return; 412 return;
320 } 413 }
321 414
322 state_ = STARTING; 415 state_ = STARTING;
323 DVLOG(3) << "Starting the capturer with" 416 DVLOG(3) << "Starting the capturer with"
324 << " width = " << current_format_.frame_size.width() 417 << " width = " << current_format_.frame_size.width()
325 << " height = " << current_format_.frame_size.height() 418 << " height = " << current_format_.frame_size.height()
326 << " frame rate = " << current_format_.frame_rate; 419 << " frame rate = " << current_format_.frame_rate;
327 420
328 media::VideoCaptureParams params; 421 media::VideoCaptureParams params;
329 params.requested_format = current_format_; 422 params.requested_format = current_format_;
330 StartSourceImpl(params); 423 StartSourceImpl(params);
331 } 424 }
332 425
333 bool MediaStreamVideoSource::FindBestFormatWithConstraints( 426 bool MediaStreamVideoSource::FindBestFormatWithConstraints(
334 const media::VideoCaptureFormats& formats, 427 const media::VideoCaptureFormats& formats,
335 media::VideoCaptureFormat* best_format, 428 media::VideoCaptureFormat* best_format,
429 gfx::Size* frame_output_size,
336 blink::WebMediaConstraints* resulting_constraints) { 430 blink::WebMediaConstraints* resulting_constraints) {
337 // Find the first constraints that we can fulfilled. 431 // Find the first constraints that we can fulfill.
338 for (std::vector<RequestedConstraints>::iterator request_it = 432 for (std::vector<RequestedConstraints>::iterator request_it =
339 requested_constraints_.begin(); 433 requested_constraints_.begin();
340 request_it != requested_constraints_.end(); ++request_it) { 434 request_it != requested_constraints_.end(); ++request_it) {
341 const blink::WebMediaConstraints& requested_constraints = 435 const blink::WebMediaConstraints& requested_constraints =
342 request_it->constraints; 436 request_it->constraints;
343 437
344 media::VideoCaptureFormats filtered_formats = 438 media::VideoCaptureFormats filtered_formats =
345 FilterFormats(requested_constraints, formats); 439 FilterFormats(requested_constraints, formats);
346 if (filtered_formats.size() > 0) { 440 if (filtered_formats.size() > 0) {
347 // A request with constraints that can be fulfilled. 441 // A request with constraints that can be fulfilled.
348 *best_format = GetBestCaptureFormat(filtered_formats); 442 GetBestCaptureFormat(filtered_formats,
443 requested_constraints,
444 best_format,
445 frame_output_size);
349 *resulting_constraints= requested_constraints; 446 *resulting_constraints= requested_constraints;
350 return true; 447 return true;
351 } 448 }
352 } 449 }
353 return false; 450 return false;
354 } 451 }
355 452
356 void MediaStreamVideoSource::OnStartDone(bool success) { 453 void MediaStreamVideoSource::OnStartDone(bool success) {
357 DCHECK(CalledOnValidThread()); 454 DCHECK(CalledOnValidThread());
358 DVLOG(3) << "OnStartDone({success =" << success << "})"; 455 DVLOG(3) << "OnStartDone({success =" << success << "})";
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 MediaStreamVideoSource::RequestedConstraints::RequestedConstraints( 493 MediaStreamVideoSource::RequestedConstraints::RequestedConstraints(
397 const blink::WebMediaConstraints& constraints, 494 const blink::WebMediaConstraints& constraints,
398 const ConstraintsCallback& callback) 495 const ConstraintsCallback& callback)
399 : constraints(constraints), callback(callback) { 496 : constraints(constraints), callback(callback) {
400 } 497 }
401 498
402 MediaStreamVideoSource::RequestedConstraints::~RequestedConstraints() { 499 MediaStreamVideoSource::RequestedConstraints::~RequestedConstraints() {
403 } 500 }
404 501
405 } // namespace content 502 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/media_stream_video_source.h ('k') | content/renderer/media/media_stream_video_source_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698