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 <string> | 9 #include <string> |
10 | 10 |
11 #include "base/debug/trace_event.h" | 11 #include "base/debug/trace_event.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
14 #include "content/child/child_process.h" | 14 #include "content/child/child_process.h" |
15 #include "content/renderer/media/media_stream_constraints_util.h" | 15 #include "content/renderer/media/media_stream_constraints_util.h" |
16 #include "content/renderer/media/media_stream_video_track.h" | 16 #include "content/renderer/media/media_stream_video_track.h" |
17 #include "content/renderer/media/video_frame_deliverer.h" | 17 #include "content/renderer/media/video_track_adapter.h" |
18 | 18 |
19 namespace content { | 19 namespace content { |
20 | 20 |
21 // Constraint keys. Specified by draft-alvestrand-constraints-resolution-00b | 21 // Constraint keys. Specified by draft-alvestrand-constraints-resolution-00b |
22 const char MediaStreamVideoSource::kMinAspectRatio[] = "minAspectRatio"; | 22 const char MediaStreamVideoSource::kMinAspectRatio[] = "minAspectRatio"; |
23 const char MediaStreamVideoSource::kMaxAspectRatio[] = "maxAspectRatio"; | 23 const char MediaStreamVideoSource::kMaxAspectRatio[] = "maxAspectRatio"; |
24 const char MediaStreamVideoSource::kMaxWidth[] = "maxWidth"; | 24 const char MediaStreamVideoSource::kMaxWidth[] = "maxWidth"; |
25 const char MediaStreamVideoSource::kMinWidth[] = "minWidth"; | 25 const char MediaStreamVideoSource::kMinWidth[] = "minWidth"; |
26 const char MediaStreamVideoSource::kMaxHeight[] = "maxHeight"; | 26 const char MediaStreamVideoSource::kMaxHeight[] = "maxHeight"; |
27 const char MediaStreamVideoSource::kMinHeight[] = "minHeight"; | 27 const char MediaStreamVideoSource::kMinHeight[] = "minHeight"; |
(...skipping 19 matching lines...) Expand all Loading... |
47 | 47 |
48 // Google-specific key prefix. Constraints with this prefix are ignored if they | 48 // Google-specific key prefix. Constraints with this prefix are ignored if they |
49 // are unknown. | 49 // are unknown. |
50 const char kGooglePrefix[] = "goog"; | 50 const char kGooglePrefix[] = "goog"; |
51 | 51 |
52 // MediaStreamVideoSource supports cropping of video frames but only up to | 52 // MediaStreamVideoSource supports cropping of video frames but only up to |
53 // kMaxCropFactor. Ie - if a constraint is set to maxHeight 360, an original | 53 // kMaxCropFactor. Ie - if a constraint is set to maxHeight 360, an original |
54 // input frame height of max 360 * kMaxCropFactor pixels is accepted. | 54 // input frame height of max 360 * kMaxCropFactor pixels is accepted. |
55 const int kMaxCropFactor = 2; | 55 const int kMaxCropFactor = 2; |
56 | 56 |
| 57 // Returns true if |constraint| has mandatory constraints. |
| 58 bool HasMandatoryConstraints(const blink::WebMediaConstraints& constraints) { |
| 59 blink::WebVector<blink::WebMediaConstraint> mandatory_constraints; |
| 60 constraints.getMandatoryConstraints(mandatory_constraints); |
| 61 return !mandatory_constraints.isEmpty(); |
| 62 } |
| 63 |
| 64 // Retrieve the desired max width and height from |constraints|. If not set, |
| 65 // the |desired_width| and |desired_height| are set to |
| 66 // std::numeric_limits<int>::max(); |
| 67 // If either max width or height is set as a mandatory constraint, the optional |
| 68 // constraints are not checked. |
| 69 void GetDesiredMaxWidthAndHeight(const blink::WebMediaConstraints& constraints, |
| 70 int* desired_width, int* desired_height) { |
| 71 *desired_width = std::numeric_limits<int>::max(); |
| 72 *desired_height = std::numeric_limits<int>::max(); |
| 73 |
| 74 bool mandatory = GetMandatoryConstraintValueAsInteger( |
| 75 constraints, |
| 76 MediaStreamVideoSource::kMaxWidth, |
| 77 desired_width); |
| 78 mandatory |= GetMandatoryConstraintValueAsInteger( |
| 79 constraints, |
| 80 MediaStreamVideoSource::kMaxHeight, |
| 81 desired_height); |
| 82 if (mandatory) |
| 83 return; |
| 84 |
| 85 GetOptionalConstraintValueAsInteger(constraints, |
| 86 MediaStreamVideoSource::kMaxWidth, |
| 87 desired_width); |
| 88 GetOptionalConstraintValueAsInteger(constraints, |
| 89 MediaStreamVideoSource::kMaxHeight, |
| 90 desired_height); |
| 91 } |
| 92 |
| 93 // Retrieve the desired max and min aspect ratio from |constraints|. If not set, |
| 94 // the |min_aspect_ratio| is set to 0 and |max_aspect_ratio| is set to |
| 95 // std::numeric_limits<double>::max(); |
| 96 // If either min or max aspect ratio is set as a mandatory constraint, the |
| 97 // optional constraints are not checked. |
| 98 void GetDesiredMinAndMaxAspectRatio( |
| 99 const blink::WebMediaConstraints& constraints, |
| 100 double* min_aspect_ratio, |
| 101 double* max_aspect_ratio) { |
| 102 *min_aspect_ratio = 0; |
| 103 *max_aspect_ratio = std::numeric_limits<double>::max(); |
| 104 |
| 105 bool mandatory = GetMandatoryConstraintValueAsDouble( |
| 106 constraints, |
| 107 MediaStreamVideoSource::kMinAspectRatio, |
| 108 min_aspect_ratio); |
| 109 mandatory |= GetMandatoryConstraintValueAsDouble( |
| 110 constraints, |
| 111 MediaStreamVideoSource::kMaxAspectRatio, |
| 112 max_aspect_ratio); |
| 113 if (mandatory) |
| 114 return; |
| 115 |
| 116 GetOptionalConstraintValueAsDouble( |
| 117 constraints, |
| 118 MediaStreamVideoSource::kMinAspectRatio, |
| 119 min_aspect_ratio); |
| 120 GetOptionalConstraintValueAsDouble( |
| 121 constraints, |
| 122 MediaStreamVideoSource::kMaxAspectRatio, |
| 123 max_aspect_ratio); |
| 124 } |
| 125 |
57 // Returns true if |constraint| is fulfilled. |format| can be changed | 126 // Returns true if |constraint| is fulfilled. |format| can be changed |
58 // changed by a constraint. Ie - the frame rate can be changed by setting | 127 // changed by a constraint. Ie - the frame rate can be changed by setting |
59 // maxFrameRate. | 128 // maxFrameRate. |
60 bool UpdateFormatForConstraint( | 129 bool UpdateFormatForConstraint( |
61 const blink::WebMediaConstraint& constraint, | 130 const blink::WebMediaConstraint& constraint, |
62 bool mandatory, | 131 bool mandatory, |
63 media::VideoCaptureFormat* format) { | 132 media::VideoCaptureFormat* format) { |
64 DCHECK(format != NULL); | 133 DCHECK(format != NULL); |
65 | 134 |
66 if (!format->IsValid()) | 135 if (!format->IsValid()) |
(...skipping 13 matching lines...) Expand all Loading... |
80 return true; | 149 return true; |
81 } | 150 } |
82 | 151 |
83 // Ignore Chrome specific Tab capture constraints. | 152 // Ignore Chrome specific Tab capture constraints. |
84 if (constraint_name == kMediaStreamSource || | 153 if (constraint_name == kMediaStreamSource || |
85 constraint_name == kMediaStreamSourceId) | 154 constraint_name == kMediaStreamSourceId) |
86 return true; | 155 return true; |
87 | 156 |
88 if (constraint_name == MediaStreamVideoSource::kMinAspectRatio || | 157 if (constraint_name == MediaStreamVideoSource::kMinAspectRatio || |
89 constraint_name == MediaStreamVideoSource::kMaxAspectRatio) { | 158 constraint_name == MediaStreamVideoSource::kMaxAspectRatio) { |
90 double double_value = 0; | 159 // These constraints are handled by cropping if the camera outputs the wrong |
91 base::StringToDouble(constraint_value, &double_value); | 160 // aspect ratio. |
92 | 161 double value; |
93 // The aspect ratio in |constraint.m_value| has been converted to a string | 162 return base::StringToDouble(constraint_value, &value); |
94 // and back to a double, so it may have a rounding error. | |
95 // E.g if the value 1/3 is converted to a string, the string will not have | |
96 // infinite length. | |
97 // We add a margin of 0.0005 which is high enough to detect the same aspect | |
98 // ratio but small enough to avoid matching wrong aspect ratios. | |
99 const double kRoundingTruncation = 0.0005; | |
100 double ratio = static_cast<double>(format->frame_size.width()) / | |
101 format->frame_size.height(); | |
102 if (constraint_name == MediaStreamVideoSource::kMinAspectRatio) | |
103 return (double_value <= ratio + kRoundingTruncation); | |
104 // Subtract 0.0005 to avoid rounding problems. Same as above. | |
105 return (double_value >= ratio - kRoundingTruncation); | |
106 } | 163 } |
107 | 164 |
108 int value; | 165 int value; |
109 if (!base::StringToInt(constraint_value, &value)) { | 166 if (!base::StringToInt(constraint_value, &value)) { |
110 DLOG(WARNING) << "Can't parse MediaStream constraint. Name:" | 167 DLOG(WARNING) << "Can't parse MediaStream constraint. Name:" |
111 << constraint_name << " Value:" << constraint_value; | 168 << constraint_name << " Value:" << constraint_value; |
112 return false; | 169 return false; |
113 } | 170 } |
114 if (constraint_name == MediaStreamVideoSource::kMinWidth) { | 171 if (constraint_name == MediaStreamVideoSource::kMinWidth) { |
115 return (value <= format->frame_size.width()); | 172 return (value <= format->frame_size.width()); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 } | 222 } |
166 | 223 |
167 // Returns the media::VideoCaptureFormats that matches |constraints|. | 224 // Returns the media::VideoCaptureFormats that matches |constraints|. |
168 media::VideoCaptureFormats FilterFormats( | 225 media::VideoCaptureFormats FilterFormats( |
169 const blink::WebMediaConstraints& constraints, | 226 const blink::WebMediaConstraints& constraints, |
170 const media::VideoCaptureFormats& supported_formats) { | 227 const media::VideoCaptureFormats& supported_formats) { |
171 if (constraints.isNull()) { | 228 if (constraints.isNull()) { |
172 return supported_formats; | 229 return supported_formats; |
173 } | 230 } |
174 | 231 |
| 232 double max_aspect_ratio; |
| 233 double min_aspect_ratio; |
| 234 GetDesiredMinAndMaxAspectRatio(constraints, |
| 235 &min_aspect_ratio, |
| 236 &max_aspect_ratio); |
| 237 |
| 238 if (min_aspect_ratio > max_aspect_ratio || max_aspect_ratio < 0.05f) { |
| 239 DLOG(WARNING) << "Wrong requested aspect ratio."; |
| 240 return media::VideoCaptureFormats(); |
| 241 } |
| 242 |
| 243 int min_width = 0; |
| 244 GetMandatoryConstraintValueAsInteger(constraints, |
| 245 MediaStreamVideoSource::kMinWidth, |
| 246 &min_width); |
| 247 int min_height = 0; |
| 248 GetMandatoryConstraintValueAsInteger(constraints, |
| 249 MediaStreamVideoSource::kMinHeight, |
| 250 &min_height); |
| 251 int max_width; |
| 252 int max_height; |
| 253 GetDesiredMaxWidthAndHeight(constraints, &max_width, &max_height); |
| 254 |
| 255 if (min_width > max_width || min_height > max_height) |
| 256 return media::VideoCaptureFormats(); |
| 257 |
175 blink::WebVector<blink::WebMediaConstraint> mandatory; | 258 blink::WebVector<blink::WebMediaConstraint> mandatory; |
176 blink::WebVector<blink::WebMediaConstraint> optional; | 259 blink::WebVector<blink::WebMediaConstraint> optional; |
177 constraints.getMandatoryConstraints(mandatory); | 260 constraints.getMandatoryConstraints(mandatory); |
178 constraints.getOptionalConstraints(optional); | 261 constraints.getOptionalConstraints(optional); |
179 | |
180 media::VideoCaptureFormats candidates = supported_formats; | 262 media::VideoCaptureFormats candidates = supported_formats; |
181 | |
182 for (size_t i = 0; i < mandatory.size(); ++i) | 263 for (size_t i = 0; i < mandatory.size(); ++i) |
183 FilterFormatsByConstraint(mandatory[i], true, &candidates); | 264 FilterFormatsByConstraint(mandatory[i], true, &candidates); |
184 | 265 |
185 if (candidates.empty()) | 266 if (candidates.empty()) |
186 return candidates; | 267 return candidates; |
187 | 268 |
188 // Ok - all mandatory checked and we still have candidates. | 269 // Ok - all mandatory checked and we still have candidates. |
189 // Let's try filtering using the optional constraints. The optional | 270 // Let's try filtering using the optional constraints. The optional |
190 // constraints must be filtered in the order they occur in |optional|. | 271 // constraints must be filtered in the order they occur in |optional|. |
191 // But if a constraint produce zero candidates, the constraint is ignored and | 272 // But if a constraint produce zero candidates, the constraint is ignored and |
192 // the next constraint is tested. | 273 // the next constraint is tested. |
193 // http://dev.w3.org/2011/webrtc/editor/getusermedia.html#idl-def-Constraints | 274 // http://dev.w3.org/2011/webrtc/editor/getusermedia.html#idl-def-Constraints |
194 for (size_t i = 0; i < optional.size(); ++i) { | 275 for (size_t i = 0; i < optional.size(); ++i) { |
195 media::VideoCaptureFormats current_candidates = candidates; | 276 media::VideoCaptureFormats current_candidates = candidates; |
196 FilterFormatsByConstraint(optional[i], false, ¤t_candidates); | 277 FilterFormatsByConstraint(optional[i], false, ¤t_candidates); |
197 if (!current_candidates.empty()) { | 278 if (!current_candidates.empty()) { |
198 candidates = current_candidates; | 279 candidates = current_candidates; |
199 } | 280 } |
200 } | 281 } |
201 | 282 |
202 // We have done as good as we can to filter the supported resolutions. | 283 // We have done as good as we can to filter the supported resolutions. |
203 return candidates; | 284 return candidates; |
204 } | 285 } |
205 | 286 |
206 // Returns true if |constraint| has mandatory constraints. | |
207 bool HasMandatoryConstraints(const blink::WebMediaConstraints& constraints) { | |
208 blink::WebVector<blink::WebMediaConstraint> mandatory_constraints; | |
209 constraints.getMandatoryConstraints(mandatory_constraints); | |
210 return !mandatory_constraints.isEmpty(); | |
211 } | |
212 | |
213 // Retrieve the desired max width and height from |constraints|. | |
214 void GetDesiredMaxWidthAndHeight(const blink::WebMediaConstraints& constraints, | |
215 int* desired_width, int* desired_height) { | |
216 bool mandatory = GetMandatoryConstraintValueAsInteger( | |
217 constraints, MediaStreamVideoSource::kMaxWidth, desired_width); | |
218 mandatory |= GetMandatoryConstraintValueAsInteger( | |
219 constraints, MediaStreamVideoSource::kMaxHeight, desired_height); | |
220 // Skip the optional constraints if any of the mandatory constraint is | |
221 // specified. | |
222 if (mandatory) | |
223 return; | |
224 | |
225 GetOptionalConstraintValueAsInteger(constraints, | |
226 MediaStreamVideoSource::kMaxWidth, | |
227 desired_width); | |
228 GetOptionalConstraintValueAsInteger(constraints, | |
229 MediaStreamVideoSource::kMaxHeight, | |
230 desired_height); | |
231 } | |
232 | |
233 const media::VideoCaptureFormat& GetBestFormatBasedOnArea( | 287 const media::VideoCaptureFormat& GetBestFormatBasedOnArea( |
234 const media::VideoCaptureFormats& formats, | 288 const media::VideoCaptureFormats& formats, |
235 int area) { | 289 int area) { |
236 media::VideoCaptureFormats::const_iterator it = formats.begin(); | 290 media::VideoCaptureFormats::const_iterator it = formats.begin(); |
237 media::VideoCaptureFormats::const_iterator best_it = formats.begin(); | 291 media::VideoCaptureFormats::const_iterator best_it = formats.begin(); |
238 int best_diff = std::numeric_limits<int>::max(); | 292 int best_diff = std::numeric_limits<int>::max(); |
239 for (; it != formats.end(); ++it) { | 293 for (; it != formats.end(); ++it) { |
240 int diff = abs(area - it->frame_size.width() * it->frame_size.height()); | 294 int diff = abs(area - it->frame_size.width() * it->frame_size.height()); |
241 if (diff < best_diff) { | 295 if (diff < best_diff) { |
242 best_diff = diff; | 296 best_diff = diff; |
243 best_it = it; | 297 best_it = it; |
244 } | 298 } |
245 } | 299 } |
246 return *best_it; | 300 return *best_it; |
247 } | 301 } |
248 | 302 |
249 // Find the format that best matches the default video size. | 303 // Find the format that best matches the default video size. |
250 // This algorithm is chosen since a resolution must be picked even if no | 304 // This algorithm is chosen since a resolution must be picked even if no |
251 // constraints are provided. We don't just select the maximum supported | 305 // constraints are provided. We don't just select the maximum supported |
252 // resolution since higher resolutions cost more in terms of complexity and | 306 // resolution since higher resolutions cost more in terms of complexity and |
253 // many cameras have lower frame rate and have more noise in the image at | 307 // many cameras have lower frame rate and have more noise in the image at |
254 // their maximum supported resolution. | 308 // their maximum supported resolution. |
255 void GetBestCaptureFormat( | 309 void GetBestCaptureFormat( |
256 const media::VideoCaptureFormats& formats, | 310 const media::VideoCaptureFormats& formats, |
257 const blink::WebMediaConstraints& constraints, | 311 const blink::WebMediaConstraints& constraints, |
258 media::VideoCaptureFormat* capture_format, | 312 media::VideoCaptureFormat* capture_format) { |
259 gfx::Size* max_frame_output_size) { | |
260 DCHECK(!formats.empty()); | 313 DCHECK(!formats.empty()); |
261 DCHECK(max_frame_output_size); | |
262 | 314 |
263 int max_width = std::numeric_limits<int>::max(); | 315 int max_width; |
264 int max_height = std::numeric_limits<int>::max();; | 316 int max_height; |
265 GetDesiredMaxWidthAndHeight(constraints, &max_width, &max_height); | 317 GetDesiredMaxWidthAndHeight(constraints, &max_width, &max_height); |
266 | 318 |
267 *capture_format = GetBestFormatBasedOnArea( | 319 *capture_format = GetBestFormatBasedOnArea( |
268 formats, | 320 formats, |
269 std::min(max_width, MediaStreamVideoSource::kDefaultWidth) * | 321 std::min(max_width, MediaStreamVideoSource::kDefaultWidth) * |
270 std::min(max_height, MediaStreamVideoSource::kDefaultHeight)); | 322 std::min(max_height, MediaStreamVideoSource::kDefaultHeight)); |
271 | |
272 max_frame_output_size->set_width(max_width); | |
273 max_frame_output_size->set_height(max_height); | |
274 } | |
275 | |
276 // Empty method used for keeping a reference to the original media::VideoFrame | |
277 // in MediaStreamVideoSource::FrameDeliverer::DeliverFrameOnIO if cropping is | |
278 // needed. The reference to |frame| is kept in the closure that calls this | |
279 // method. | |
280 void ReleaseOriginalFrame( | |
281 const scoped_refptr<media::VideoFrame>& frame) { | |
282 } | 323 } |
283 | 324 |
284 } // anonymous namespace | 325 } // anonymous namespace |
285 | 326 |
286 // Helper class used for delivering video frames to all registered tracks | |
287 // on the IO-thread. | |
288 class MediaStreamVideoSource::FrameDeliverer : public VideoFrameDeliverer { | |
289 public: | |
290 FrameDeliverer( | |
291 const scoped_refptr<base::MessageLoopProxy>& io_message_loop) | |
292 : VideoFrameDeliverer(io_message_loop) { | |
293 } | |
294 | |
295 // Register |callback| to receive video frames of max size | |
296 // |max_frame_output_size| on the IO thread. | |
297 // TODO(perkj): Currently |max_frame_output_size| must be the same for all | |
298 // |callbacks|. | |
299 void AddCallback(void* id, | |
300 const VideoCaptureDeliverFrameCB& callback, | |
301 const gfx::Size& max_frame_output_size) { | |
302 DCHECK(thread_checker().CalledOnValidThread()); | |
303 io_message_loop()->PostTask( | |
304 FROM_HERE, | |
305 base::Bind( | |
306 &FrameDeliverer::AddCallbackWithResolutionOnIO, | |
307 this, id, callback, max_frame_output_size)); | |
308 } | |
309 | |
310 virtual void DeliverFrameOnIO( | |
311 const scoped_refptr<media::VideoFrame>& frame, | |
312 const media::VideoCaptureFormat& format) OVERRIDE { | |
313 DCHECK(io_message_loop()->BelongsToCurrentThread()); | |
314 TRACE_EVENT0("video", "MediaStreamVideoSource::DeliverFrameOnIO"); | |
315 if (max_output_size_.IsEmpty()) | |
316 return; // Frame received before the output has been decided. | |
317 | |
318 scoped_refptr<media::VideoFrame> video_frame(frame); | |
319 const gfx::Size& visible_size = frame->visible_rect().size(); | |
320 if (visible_size.width() > max_output_size_.width() || | |
321 visible_size.height() > max_output_size_.height()) { | |
322 // If |frame| is not the size that is expected, we need to crop it by | |
323 // providing a new |visible_rect|. The new visible rect must be within the | |
324 // original |visible_rect|. | |
325 gfx::Rect output_rect = frame->visible_rect(); | |
326 output_rect.ClampToCenteredSize(max_output_size_); | |
327 // TODO(perkj): Allow cropping of textures once http://crbug/362521 is | |
328 // fixed. | |
329 if (frame->format() != media::VideoFrame::NATIVE_TEXTURE) { | |
330 video_frame = media::VideoFrame::WrapVideoFrame( | |
331 frame, | |
332 output_rect, | |
333 output_rect.size(), | |
334 base::Bind(&ReleaseOriginalFrame, frame)); | |
335 } | |
336 } | |
337 VideoFrameDeliverer::DeliverFrameOnIO(video_frame, format); | |
338 } | |
339 | |
340 protected: | |
341 virtual ~FrameDeliverer() { | |
342 } | |
343 | |
344 void AddCallbackWithResolutionOnIO( | |
345 void* id, | |
346 const VideoCaptureDeliverFrameCB& callback, | |
347 const gfx::Size& max_frame_output_size) { | |
348 DCHECK(io_message_loop()->BelongsToCurrentThread()); | |
349 // Currently we only support one frame output size. | |
350 DCHECK(!max_frame_output_size.IsEmpty() && | |
351 (max_output_size_.IsEmpty() || | |
352 max_output_size_ == max_frame_output_size)); | |
353 max_output_size_ = max_frame_output_size; | |
354 VideoFrameDeliverer::AddCallbackOnIO(id, callback); | |
355 } | |
356 | |
357 private: | |
358 gfx::Size max_output_size_; | |
359 }; | |
360 | |
361 // static | 327 // static |
362 MediaStreamVideoSource* MediaStreamVideoSource::GetVideoSource( | 328 MediaStreamVideoSource* MediaStreamVideoSource::GetVideoSource( |
363 const blink::WebMediaStreamSource& source) { | 329 const blink::WebMediaStreamSource& source) { |
364 return static_cast<MediaStreamVideoSource*>(source.extraData()); | 330 return static_cast<MediaStreamVideoSource*>(source.extraData()); |
365 } | 331 } |
366 | 332 |
367 // static | 333 // static |
368 bool MediaStreamVideoSource::IsConstraintSupported(const std::string& name) { | 334 bool MediaStreamVideoSource::IsConstraintSupported(const std::string& name) { |
369 for (size_t i = 0; i < arraysize(kSupportedConstraints); ++i) { | 335 for (size_t i = 0; i < arraysize(kSupportedConstraints); ++i) { |
370 if (kSupportedConstraints[i] == name) | 336 if (kSupportedConstraints[i] == name) |
371 return true; | 337 return true; |
372 } | 338 } |
373 return false; | 339 return false; |
374 } | 340 } |
375 | 341 |
376 MediaStreamVideoSource::MediaStreamVideoSource() | 342 MediaStreamVideoSource::MediaStreamVideoSource() |
377 : state_(NEW), | 343 : state_(NEW), |
378 frame_deliverer_( | 344 track_adapter_(new VideoTrackAdapter( |
379 new MediaStreamVideoSource::FrameDeliverer( | 345 ChildProcess::current()->io_message_loop_proxy())), |
380 ChildProcess::current()->io_message_loop_proxy())), | |
381 weak_factory_(this) { | 346 weak_factory_(this) { |
382 } | 347 } |
383 | 348 |
384 MediaStreamVideoSource::~MediaStreamVideoSource() { | 349 MediaStreamVideoSource::~MediaStreamVideoSource() { |
385 DVLOG(3) << "~MediaStreamVideoSource()"; | 350 DVLOG(3) << "~MediaStreamVideoSource()"; |
386 } | 351 } |
387 | 352 |
388 void MediaStreamVideoSource::AddTrack( | 353 void MediaStreamVideoSource::AddTrack( |
389 MediaStreamVideoTrack* track, | 354 MediaStreamVideoTrack* track, |
390 const VideoCaptureDeliverFrameCB& frame_callback, | 355 const VideoCaptureDeliverFrameCB& frame_callback, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 } | 398 } |
434 } | 399 } |
435 } | 400 } |
436 | 401 |
437 void MediaStreamVideoSource::RemoveTrack(MediaStreamVideoTrack* video_track) { | 402 void MediaStreamVideoSource::RemoveTrack(MediaStreamVideoTrack* video_track) { |
438 DCHECK(CalledOnValidThread()); | 403 DCHECK(CalledOnValidThread()); |
439 std::vector<MediaStreamVideoTrack*>::iterator it = | 404 std::vector<MediaStreamVideoTrack*>::iterator it = |
440 std::find(tracks_.begin(), tracks_.end(), video_track); | 405 std::find(tracks_.begin(), tracks_.end(), video_track); |
441 DCHECK(it != tracks_.end()); | 406 DCHECK(it != tracks_.end()); |
442 tracks_.erase(it); | 407 tracks_.erase(it); |
443 // Call |RemoveCallback| here even if adding the track has failed and | 408 |
444 // frame_deliverer_->AddCallback has not been called. | 409 // Check if |video_track| is waiting for applying new constraints and remove |
445 frame_deliverer_->RemoveCallback(video_track); | 410 // the request in that case. |
| 411 for (std::vector<RequestedConstraints>::iterator it = |
| 412 requested_constraints_.begin(); |
| 413 it != requested_constraints_.end(); ++it) { |
| 414 if (it->track == video_track) { |
| 415 requested_constraints_.erase(it); |
| 416 break; |
| 417 } |
| 418 } |
| 419 // Call |frame_adapter_->RemoveTrack| here even if adding the track has |
| 420 // failed and |frame_adapter_->AddCallback| has not been called. |
| 421 track_adapter_->RemoveTrack(video_track); |
446 | 422 |
447 if (tracks_.empty()) | 423 if (tracks_.empty()) |
448 StopSource(); | 424 StopSource(); |
449 } | 425 } |
450 | 426 |
451 const scoped_refptr<base::MessageLoopProxy>& | 427 const scoped_refptr<base::MessageLoopProxy>& |
452 MediaStreamVideoSource::io_message_loop() const { | 428 MediaStreamVideoSource::io_message_loop() const { |
453 return frame_deliverer_->io_message_loop(); | 429 DCHECK(CalledOnValidThread()); |
| 430 return track_adapter_->io_message_loop(); |
454 } | 431 } |
455 | 432 |
456 void MediaStreamVideoSource::DoStopSource() { | 433 void MediaStreamVideoSource::DoStopSource() { |
457 DCHECK(CalledOnValidThread()); | 434 DCHECK(CalledOnValidThread()); |
458 DVLOG(3) << "DoStopSource()"; | 435 DVLOG(3) << "DoStopSource()"; |
459 if (state_ == ENDED) | 436 if (state_ == ENDED) |
460 return; | 437 return; |
461 StopSourceImpl(); | 438 StopSourceImpl(); |
462 state_ = ENDED; | 439 state_ = ENDED; |
463 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded); | 440 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded); |
464 } | 441 } |
465 | 442 |
466 void MediaStreamVideoSource::OnSupportedFormats( | 443 void MediaStreamVideoSource::OnSupportedFormats( |
467 const media::VideoCaptureFormats& formats) { | 444 const media::VideoCaptureFormats& formats) { |
468 DCHECK(CalledOnValidThread()); | 445 DCHECK(CalledOnValidThread()); |
469 DCHECK_EQ(RETRIEVING_CAPABILITIES, state_); | 446 DCHECK_EQ(RETRIEVING_CAPABILITIES, state_); |
470 | 447 |
471 supported_formats_ = formats; | 448 supported_formats_ = formats; |
472 if (!FindBestFormatWithConstraints(supported_formats_, | 449 if (!FindBestFormatWithConstraints(supported_formats_, |
473 ¤t_format_, | 450 ¤t_format_)) { |
474 &max_frame_output_size_, | |
475 ¤t_constraints_)) { | |
476 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded); | 451 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded); |
477 // This object can be deleted after calling FinalizeAddTrack. See comment | 452 // This object can be deleted after calling FinalizeAddTrack. See comment |
478 // in the header file. | 453 // in the header file. |
479 FinalizeAddTrack(); | 454 FinalizeAddTrack(); |
480 return; | 455 return; |
481 } | 456 } |
482 | 457 |
483 state_ = STARTING; | 458 state_ = STARTING; |
484 DVLOG(3) << "Starting the capturer with" | 459 DVLOG(3) << "Starting the capturer with" |
485 << " width = " << current_format_.frame_size.width() | 460 << " width = " << current_format_.frame_size.width() |
486 << " height = " << current_format_.frame_size.height() | 461 << " height = " << current_format_.frame_size.height() |
487 << " frame rate = " << current_format_.frame_rate; | 462 << " frame rate = " << current_format_.frame_rate; |
488 | 463 |
489 media::VideoCaptureParams params; | 464 media::VideoCaptureParams params; |
490 params.requested_format = current_format_; | 465 params.requested_format = current_format_; |
491 StartSourceImpl( | 466 StartSourceImpl( |
492 params, | 467 params, |
493 base::Bind(&MediaStreamVideoSource::FrameDeliverer::DeliverFrameOnIO, | 468 base::Bind(&VideoTrackAdapter::DeliverFrameOnIO, track_adapter_)); |
494 frame_deliverer_)); | |
495 } | 469 } |
496 | 470 |
497 bool MediaStreamVideoSource::FindBestFormatWithConstraints( | 471 bool MediaStreamVideoSource::FindBestFormatWithConstraints( |
498 const media::VideoCaptureFormats& formats, | 472 const media::VideoCaptureFormats& formats, |
499 media::VideoCaptureFormat* best_format, | 473 media::VideoCaptureFormat* best_format) { |
500 gfx::Size* max_frame_output_size, | |
501 blink::WebMediaConstraints* resulting_constraints) { | |
502 // Find the first constraints that we can fulfill. | 474 // Find the first constraints that we can fulfill. |
503 for (std::vector<RequestedConstraints>::iterator request_it = | 475 for (std::vector<RequestedConstraints>::iterator request_it = |
504 requested_constraints_.begin(); | 476 requested_constraints_.begin(); |
505 request_it != requested_constraints_.end(); ++request_it) { | 477 request_it != requested_constraints_.end(); ++request_it) { |
506 const blink::WebMediaConstraints& requested_constraints = | 478 const blink::WebMediaConstraints& requested_constraints = |
507 request_it->constraints; | 479 request_it->constraints; |
508 | 480 |
509 // If the source doesn't support capability enumeration it is still ok if | 481 // If the source doesn't support capability enumeration it is still ok if |
510 // no mandatory constraints have been specified. That just means that | 482 // no mandatory constraints have been specified. That just means that |
511 // we will start with whatever format is native to the source. | 483 // we will start with whatever format is native to the source. |
512 if (formats.empty() && !HasMandatoryConstraints(requested_constraints)) { | 484 if (formats.empty() && !HasMandatoryConstraints(requested_constraints)) { |
513 *best_format = media::VideoCaptureFormat(); | 485 *best_format = media::VideoCaptureFormat(); |
514 *resulting_constraints = requested_constraints; | |
515 *max_frame_output_size = gfx::Size(std::numeric_limits<int>::max(), | |
516 std::numeric_limits<int>::max()); | |
517 return true; | 486 return true; |
518 } | 487 } |
519 media::VideoCaptureFormats filtered_formats = | 488 media::VideoCaptureFormats filtered_formats = |
520 FilterFormats(requested_constraints, formats); | 489 FilterFormats(requested_constraints, formats); |
521 if (filtered_formats.size() > 0) { | 490 if (filtered_formats.size() > 0) { |
522 // A request with constraints that can be fulfilled. | 491 // A request with constraints that can be fulfilled. |
523 GetBestCaptureFormat(filtered_formats, | 492 GetBestCaptureFormat(filtered_formats, |
524 requested_constraints, | 493 requested_constraints, |
525 best_format, | 494 best_format); |
526 max_frame_output_size); | |
527 *resulting_constraints= requested_constraints; | |
528 return true; | 495 return true; |
529 } | 496 } |
530 } | 497 } |
531 return false; | 498 return false; |
532 } | 499 } |
533 | 500 |
534 void MediaStreamVideoSource::OnStartDone(bool success) { | 501 void MediaStreamVideoSource::OnStartDone(bool success) { |
535 DCHECK(CalledOnValidThread()); | 502 DCHECK(CalledOnValidThread()); |
536 DVLOG(3) << "OnStartDone({success =" << success << "})"; | 503 DVLOG(3) << "OnStartDone({success =" << success << "})"; |
537 if (success) { | 504 if (success) { |
(...skipping 21 matching lines...) Expand all Loading... |
559 it != callbacks.end(); ++it) { | 526 it != callbacks.end(); ++it) { |
560 // The track has been added successfully if the source has started and | 527 // The track has been added successfully if the source has started and |
561 // there are either no mandatory constraints and the source doesn't expose | 528 // there are either no mandatory constraints and the source doesn't expose |
562 // its format capabilities, or the constraints and the format match. | 529 // its format capabilities, or the constraints and the format match. |
563 // For example, a remote source doesn't expose its format capabilities. | 530 // For example, a remote source doesn't expose its format capabilities. |
564 bool success = | 531 bool success = |
565 state_ == STARTED && | 532 state_ == STARTED && |
566 ((!current_format_.IsValid() && !HasMandatoryConstraints( | 533 ((!current_format_.IsValid() && !HasMandatoryConstraints( |
567 it->constraints)) || | 534 it->constraints)) || |
568 !FilterFormats(it->constraints, formats).empty()); | 535 !FilterFormats(it->constraints, formats).empty()); |
| 536 |
569 if (success) { | 537 if (success) { |
570 frame_deliverer_->AddCallback(it->track, it->frame_callback, | 538 int max_width; |
571 max_frame_output_size_); | 539 int max_height; |
| 540 GetDesiredMaxWidthAndHeight(it->constraints, &max_width, &max_height); |
| 541 double max_aspect_ratio; |
| 542 double min_aspect_ratio; |
| 543 GetDesiredMinAndMaxAspectRatio(it->constraints, |
| 544 &min_aspect_ratio, |
| 545 &max_aspect_ratio); |
| 546 track_adapter_->AddTrack(it->track,it->frame_callback, |
| 547 max_width, max_height, |
| 548 min_aspect_ratio, max_aspect_ratio); |
572 } | 549 } |
| 550 |
573 DVLOG(3) << "FinalizeAddTrack() success " << success; | 551 DVLOG(3) << "FinalizeAddTrack() success " << success; |
| 552 |
574 if (!it->callback.is_null()) | 553 if (!it->callback.is_null()) |
575 it->callback.Run(this, success); | 554 it->callback.Run(this, success); |
576 } | 555 } |
577 } | 556 } |
578 | 557 |
579 void MediaStreamVideoSource::SetReadyState( | 558 void MediaStreamVideoSource::SetReadyState( |
580 blink::WebMediaStreamSource::ReadyState state) { | 559 blink::WebMediaStreamSource::ReadyState state) { |
581 if (!owner().isNull()) { | 560 if (!owner().isNull()) { |
582 owner().setReadyState(state); | 561 owner().setReadyState(state); |
583 } | 562 } |
(...skipping 11 matching lines...) Expand all Loading... |
595 : track(track), | 574 : track(track), |
596 frame_callback(frame_callback), | 575 frame_callback(frame_callback), |
597 constraints(constraints), | 576 constraints(constraints), |
598 callback(callback) { | 577 callback(callback) { |
599 } | 578 } |
600 | 579 |
601 MediaStreamVideoSource::RequestedConstraints::~RequestedConstraints() { | 580 MediaStreamVideoSource::RequestedConstraints::~RequestedConstraints() { |
602 } | 581 } |
603 | 582 |
604 } // namespace content | 583 } // namespace content |
OLD | NEW |