Chromium Code Reviews| 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 |