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/logging.h" | 11 #include "base/logging.h" |
12 #include "base/macros.h" | 12 #include "base/macros.h" |
13 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
14 #include "base/trace_event/trace_event.h" | 14 #include "base/trace_event/trace_event.h" |
15 #include "content/child/child_process.h" | 15 #include "content/child/child_process.h" |
16 #include "content/renderer/media/media_stream_constraints_util.h" | |
17 #include "content/renderer/media/media_stream_video_track.h" | 16 #include "content/renderer/media/media_stream_video_track.h" |
18 #include "content/renderer/media/video_track_adapter.h" | 17 #include "content/renderer/media/video_track_adapter.h" |
19 | 18 |
20 namespace content { | 19 namespace content { |
21 | 20 |
22 // Constraint keys. Specified by draft-alvestrand-constraints-resolution-00b | 21 // Constraint keys. Specified by draft-alvestrand-constraints-resolution-00b |
23 const char MediaStreamVideoSource::kMinAspectRatio[] = "minAspectRatio"; | 22 const char MediaStreamVideoSource::kMinAspectRatio[] = "minAspectRatio"; |
24 const char MediaStreamVideoSource::kMaxAspectRatio[] = "maxAspectRatio"; | 23 const char MediaStreamVideoSource::kMaxAspectRatio[] = "maxAspectRatio"; |
25 const char MediaStreamVideoSource::kMaxWidth[] = "maxWidth"; | 24 const char MediaStreamVideoSource::kMaxWidth[] = "maxWidth"; |
26 const char MediaStreamVideoSource::kMinWidth[] = "minWidth"; | 25 const char MediaStreamVideoSource::kMinWidth[] = "minWidth"; |
27 const char MediaStreamVideoSource::kMaxHeight[] = "maxHeight"; | 26 const char MediaStreamVideoSource::kMaxHeight[] = "maxHeight"; |
28 const char MediaStreamVideoSource::kMinHeight[] = "minHeight"; | 27 const char MediaStreamVideoSource::kMinHeight[] = "minHeight"; |
29 const char MediaStreamVideoSource::kMaxFrameRate[] = "maxFrameRate"; | 28 const char MediaStreamVideoSource::kMaxFrameRate[] = "maxFrameRate"; |
30 const char MediaStreamVideoSource::kMinFrameRate[] = "minFrameRate"; | 29 const char MediaStreamVideoSource::kMinFrameRate[] = "minFrameRate"; |
31 | 30 |
32 // TODO(mcasas): Find a way to guarantee all constraints are added to the array. | 31 // TODO(mcasas): Find a way to guarantee all constraints are added to the array. |
33 const char* kSupportedConstraints[] = { | 32 const char* kSupportedConstraints[] = { |
34 MediaStreamVideoSource::kMaxAspectRatio, | 33 MediaStreamVideoSource::kMaxAspectRatio, |
35 MediaStreamVideoSource::kMinAspectRatio, | 34 MediaStreamVideoSource::kMinAspectRatio, |
36 MediaStreamVideoSource::kMaxWidth, | 35 MediaStreamVideoSource::kMaxWidth, |
37 MediaStreamVideoSource::kMinWidth, | 36 MediaStreamVideoSource::kMinWidth, |
38 MediaStreamVideoSource::kMaxHeight, | 37 MediaStreamVideoSource::kMaxHeight, |
39 MediaStreamVideoSource::kMinHeight, | 38 MediaStreamVideoSource::kMinHeight, |
40 MediaStreamVideoSource::kMaxFrameRate, | 39 MediaStreamVideoSource::kMaxFrameRate, |
41 MediaStreamVideoSource::kMinFrameRate, | 40 MediaStreamVideoSource::kMinFrameRate, |
42 }; | 41 }; |
43 | 42 |
44 namespace { | 43 namespace { |
45 | 44 |
46 // Google-specific key prefix. Constraints with this prefix are ignored if they | 45 const char* kLegalVideoConstraints[] = { |
47 // are unknown. | 46 "width", "height", "aspectRatio", "frameRate", |
48 const char kGooglePrefix[] = "goog"; | 47 "facingMode", "deviceId", "groupId", "mediaStreamSource", |
48 }; | |
49 | 49 |
50 // Returns true if |constraint| has mandatory constraints. | 50 // Returns true if |constraint| has mandatory constraints. |
51 bool HasMandatoryConstraints(const blink::WebMediaConstraints& constraints) { | 51 bool HasMandatoryConstraints(const blink::WebMediaConstraints& constraints) { |
52 blink::WebVector<blink::WebMediaConstraint> mandatory_constraints; | 52 return constraints.basic().hasMandatory(); |
53 constraints.getMandatoryConstraints(mandatory_constraints); | |
54 return !mandatory_constraints.isEmpty(); | |
55 } | 53 } |
56 | 54 |
57 // Retrieve the desired max width and height from |constraints|. If not set, | 55 // Retrieve the desired max width and height from |constraints|. If not set, |
58 // the |desired_width| and |desired_height| are set to | 56 // the |desired_width| and |desired_height| are set to |
59 // std::numeric_limits<int>::max(); | 57 // std::numeric_limits<int>::max(); |
60 // If either max width or height is set as a mandatory constraint, the optional | 58 // If either max width or height is set as a mandatory constraint, the optional |
61 // constraints are not checked. | 59 // constraints are not checked. |
62 void GetDesiredMaxWidthAndHeight(const blink::WebMediaConstraints& constraints, | 60 void GetDesiredMaxWidthAndHeight(const blink::WebMediaConstraints& constraints, |
63 int* desired_width, int* desired_height) { | 61 int* desired_width, int* desired_height) { |
64 *desired_width = std::numeric_limits<int>::max(); | 62 *desired_width = std::numeric_limits<int>::max(); |
65 *desired_height = std::numeric_limits<int>::max(); | 63 *desired_height = std::numeric_limits<int>::max(); |
66 | 64 |
67 bool mandatory = GetMandatoryConstraintValueAsInteger( | 65 const auto& basic_constraints = constraints.basic(); |
68 constraints, | 66 if (basic_constraints.width.hasMax() || basic_constraints.height.hasMax()) { |
69 MediaStreamVideoSource::kMaxWidth, | 67 if (basic_constraints.width.hasMax()) |
70 desired_width); | 68 *desired_width = basic_constraints.width.max(); |
71 mandatory |= GetMandatoryConstraintValueAsInteger( | 69 if (basic_constraints.height.hasMax()) |
72 constraints, | 70 *desired_height = basic_constraints.height.max(); |
73 MediaStreamVideoSource::kMaxHeight, | |
74 desired_height); | |
75 if (mandatory) | |
76 return; | 71 return; |
72 } | |
77 | 73 |
78 GetOptionalConstraintValueAsInteger(constraints, | 74 for (const auto& constraint_set : constraints.advanced()) { |
79 MediaStreamVideoSource::kMaxWidth, | 75 if (constraint_set.width.hasMax()) |
80 desired_width); | 76 *desired_width = constraint_set.width.max(); |
81 GetOptionalConstraintValueAsInteger(constraints, | 77 if (constraint_set.height.hasMax()) |
82 MediaStreamVideoSource::kMaxHeight, | 78 *desired_height = constraint_set.height.max(); |
83 desired_height); | 79 } |
84 } | 80 } |
85 | 81 |
86 // Retrieve the desired max and min aspect ratio from |constraints|. If not set, | 82 // Retrieve the desired max and min aspect ratio from |constraints|. If not set, |
87 // the |min_aspect_ratio| is set to 0 and |max_aspect_ratio| is set to | 83 // the |min_aspect_ratio| is set to 0 and |max_aspect_ratio| is set to |
88 // std::numeric_limits<double>::max(); | 84 // std::numeric_limits<double>::max(); |
89 // If either min or max aspect ratio is set as a mandatory constraint, the | 85 // If either min or max aspect ratio is set as a mandatory constraint, the |
90 // optional constraints are not checked. | 86 // optional constraints are not checked. |
91 void GetDesiredMinAndMaxAspectRatio( | 87 void GetDesiredMinAndMaxAspectRatio( |
92 const blink::WebMediaConstraints& constraints, | 88 const blink::WebMediaConstraints& constraints, |
93 double* min_aspect_ratio, | 89 double* min_aspect_ratio, |
94 double* max_aspect_ratio) { | 90 double* max_aspect_ratio) { |
95 *min_aspect_ratio = 0; | 91 *min_aspect_ratio = 0; |
96 *max_aspect_ratio = std::numeric_limits<double>::max(); | 92 *max_aspect_ratio = std::numeric_limits<double>::max(); |
97 | 93 |
98 bool mandatory = GetMandatoryConstraintValueAsDouble( | 94 if (constraints.basic().aspectRatio.hasMin() || |
99 constraints, | 95 constraints.basic().aspectRatio.hasMax()) { |
100 MediaStreamVideoSource::kMinAspectRatio, | 96 if (constraints.basic().aspectRatio.hasMin()) |
101 min_aspect_ratio); | 97 *min_aspect_ratio = constraints.basic().aspectRatio.min(); |
102 mandatory |= GetMandatoryConstraintValueAsDouble( | 98 if (constraints.basic().aspectRatio.hasMax()) |
103 constraints, | 99 *max_aspect_ratio = constraints.basic().aspectRatio.max(); |
104 MediaStreamVideoSource::kMaxAspectRatio, | |
105 max_aspect_ratio); | |
106 if (mandatory) | |
107 return; | 100 return; |
108 | 101 // Note - the code will ignore attempts at successive refinement |
109 GetOptionalConstraintValueAsDouble(constraints, | 102 // of the aspect ratio with advanced constraint. This may be wrong. |
110 MediaStreamVideoSource::kMinAspectRatio, | 103 } |
111 min_aspect_ratio); | 104 // Note - the code below will potentially pick min and max from different |
112 GetOptionalConstraintValueAsDouble(constraints, | 105 // constraint sets, some of which might have been ignored. |
113 MediaStreamVideoSource::kMaxAspectRatio, | 106 for (const auto& constraint_set : constraints.advanced()) { |
114 max_aspect_ratio); | 107 if (constraint_set.aspectRatio.hasMin()) { |
108 *min_aspect_ratio = constraint_set.aspectRatio.min(); | |
109 break; | |
110 } | |
111 } | |
112 for (const auto& constraint_set : constraints.advanced()) { | |
113 if (constraint_set.aspectRatio.hasMax()) { | |
114 *max_aspect_ratio = constraint_set.aspectRatio.max(); | |
115 break; | |
116 } | |
117 } | |
115 } | 118 } |
116 | 119 |
117 // Returns true if |constraint| is fulfilled. |format| can be changed by a | 120 // Returns true if |constraints| are fulfilled. |format| can be changed by a |
118 // constraint, e.g. the frame rate can be changed by setting maxFrameRate. | 121 // constraint, e.g. the frame rate can be changed by setting maxFrameRate. |
119 bool UpdateFormatForConstraint(const blink::WebMediaConstraint& constraint, | 122 bool UpdateFormatForConstraints( |
120 bool mandatory, | 123 const blink::WebMediaTrackConstraintSet& constraints, |
121 media::VideoCaptureFormat* format) { | 124 media::VideoCaptureFormat* format, |
125 blink::WebString* failing_constraint_name_out) { | |
122 DCHECK(format != NULL); | 126 DCHECK(format != NULL); |
123 | 127 |
124 if (!format->IsValid()) | 128 if (!format->IsValid()) |
125 return false; | 129 return false; |
126 | 130 |
127 const std::string constraint_name = constraint.m_name.utf8(); | 131 const char* failing_constraint_name = nullptr; |
128 const std::string constraint_value = constraint.m_value.utf8(); | |
129 | 132 |
130 if (constraint_name.find(kGooglePrefix) == 0) { | 133 // The width and height are matched based on cropping occuring later: |
131 // These are actually options, not constraints, so they can be satisfied | 134 // min width/height has to be >= the size of the frame (no upscale). |
132 // regardless of the format. | 135 // max width/height just has to be > 0 (we can crop anything too large). |
133 return true; | 136 if ((constraints.width.hasMin() && |
134 } | 137 constraints.width.min() > format->frame_size.width()) || |
135 | 138 (constraints.width.hasMax() && constraints.width.max() <= 0)) |
136 if (constraint_name == MediaStreamSource::kSourceId) { | 139 failing_constraint_name = constraints.width.name(); |
mcasas
2016/01/28 01:57:57
{} here and around l. 143
hta - Chromium
2016/01/28 08:51:40
https://google.github.io/styleguide/cppguide.html#
| |
137 // This is a constraint that doesn't affect the format. | 140 else if ((constraints.height.hasMin() && |
138 return true; | 141 constraints.height.min() > format->frame_size.height()) || |
139 } | 142 (constraints.height.hasMax() && constraints.height.max() <= 0)) |
140 | 143 failing_constraint_name = constraints.height.name(); |
141 // Ignore Chrome specific Tab capture constraints. | 144 else if (!constraints.frameRate.matches(format->frame_rate)) { |
142 if (constraint_name == kMediaStreamSource || | 145 if (constraints.frameRate.hasMax()) { |
143 constraint_name == kMediaStreamSourceId) | 146 const double value = constraints.frameRate.max(); |
147 // TODO(hta): Check if handling of max = 0.0 is relevant. | |
148 // (old handling was to set rate to 1.0 if 0.0 was specified) | |
149 if (constraints.frameRate.matches(value)) { | |
150 format->frame_rate = | |
151 (format->frame_rate > value) ? value : format->frame_rate; | |
152 return true; | |
153 } | |
154 } | |
155 failing_constraint_name = constraints.frameRate.name(); | |
156 } else | |
144 return true; | 157 return true; |
145 | 158 |
146 if (constraint_name == MediaStreamVideoSource::kMinAspectRatio || | 159 DCHECK(failing_constraint_name); |
147 constraint_name == MediaStreamVideoSource::kMaxAspectRatio) { | 160 if (failing_constraint_name_out) { |
148 // These constraints are handled by cropping if the camera outputs the wrong | 161 *failing_constraint_name_out = |
149 // aspect ratio. | 162 blink::WebString::fromUTF8(failing_constraint_name); |
150 double value; | |
151 return base::StringToDouble(constraint_value, &value); | |
152 } | 163 } |
153 | 164 return false; |
154 double value = 0.0; | |
155 if (!base::StringToDouble(constraint_value, &value)) { | |
156 DLOG(WARNING) << "Can't parse MediaStream constraint. Name:" | |
157 << constraint_name << " Value:" << constraint_value; | |
158 return false; | |
159 } | |
160 | |
161 if (constraint_name == MediaStreamVideoSource::kMinWidth) { | |
162 return (value <= format->frame_size.width()); | |
163 } else if (constraint_name == MediaStreamVideoSource::kMaxWidth) { | |
164 return value > 0.0; | |
165 } else if (constraint_name == MediaStreamVideoSource::kMinHeight) { | |
166 return (value <= format->frame_size.height()); | |
167 } else if (constraint_name == MediaStreamVideoSource::kMaxHeight) { | |
168 return value > 0.0; | |
169 } else if (constraint_name == MediaStreamVideoSource::kMinFrameRate) { | |
170 return (value > 0.0) && (value <= format->frame_rate); | |
171 } else if (constraint_name == MediaStreamVideoSource::kMaxFrameRate) { | |
172 if (value <= 0.0) { | |
173 // The frame rate is set by constraint. | |
174 // Don't allow 0 as frame rate if it is a mandatory constraint. | |
175 // Set the frame rate to 1 if it is not mandatory. | |
176 if (mandatory) { | |
177 return false; | |
178 } else { | |
179 value = 1.0; | |
180 } | |
181 } | |
182 format->frame_rate = | |
183 (format->frame_rate > value) ? value : format->frame_rate; | |
184 return true; | |
185 } else { | |
186 LOG(WARNING) << "Found unknown MediaStream constraint. Name:" | |
187 << constraint_name << " Value:" << constraint_value; | |
188 return false; | |
189 } | |
190 } | 165 } |
191 | 166 |
192 // Removes media::VideoCaptureFormats from |formats| that don't meet | 167 // Removes media::VideoCaptureFormats from |formats| that don't meet |
193 // |constraint|. | 168 // |constraints|. |
194 void FilterFormatsByConstraint(const blink::WebMediaConstraint& constraint, | 169 void FilterFormatsByConstraints( |
195 bool mandatory, | 170 const blink::WebMediaTrackConstraintSet& constraints, |
196 media::VideoCaptureFormats* formats) { | 171 media::VideoCaptureFormats* formats, |
197 DVLOG(3) << "FilterFormatsByConstraint(" | 172 blink::WebString* failing_constraint_name) { |
198 << "{ constraint.m_name = " << constraint.m_name.utf8() | |
199 << " constraint.m_value = " << constraint.m_value.utf8() | |
200 << " mandatory = " << mandatory << "})"; | |
201 media::VideoCaptureFormats::iterator format_it = formats->begin(); | 173 media::VideoCaptureFormats::iterator format_it = formats->begin(); |
202 while (format_it != formats->end()) { | 174 while (format_it != formats->end()) { |
203 // Modify the format_it to fulfill the constraint if possible. | 175 // Modify the format_it to fulfill the constraint if possible. |
mcasas
2016/01/28 01:57:57
Modify |format_it| to fulfill the constraints ...
hta - Chromium
2016/01/28 08:51:40
Done.
| |
204 // Delete it otherwise. | 176 // Delete it otherwise. |
205 if (!UpdateFormatForConstraint(constraint, mandatory, &(*format_it))) | 177 if (!UpdateFormatForConstraints(constraints, &(*format_it), |
178 failing_constraint_name)) { | |
206 format_it = formats->erase(format_it); | 179 format_it = formats->erase(format_it); |
207 else | 180 } else { |
208 ++format_it; | 181 ++format_it; |
182 } | |
209 } | 183 } |
210 } | 184 } |
211 | 185 |
212 // Returns the media::VideoCaptureFormats that matches |constraints|. | 186 // Returns the media::VideoCaptureFormats that matches |constraints|. |
213 media::VideoCaptureFormats FilterFormats( | 187 media::VideoCaptureFormats FilterFormats( |
214 const blink::WebMediaConstraints& constraints, | 188 const blink::WebMediaConstraints& constraints, |
215 const media::VideoCaptureFormats& supported_formats, | 189 const media::VideoCaptureFormats& supported_formats, |
216 blink::WebString* unsatisfied_constraint) { | 190 blink::WebString* unsatisfied_constraint) { |
mcasas
2016/01/28 01:57:57
nit: plenty of checks for if (unsatisfied_constrai
hta - Chromium
2016/01/28 08:51:40
absolutely. The caller knows if it's going to repo
| |
217 if (constraints.isNull()) | 191 if (constraints.isNull()) |
218 return supported_formats; | 192 return supported_formats; |
219 | 193 |
194 const auto& basic = constraints.basic(); | |
195 | |
196 // Do some checks that won't be done when filtering candidates. | |
197 | |
198 if (basic.width.hasMin() && basic.width.hasMax() && | |
199 basic.width.min() > basic.width.max()) { | |
200 if (unsatisfied_constraint) | |
201 *unsatisfied_constraint = blink::WebString::fromUTF8(basic.width.name()); | |
202 return media::VideoCaptureFormats(); | |
203 } | |
204 | |
205 if (basic.height.hasMin() && basic.height.hasMax() && | |
206 basic.height.min() > basic.height.max()) { | |
207 if (unsatisfied_constraint) | |
208 *unsatisfied_constraint = blink::WebString::fromUTF8(basic.height.name()); | |
209 return media::VideoCaptureFormats(); | |
210 } | |
211 | |
220 double max_aspect_ratio; | 212 double max_aspect_ratio; |
221 double min_aspect_ratio; | 213 double min_aspect_ratio; |
222 GetDesiredMinAndMaxAspectRatio(constraints, | 214 GetDesiredMinAndMaxAspectRatio(constraints, |
223 &min_aspect_ratio, | 215 &min_aspect_ratio, |
224 &max_aspect_ratio); | 216 &max_aspect_ratio); |
225 | 217 |
226 if (min_aspect_ratio > max_aspect_ratio || max_aspect_ratio < 0.05f) { | 218 if (min_aspect_ratio > max_aspect_ratio || max_aspect_ratio < 0.05f) { |
227 DLOG(WARNING) << "Wrong requested aspect ratio."; | 219 DLOG(WARNING) << "Wrong requested aspect ratio: min " << min_aspect_ratio |
220 << " max " << max_aspect_ratio; | |
221 if (unsatisfied_constraint) { | |
222 *unsatisfied_constraint = | |
223 blink::WebString::fromUTF8(basic.aspectRatio.name()); | |
224 } | |
228 return media::VideoCaptureFormats(); | 225 return media::VideoCaptureFormats(); |
229 } | 226 } |
230 | 227 |
231 int min_width = 0; | 228 std::vector<std::string> temp( |
232 GetMandatoryConstraintValueAsInteger(constraints, | 229 &kLegalVideoConstraints[0], |
233 MediaStreamVideoSource::kMinWidth, | 230 &kLegalVideoConstraints[sizeof(kLegalVideoConstraints) / |
234 &min_width); | 231 sizeof(kLegalVideoConstraints[0])]); |
235 int min_height = 0; | 232 std::string failing_name; |
236 GetMandatoryConstraintValueAsInteger(constraints, | 233 if (basic.hasMandatoryOutsideSet(temp, failing_name)) { |
237 MediaStreamVideoSource::kMinHeight, | 234 if (unsatisfied_constraint) |
238 &min_height); | 235 *unsatisfied_constraint = blink::WebString::fromUTF8(failing_name); |
239 int max_width; | |
240 int max_height; | |
241 GetDesiredMaxWidthAndHeight(constraints, &max_width, &max_height); | |
242 | |
243 if (min_width > max_width || min_height > max_height) | |
244 return media::VideoCaptureFormats(); | 236 return media::VideoCaptureFormats(); |
245 | |
246 double min_frame_rate = 0.0f; | |
247 double max_frame_rate = 0.0f; | |
248 if (GetConstraintValueAsDouble(constraints, | |
249 MediaStreamVideoSource::kMaxFrameRate, | |
250 &max_frame_rate) && | |
251 GetConstraintValueAsDouble(constraints, | |
252 MediaStreamVideoSource::kMinFrameRate, | |
253 &min_frame_rate)) { | |
254 if (min_frame_rate > max_frame_rate) { | |
255 DLOG(WARNING) << "Wrong requested frame rate."; | |
256 return media::VideoCaptureFormats(); | |
257 } | |
258 } | 237 } |
259 | 238 |
260 blink::WebVector<blink::WebMediaConstraint> mandatory; | |
261 blink::WebVector<blink::WebMediaConstraint> optional; | |
262 constraints.getMandatoryConstraints(mandatory); | |
263 constraints.getOptionalConstraints(optional); | |
264 media::VideoCaptureFormats candidates = supported_formats; | 239 media::VideoCaptureFormats candidates = supported_formats; |
265 for (const auto& constraint : mandatory) { | 240 FilterFormatsByConstraints(basic, &candidates, unsatisfied_constraint); |
266 FilterFormatsByConstraint(constraint, true, &candidates); | |
267 if (candidates.empty()) { | |
268 *unsatisfied_constraint = constraint.m_name; | |
269 return candidates; | |
270 } | |
271 } | |
272 | 241 |
273 if (candidates.empty()) | 242 if (candidates.empty()) |
274 return candidates; | 243 return candidates; |
275 | 244 |
276 // Ok - all mandatory checked and we still have candidates. | 245 // Ok - all mandatory checked and we still have candidates. |
277 // Let's try filtering using the optional constraints. The optional | 246 // Let's try filtering using the advanced constraints. The advanced |
278 // constraints must be filtered in the order they occur in |optional|. | 247 // constraints must be filtered in the order they occur in |advanced|. |
279 // But if a constraint produce zero candidates, the constraint is ignored and | 248 // But if a constraint produce zero candidates, the constraint is ignored and |
280 // the next constraint is tested. | 249 // the next constraint is tested. |
281 // http://dev.w3.org/2011/webrtc/editor/getusermedia.html#idl-def-Constraints | 250 // http://w3c.github.io/mediacapture-main/getusermedia.html#dfn-selectsettings |
282 for (const auto& constraint : optional) { | 251 const blink::WebVector<blink::WebMediaTrackConstraintSet>& advanced = |
252 constraints.advanced(); | |
253 | |
254 for (const auto& constraint_set : advanced) { | |
mcasas
2016/01/28 01:57:57
s/advanced/constraints.advanced()/ ?
hta - Chromium
2016/01/28 08:51:40
Done.
| |
283 media::VideoCaptureFormats current_candidates = candidates; | 255 media::VideoCaptureFormats current_candidates = candidates; |
284 FilterFormatsByConstraint(constraint, false, ¤t_candidates); | 256 FilterFormatsByConstraints(constraint_set, ¤t_candidates, nullptr); |
mcasas
2016/01/28 01:57:57
Just to be sure, no s/nullptr/unsatisfied_constrai
hta - Chromium
2016/01/28 08:51:40
It throws the information away, but it can do that
| |
285 if (!current_candidates.empty()) | 257 if (!current_candidates.empty()) |
286 candidates = current_candidates; | 258 candidates = current_candidates; |
287 } | 259 } |
288 | 260 |
289 // We have done as good as we can to filter the supported resolutions. | 261 // We have done as good as we can to filter the supported resolutions. |
290 return candidates; | 262 return candidates; |
291 } | 263 } |
292 | 264 |
293 media::VideoCaptureFormat GetBestFormatBasedOnArea( | 265 media::VideoCaptureFormat GetBestFormatBasedOnArea( |
294 const media::VideoCaptureFormats& formats, | 266 const media::VideoCaptureFormats& formats, |
295 int area) { | 267 int area) { |
296 DCHECK(!formats.empty()); | 268 DCHECK(!formats.empty()); |
297 const media::VideoCaptureFormat* best_format = nullptr; | 269 const media::VideoCaptureFormat* best_format = nullptr; |
298 int best_diff = std::numeric_limits<int>::max(); | 270 int best_diff = std::numeric_limits<int>::max(); |
299 for (const auto& format : formats) { | 271 for (const auto& format : formats) { |
300 const int diff = abs(area - format.frame_size.GetArea()); | 272 const int diff = abs(area - format.frame_size.GetArea()); |
301 if (diff < best_diff) { | 273 if (diff < best_diff) { |
302 best_diff = diff; | 274 best_diff = diff; |
303 best_format = &format; | 275 best_format = &format; |
304 } | 276 } |
305 } | 277 } |
278 DVLOG(3) << "GetBestFormatBasedOnArea chose format " | |
279 << media::VideoCaptureFormat::ToString(*best_format); | |
306 return *best_format; | 280 return *best_format; |
307 } | 281 } |
308 | 282 |
309 // Find the format that best matches the default video size. | 283 // Find the format that best matches the default video size. |
310 // This algorithm is chosen since a resolution must be picked even if no | 284 // This algorithm is chosen since a resolution must be picked even if no |
311 // constraints are provided. We don't just select the maximum supported | 285 // constraints are provided. We don't just select the maximum supported |
312 // resolution since higher resolutions cost more in terms of complexity and | 286 // resolution since higher resolutions cost more in terms of complexity and |
313 // many cameras have lower frame rate and have more noise in the image at | 287 // many cameras have lower frame rate and have more noise in the image at |
314 // their maximum supported resolution. | 288 // their maximum supported resolution. |
315 media::VideoCaptureFormat GetBestCaptureFormat( | 289 media::VideoCaptureFormat GetBestCaptureFormat( |
(...skipping 14 matching lines...) Expand all Loading... | |
330 } | 304 } |
331 | 305 |
332 } // anonymous namespace | 306 } // anonymous namespace |
333 | 307 |
334 // static | 308 // static |
335 MediaStreamVideoSource* MediaStreamVideoSource::GetVideoSource( | 309 MediaStreamVideoSource* MediaStreamVideoSource::GetVideoSource( |
336 const blink::WebMediaStreamSource& source) { | 310 const blink::WebMediaStreamSource& source) { |
337 return static_cast<MediaStreamVideoSource*>(source.extraData()); | 311 return static_cast<MediaStreamVideoSource*>(source.extraData()); |
338 } | 312 } |
339 | 313 |
340 // static | 314 // static, deprecated |
341 bool MediaStreamVideoSource::IsConstraintSupported(const std::string& name) { | 315 bool MediaStreamVideoSource::IsConstraintSupported(const std::string& name) { |
342 return std::find(kSupportedConstraints, | 316 return std::find(kSupportedConstraints, |
343 kSupportedConstraints + arraysize(kSupportedConstraints), | 317 kSupportedConstraints + arraysize(kSupportedConstraints), |
344 name) != | 318 name) != |
345 kSupportedConstraints + arraysize(kSupportedConstraints); | 319 kSupportedConstraints + arraysize(kSupportedConstraints); |
346 } | 320 } |
347 | 321 |
348 MediaStreamVideoSource::MediaStreamVideoSource() | 322 MediaStreamVideoSource::MediaStreamVideoSource() |
349 : state_(NEW), | 323 : state_(NEW), |
350 track_adapter_( | 324 track_adapter_( |
(...skipping 16 matching lines...) Expand all Loading... | |
367 tracks_.push_back(track); | 341 tracks_.push_back(track); |
368 | 342 |
369 track_descriptors_.push_back( | 343 track_descriptors_.push_back( |
370 TrackDescriptor(track, frame_callback, constraints, callback)); | 344 TrackDescriptor(track, frame_callback, constraints, callback)); |
371 | 345 |
372 switch (state_) { | 346 switch (state_) { |
373 case NEW: { | 347 case NEW: { |
374 // Tab capture and Screen capture needs the maximum requested height | 348 // Tab capture and Screen capture needs the maximum requested height |
375 // and width to decide on the resolution. | 349 // and width to decide on the resolution. |
376 int max_requested_width = 0; | 350 int max_requested_width = 0; |
377 GetMandatoryConstraintValueAsInteger(constraints, kMaxWidth, | 351 if (constraints.basic().width.hasMax()) |
378 &max_requested_width); | 352 max_requested_width = constraints.basic().width.max(); |
379 | 353 |
380 int max_requested_height = 0; | 354 int max_requested_height = 0; |
381 GetMandatoryConstraintValueAsInteger(constraints, kMaxHeight, | 355 if (constraints.basic().height.hasMax()) |
382 &max_requested_height); | 356 max_requested_height = constraints.basic().height.max(); |
383 | 357 |
384 double max_requested_frame_rate = kDefaultFrameRate; | 358 double max_requested_frame_rate = kDefaultFrameRate; |
385 GetConstraintValueAsDouble(constraints, kMaxFrameRate, | 359 if (constraints.basic().frameRate.hasMax()) |
386 &max_requested_frame_rate); | 360 max_requested_frame_rate = constraints.basic().frameRate.max(); |
387 | 361 |
388 state_ = RETRIEVING_CAPABILITIES; | 362 state_ = RETRIEVING_CAPABILITIES; |
389 GetCurrentSupportedFormats( | 363 GetCurrentSupportedFormats( |
390 max_requested_width, | 364 max_requested_width, |
391 max_requested_height, | 365 max_requested_height, |
392 max_requested_frame_rate, | 366 max_requested_frame_rate, |
393 base::Bind(&MediaStreamVideoSource::OnSupportedFormats, | 367 base::Bind(&MediaStreamVideoSource::OnSupportedFormats, |
394 weak_factory_.GetWeakPtr())); | 368 weak_factory_.GetWeakPtr())); |
395 | 369 |
396 break; | 370 break; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
452 const media::VideoCaptureFormats& formats) { | 426 const media::VideoCaptureFormats& formats) { |
453 DCHECK(CalledOnValidThread()); | 427 DCHECK(CalledOnValidThread()); |
454 DCHECK_EQ(RETRIEVING_CAPABILITIES, state_); | 428 DCHECK_EQ(RETRIEVING_CAPABILITIES, state_); |
455 | 429 |
456 supported_formats_ = formats; | 430 supported_formats_ = formats; |
457 blink::WebMediaConstraints fulfilled_constraints; | 431 blink::WebMediaConstraints fulfilled_constraints; |
458 if (!FindBestFormatWithConstraints(supported_formats_, | 432 if (!FindBestFormatWithConstraints(supported_formats_, |
459 ¤t_format_, | 433 ¤t_format_, |
460 &fulfilled_constraints)) { | 434 &fulfilled_constraints)) { |
461 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded); | 435 SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded); |
436 DVLOG(3) << "OnSupportedFormats failed to find an usable format"; | |
462 // This object can be deleted after calling FinalizeAddTrack. See comment | 437 // This object can be deleted after calling FinalizeAddTrack. See comment |
463 // in the header file. | 438 // in the header file. |
464 FinalizeAddTrack(); | 439 FinalizeAddTrack(); |
465 return; | 440 return; |
466 } | 441 } |
467 | 442 |
468 state_ = STARTING; | 443 state_ = STARTING; |
469 DVLOG(3) << "Starting the capturer with " | 444 DVLOG(3) << "Starting the capturer with " |
470 << media::VideoCaptureFormat::ToString(current_format_); | 445 << media::VideoCaptureFormat::ToString(current_format_); |
471 | 446 |
472 StartSourceImpl( | 447 StartSourceImpl( |
473 current_format_, | 448 current_format_, |
474 fulfilled_constraints, | 449 fulfilled_constraints, |
475 base::Bind(&VideoTrackAdapter::DeliverFrameOnIO, track_adapter_)); | 450 base::Bind(&VideoTrackAdapter::DeliverFrameOnIO, track_adapter_)); |
476 } | 451 } |
477 | 452 |
478 bool MediaStreamVideoSource::FindBestFormatWithConstraints( | 453 bool MediaStreamVideoSource::FindBestFormatWithConstraints( |
479 const media::VideoCaptureFormats& formats, | 454 const media::VideoCaptureFormats& formats, |
480 media::VideoCaptureFormat* best_format, | 455 media::VideoCaptureFormat* best_format, |
481 blink::WebMediaConstraints* fulfilled_constraints) { | 456 blink::WebMediaConstraints* fulfilled_constraints) { |
482 DCHECK(CalledOnValidThread()); | 457 DCHECK(CalledOnValidThread()); |
483 // Find the first constraints that we can fulfill. | 458 DVLOG(3) << "MediaStreamVideoSource::FindBestFormatWithConstraints " |
459 << "with " << formats.size() << " formats"; | |
460 // Find the first track descriptor that can fulfil the constraints. | |
484 for (const auto& track : track_descriptors_) { | 461 for (const auto& track : track_descriptors_) { |
485 const blink::WebMediaConstraints& track_constraints = track.constraints; | 462 const blink::WebMediaConstraints& track_constraints = track.constraints; |
486 | 463 |
487 // If the source doesn't support capability enumeration it is still ok if | 464 // If the source doesn't support capability enumeration it is still ok if |
488 // no mandatory constraints have been specified. That just means that | 465 // no mandatory constraints have been specified. That just means that |
489 // we will start with whatever format is native to the source. | 466 // we will start with whatever format is native to the source. |
490 if (formats.empty() && !HasMandatoryConstraints(track_constraints)) { | 467 if (formats.empty() && !HasMandatoryConstraints(track_constraints)) { |
468 DVLOG(3) << "No mandatory constraints and no formats"; | |
491 *fulfilled_constraints = track_constraints; | 469 *fulfilled_constraints = track_constraints; |
492 *best_format = media::VideoCaptureFormat(); | 470 *best_format = media::VideoCaptureFormat(); |
493 return true; | 471 return true; |
494 } | 472 } |
495 blink::WebString unsatisfied_constraint; | 473 blink::WebString unsatisfied_constraint; |
496 const media::VideoCaptureFormats filtered_formats = | 474 const media::VideoCaptureFormats filtered_formats = |
497 FilterFormats(track_constraints, formats, &unsatisfied_constraint); | 475 FilterFormats(track_constraints, formats, &unsatisfied_constraint); |
498 if (filtered_formats.empty()) | 476 if (filtered_formats.empty()) |
499 continue; | 477 continue; |
500 | 478 |
501 // A request with constraints that can be fulfilled. | 479 // A request with constraints that can be fulfilled. |
502 *fulfilled_constraints = track_constraints; | 480 *fulfilled_constraints = track_constraints; |
503 *best_format = GetBestCaptureFormat(filtered_formats, track_constraints); | 481 *best_format = GetBestCaptureFormat(filtered_formats, track_constraints); |
482 DVLOG(3) << "Found a track that matches the constraints"; | |
504 return true; | 483 return true; |
505 } | 484 } |
485 DVLOG(3) << "No usable format found"; | |
506 return false; | 486 return false; |
507 } | 487 } |
508 | 488 |
509 void MediaStreamVideoSource::OnStartDone(MediaStreamRequestResult result) { | 489 void MediaStreamVideoSource::OnStartDone(MediaStreamRequestResult result) { |
510 DCHECK(CalledOnValidThread()); | 490 DCHECK(CalledOnValidThread()); |
511 DVLOG(3) << "OnStartDone({result =" << result << "})"; | 491 DVLOG(3) << "OnStartDone({result =" << result << "})"; |
512 if (result == MEDIA_DEVICE_OK) { | 492 if (result == MEDIA_DEVICE_OK) { |
513 DCHECK_EQ(STARTING, state_); | 493 DCHECK_EQ(STARTING, state_); |
514 state_ = STARTED; | 494 state_ = STARTED; |
515 SetReadyState(blink::WebMediaStreamSource::ReadyStateLive); | 495 SetReadyState(blink::WebMediaStreamSource::ReadyStateLive); |
(...skipping 19 matching lines...) Expand all Loading... | |
535 std::vector<TrackDescriptor> track_descriptors; | 515 std::vector<TrackDescriptor> track_descriptors; |
536 track_descriptors.swap(track_descriptors_); | 516 track_descriptors.swap(track_descriptors_); |
537 for (const auto& track : track_descriptors) { | 517 for (const auto& track : track_descriptors) { |
538 MediaStreamRequestResult result = MEDIA_DEVICE_OK; | 518 MediaStreamRequestResult result = MEDIA_DEVICE_OK; |
539 blink::WebString unsatisfied_constraint; | 519 blink::WebString unsatisfied_constraint; |
540 | 520 |
541 if (HasMandatoryConstraints(track.constraints) && | 521 if (HasMandatoryConstraints(track.constraints) && |
542 FilterFormats(track.constraints, formats, &unsatisfied_constraint) | 522 FilterFormats(track.constraints, formats, &unsatisfied_constraint) |
543 .empty()) { | 523 .empty()) { |
544 result = MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED; | 524 result = MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED; |
525 DVLOG(3) << "FinalizeAddTrack() ignoring device on constraint " | |
526 << unsatisfied_constraint.utf8(); | |
545 } | 527 } |
546 | 528 |
547 if (state_ != STARTED && result == MEDIA_DEVICE_OK) | 529 if (state_ != STARTED && result == MEDIA_DEVICE_OK) |
548 result = MEDIA_DEVICE_TRACK_START_FAILURE; | 530 result = MEDIA_DEVICE_TRACK_START_FAILURE; |
549 | 531 |
550 if (result == MEDIA_DEVICE_OK) { | 532 if (result == MEDIA_DEVICE_OK) { |
551 int max_width; | 533 int max_width; |
552 int max_height; | 534 int max_height; |
553 GetDesiredMaxWidthAndHeight(track.constraints, &max_width, &max_height); | 535 GetDesiredMaxWidthAndHeight(track.constraints, &max_width, &max_height); |
554 double max_aspect_ratio; | 536 double max_aspect_ratio; |
555 double min_aspect_ratio; | 537 double min_aspect_ratio; |
556 GetDesiredMinAndMaxAspectRatio(track.constraints, | 538 GetDesiredMinAndMaxAspectRatio(track.constraints, |
557 &min_aspect_ratio, | 539 &min_aspect_ratio, |
558 &max_aspect_ratio); | 540 &max_aspect_ratio); |
559 double max_frame_rate = 0.0f; | 541 double max_frame_rate = 0.0f; |
560 GetConstraintValueAsDouble(track.constraints, | 542 if (track.constraints.basic().frameRate.hasMax()) |
561 kMaxFrameRate, &max_frame_rate); | 543 max_frame_rate = track.constraints.basic().frameRate.max(); |
562 | 544 |
563 track_adapter_->AddTrack(track.track, track.frame_callback, max_width, | 545 track_adapter_->AddTrack(track.track, track.frame_callback, max_width, |
564 max_height, min_aspect_ratio, max_aspect_ratio, | 546 max_height, min_aspect_ratio, max_aspect_ratio, |
565 max_frame_rate); | 547 max_frame_rate); |
566 } | 548 } |
567 | 549 |
568 DVLOG(3) << "FinalizeAddTrack() result " << result; | 550 DVLOG(3) << "FinalizeAddTrack() result " << result; |
569 | 551 |
570 if (!track.callback.is_null()) | 552 if (!track.callback.is_null()) |
571 track.callback.Run(this, result, unsatisfied_constraint); | 553 track.callback.Run(this, result, unsatisfied_constraint); |
(...skipping 28 matching lines...) Expand all Loading... | |
600 : track(track), | 582 : track(track), |
601 frame_callback(frame_callback), | 583 frame_callback(frame_callback), |
602 constraints(constraints), | 584 constraints(constraints), |
603 callback(callback) { | 585 callback(callback) { |
604 } | 586 } |
605 | 587 |
606 MediaStreamVideoSource::TrackDescriptor::~TrackDescriptor() { | 588 MediaStreamVideoSource::TrackDescriptor::~TrackDescriptor() { |
607 } | 589 } |
608 | 590 |
609 } // namespace content | 591 } // namespace content |
OLD | NEW |