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