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