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