| Index: content/renderer/media/media_stream_video_source.cc
|
| diff --git a/content/renderer/media/media_stream_video_source.cc b/content/renderer/media/media_stream_video_source.cc
|
| index 38f19b0d301357bc43d747d02187563a02cc6098..942d24853808c71e82d6d5d8f5696af51e73df7b 100644
|
| --- a/content/renderer/media/media_stream_video_source.cc
|
| +++ b/content/renderer/media/media_stream_video_source.cc
|
| @@ -13,7 +13,6 @@
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/trace_event/trace_event.h"
|
| #include "content/child/child_process.h"
|
| -#include "content/renderer/media/media_stream_constraints_util.h"
|
| #include "content/renderer/media/media_stream_video_track.h"
|
| #include "content/renderer/media/video_track_adapter.h"
|
|
|
| @@ -43,15 +42,14 @@ const char* kSupportedConstraints[] = {
|
|
|
| namespace {
|
|
|
| -// Google-specific key prefix. Constraints with this prefix are ignored if they
|
| -// are unknown.
|
| -const char kGooglePrefix[] = "goog";
|
| +const char* kLegalVideoConstraints[] = {
|
| + "width", "height", "aspectRatio", "frameRate",
|
| + "facingMode", "deviceId", "groupId", "mediaStreamSource",
|
| +};
|
|
|
| // Returns true if |constraint| has mandatory constraints.
|
| bool HasMandatoryConstraints(const blink::WebMediaConstraints& constraints) {
|
| - blink::WebVector<blink::WebMediaConstraint> mandatory_constraints;
|
| - constraints.getMandatoryConstraints(mandatory_constraints);
|
| - return !mandatory_constraints.isEmpty();
|
| + return constraints.basic().hasMandatory();
|
| }
|
|
|
| // Retrieve the desired max width and height from |constraints|. If not set,
|
| @@ -64,23 +62,21 @@ void GetDesiredMaxWidthAndHeight(const blink::WebMediaConstraints& constraints,
|
| *desired_width = std::numeric_limits<int>::max();
|
| *desired_height = std::numeric_limits<int>::max();
|
|
|
| - bool mandatory = GetMandatoryConstraintValueAsInteger(
|
| - constraints,
|
| - MediaStreamVideoSource::kMaxWidth,
|
| - desired_width);
|
| - mandatory |= GetMandatoryConstraintValueAsInteger(
|
| - constraints,
|
| - MediaStreamVideoSource::kMaxHeight,
|
| - desired_height);
|
| - if (mandatory)
|
| + const auto& basic_constraints = constraints.basic();
|
| + if (basic_constraints.width.hasMax() || basic_constraints.height.hasMax()) {
|
| + if (basic_constraints.width.hasMax())
|
| + *desired_width = basic_constraints.width.max();
|
| + if (basic_constraints.height.hasMax())
|
| + *desired_height = basic_constraints.height.max();
|
| return;
|
| + }
|
|
|
| - GetOptionalConstraintValueAsInteger(constraints,
|
| - MediaStreamVideoSource::kMaxWidth,
|
| - desired_width);
|
| - GetOptionalConstraintValueAsInteger(constraints,
|
| - MediaStreamVideoSource::kMaxHeight,
|
| - desired_height);
|
| + for (const auto& constraint_set : constraints.advanced()) {
|
| + if (constraint_set.width.hasMax())
|
| + *desired_width = constraint_set.width.max();
|
| + if (constraint_set.height.hasMax())
|
| + *desired_height = constraint_set.height.max();
|
| + }
|
| }
|
|
|
| // Retrieve the desired max and min aspect ratio from |constraints|. If not set,
|
| @@ -95,128 +91,119 @@ void GetDesiredMinAndMaxAspectRatio(
|
| *min_aspect_ratio = 0;
|
| *max_aspect_ratio = std::numeric_limits<double>::max();
|
|
|
| - bool mandatory = GetMandatoryConstraintValueAsDouble(
|
| - constraints,
|
| - MediaStreamVideoSource::kMinAspectRatio,
|
| - min_aspect_ratio);
|
| - mandatory |= GetMandatoryConstraintValueAsDouble(
|
| - constraints,
|
| - MediaStreamVideoSource::kMaxAspectRatio,
|
| - max_aspect_ratio);
|
| - if (mandatory)
|
| + if (constraints.basic().aspectRatio.hasMin() ||
|
| + constraints.basic().aspectRatio.hasMax()) {
|
| + if (constraints.basic().aspectRatio.hasMin())
|
| + *min_aspect_ratio = constraints.basic().aspectRatio.min();
|
| + if (constraints.basic().aspectRatio.hasMax())
|
| + *max_aspect_ratio = constraints.basic().aspectRatio.max();
|
| return;
|
| -
|
| - GetOptionalConstraintValueAsDouble(constraints,
|
| - MediaStreamVideoSource::kMinAspectRatio,
|
| - min_aspect_ratio);
|
| - GetOptionalConstraintValueAsDouble(constraints,
|
| - MediaStreamVideoSource::kMaxAspectRatio,
|
| - max_aspect_ratio);
|
| + // Note - the code will ignore attempts at successive refinement
|
| + // of the aspect ratio with advanced constraint. This may be wrong.
|
| + }
|
| + // Note - the code below will potentially pick min and max from different
|
| + // constraint sets, some of which might have been ignored.
|
| + for (const auto& constraint_set : constraints.advanced()) {
|
| + if (constraint_set.aspectRatio.hasMin()) {
|
| + *min_aspect_ratio = constraint_set.aspectRatio.min();
|
| + break;
|
| + }
|
| + }
|
| + for (const auto& constraint_set : constraints.advanced()) {
|
| + if (constraint_set.aspectRatio.hasMax()) {
|
| + *max_aspect_ratio = constraint_set.aspectRatio.max();
|
| + break;
|
| + }
|
| + }
|
| }
|
|
|
| -// Returns true if |constraint| is fulfilled. |format| can be changed by a
|
| +// Returns true if |constraints| are fulfilled. |format| can be changed by a
|
| // constraint, e.g. the frame rate can be changed by setting maxFrameRate.
|
| -bool UpdateFormatForConstraint(const blink::WebMediaConstraint& constraint,
|
| - bool mandatory,
|
| - media::VideoCaptureFormat* format) {
|
| +bool UpdateFormatForConstraints(
|
| + const blink::WebMediaTrackConstraintSet& constraints,
|
| + media::VideoCaptureFormat* format,
|
| + std::string* failing_constraint_name) {
|
| DCHECK(format != NULL);
|
|
|
| if (!format->IsValid())
|
| return false;
|
|
|
| - const std::string constraint_name = constraint.m_name.utf8();
|
| - const std::string constraint_value = constraint.m_value.utf8();
|
| -
|
| - if (constraint_name.find(kGooglePrefix) == 0) {
|
| - // These are actually options, not constraints, so they can be satisfied
|
| - // regardless of the format.
|
| - return true;
|
| - }
|
| -
|
| - if (constraint_name == MediaStreamSource::kSourceId) {
|
| - // This is a constraint that doesn't affect the format.
|
| - return true;
|
| - }
|
| -
|
| - // Ignore Chrome specific Tab capture constraints.
|
| - if (constraint_name == kMediaStreamSource ||
|
| - constraint_name == kMediaStreamSourceId)
|
| - return true;
|
| -
|
| - if (constraint_name == MediaStreamVideoSource::kMinAspectRatio ||
|
| - constraint_name == MediaStreamVideoSource::kMaxAspectRatio) {
|
| - // These constraints are handled by cropping if the camera outputs the wrong
|
| - // aspect ratio.
|
| - double value;
|
| - return base::StringToDouble(constraint_value, &value);
|
| - }
|
| -
|
| - double value = 0.0;
|
| - if (!base::StringToDouble(constraint_value, &value)) {
|
| - DLOG(WARNING) << "Can't parse MediaStream constraint. Name:"
|
| - << constraint_name << " Value:" << constraint_value;
|
| - return false;
|
| - }
|
| -
|
| - if (constraint_name == MediaStreamVideoSource::kMinWidth) {
|
| - return (value <= format->frame_size.width());
|
| - } else if (constraint_name == MediaStreamVideoSource::kMaxWidth) {
|
| - return value > 0.0;
|
| - } else if (constraint_name == MediaStreamVideoSource::kMinHeight) {
|
| - return (value <= format->frame_size.height());
|
| - } else if (constraint_name == MediaStreamVideoSource::kMaxHeight) {
|
| - return value > 0.0;
|
| - } else if (constraint_name == MediaStreamVideoSource::kMinFrameRate) {
|
| - return (value > 0.0) && (value <= format->frame_rate);
|
| - } else if (constraint_name == MediaStreamVideoSource::kMaxFrameRate) {
|
| - if (value <= 0.0) {
|
| - // The frame rate is set by constraint.
|
| - // Don't allow 0 as frame rate if it is a mandatory constraint.
|
| - // Set the frame rate to 1 if it is not mandatory.
|
| - if (mandatory) {
|
| - return false;
|
| - } else {
|
| - value = 1.0;
|
| + // The width and height are matched based on cropping occuring later:
|
| + // min width/height has to be >= the size of the frame (no upscale).
|
| + // max width/height just has to be > 0 (we can crop anything too large).
|
| + if ((constraints.width.hasMin() &&
|
| + constraints.width.min() > format->frame_size.width()) ||
|
| + (constraints.width.hasMax() && constraints.width.max() <= 0)) {
|
| + *failing_constraint_name = constraints.width.name();
|
| + } else if ((constraints.height.hasMin() &&
|
| + constraints.height.min() > format->frame_size.height()) ||
|
| + (constraints.height.hasMax() && constraints.height.max() <= 0)) {
|
| + *failing_constraint_name = constraints.height.name();
|
| + } else if (!constraints.frameRate.matches(format->frame_rate)) {
|
| + if (constraints.frameRate.hasMax()) {
|
| + const double value = constraints.frameRate.max();
|
| + // TODO(hta): Check if handling of max = 0.0 is relevant.
|
| + // (old handling was to set rate to 1.0 if 0.0 was specified)
|
| + if (constraints.frameRate.matches(value)) {
|
| + format->frame_rate =
|
| + (format->frame_rate > value) ? value : format->frame_rate;
|
| + return true;
|
| }
|
| }
|
| - format->frame_rate =
|
| - (format->frame_rate > value) ? value : format->frame_rate;
|
| - return true;
|
| + *failing_constraint_name = constraints.frameRate.name();
|
| } else {
|
| - LOG(WARNING) << "Found unknown MediaStream constraint. Name:"
|
| - << constraint_name << " Value:" << constraint_value;
|
| - return false;
|
| + return true;
|
| }
|
| +
|
| + DCHECK(!failing_constraint_name->empty());
|
| + return false;
|
| }
|
|
|
| // Removes media::VideoCaptureFormats from |formats| that don't meet
|
| -// |constraint|.
|
| -void FilterFormatsByConstraint(const blink::WebMediaConstraint& constraint,
|
| - bool mandatory,
|
| - media::VideoCaptureFormats* formats) {
|
| - DVLOG(3) << "FilterFormatsByConstraint("
|
| - << "{ constraint.m_name = " << constraint.m_name.utf8()
|
| - << " constraint.m_value = " << constraint.m_value.utf8()
|
| - << " mandatory = " << mandatory << "})";
|
| +// |constraints|.
|
| +void FilterFormatsByConstraints(
|
| + const blink::WebMediaTrackConstraintSet& constraints,
|
| + media::VideoCaptureFormats* formats,
|
| + std::string* failing_constraint_name) {
|
| media::VideoCaptureFormats::iterator format_it = formats->begin();
|
| while (format_it != formats->end()) {
|
| - // Modify the format_it to fulfill the constraint if possible.
|
| + // Modify |format_it| to fulfill the constraint if possible.
|
| // Delete it otherwise.
|
| - if (!UpdateFormatForConstraint(constraint, mandatory, &(*format_it)))
|
| + if (!UpdateFormatForConstraints(constraints, &(*format_it),
|
| + failing_constraint_name)) {
|
| format_it = formats->erase(format_it);
|
| - else
|
| + } else {
|
| ++format_it;
|
| + }
|
| }
|
| }
|
|
|
| // Returns the media::VideoCaptureFormats that matches |constraints|.
|
| +// If the return value is empty, and the reason is a specific constraint,
|
| +// |unsatisfied_constraint| returns the name of the constraint.
|
| media::VideoCaptureFormats FilterFormats(
|
| const blink::WebMediaConstraints& constraints,
|
| const media::VideoCaptureFormats& supported_formats,
|
| - blink::WebString* unsatisfied_constraint) {
|
| + std::string* unsatisfied_constraint) {
|
| if (constraints.isNull())
|
| return supported_formats;
|
|
|
| + const auto& basic = constraints.basic();
|
| +
|
| + // Do some checks that won't be done when filtering candidates.
|
| +
|
| + if (basic.width.hasMin() && basic.width.hasMax() &&
|
| + basic.width.min() > basic.width.max()) {
|
| + *unsatisfied_constraint = basic.width.name();
|
| + return media::VideoCaptureFormats();
|
| + }
|
| +
|
| + if (basic.height.hasMin() && basic.height.hasMax() &&
|
| + basic.height.min() > basic.height.max()) {
|
| + *unsatisfied_constraint = basic.height.name();
|
| + return media::VideoCaptureFormats();
|
| + }
|
| +
|
| double max_aspect_ratio;
|
| double min_aspect_ratio;
|
| GetDesiredMinAndMaxAspectRatio(constraints,
|
| @@ -224,64 +211,39 @@ media::VideoCaptureFormats FilterFormats(
|
| &max_aspect_ratio);
|
|
|
| if (min_aspect_ratio > max_aspect_ratio || max_aspect_ratio < 0.05f) {
|
| - DLOG(WARNING) << "Wrong requested aspect ratio.";
|
| + DLOG(WARNING) << "Wrong requested aspect ratio: min " << min_aspect_ratio
|
| + << " max " << max_aspect_ratio;
|
| + *unsatisfied_constraint = basic.aspectRatio.name();
|
| return media::VideoCaptureFormats();
|
| }
|
|
|
| - int min_width = 0;
|
| - GetMandatoryConstraintValueAsInteger(constraints,
|
| - MediaStreamVideoSource::kMinWidth,
|
| - &min_width);
|
| - int min_height = 0;
|
| - GetMandatoryConstraintValueAsInteger(constraints,
|
| - MediaStreamVideoSource::kMinHeight,
|
| - &min_height);
|
| - int max_width;
|
| - int max_height;
|
| - GetDesiredMaxWidthAndHeight(constraints, &max_width, &max_height);
|
| -
|
| - if (min_width > max_width || min_height > max_height)
|
| + std::vector<std::string> temp(
|
| + &kLegalVideoConstraints[0],
|
| + &kLegalVideoConstraints[sizeof(kLegalVideoConstraints) /
|
| + sizeof(kLegalVideoConstraints[0])]);
|
| + std::string failing_name;
|
| + if (basic.hasMandatoryOutsideSet(temp, failing_name)) {
|
| + *unsatisfied_constraint = failing_name;
|
| return media::VideoCaptureFormats();
|
| -
|
| - double min_frame_rate = 0.0f;
|
| - double max_frame_rate = 0.0f;
|
| - if (GetConstraintValueAsDouble(constraints,
|
| - MediaStreamVideoSource::kMaxFrameRate,
|
| - &max_frame_rate) &&
|
| - GetConstraintValueAsDouble(constraints,
|
| - MediaStreamVideoSource::kMinFrameRate,
|
| - &min_frame_rate)) {
|
| - if (min_frame_rate > max_frame_rate) {
|
| - DLOG(WARNING) << "Wrong requested frame rate.";
|
| - return media::VideoCaptureFormats();
|
| - }
|
| }
|
|
|
| - blink::WebVector<blink::WebMediaConstraint> mandatory;
|
| - blink::WebVector<blink::WebMediaConstraint> optional;
|
| - constraints.getMandatoryConstraints(mandatory);
|
| - constraints.getOptionalConstraints(optional);
|
| media::VideoCaptureFormats candidates = supported_formats;
|
| - for (const auto& constraint : mandatory) {
|
| - FilterFormatsByConstraint(constraint, true, &candidates);
|
| - if (candidates.empty()) {
|
| - *unsatisfied_constraint = constraint.m_name;
|
| - return candidates;
|
| - }
|
| - }
|
| + FilterFormatsByConstraints(basic, &candidates, unsatisfied_constraint);
|
|
|
| if (candidates.empty())
|
| return candidates;
|
|
|
| // Ok - all mandatory checked and we still have candidates.
|
| - // Let's try filtering using the optional constraints. The optional
|
| - // constraints must be filtered in the order they occur in |optional|.
|
| + // Let's try filtering using the advanced constraints. The advanced
|
| + // constraints must be filtered in the order they occur in |advanced|.
|
| // But if a constraint produce zero candidates, the constraint is ignored and
|
| // the next constraint is tested.
|
| - // http://dev.w3.org/2011/webrtc/editor/getusermedia.html#idl-def-Constraints
|
| - for (const auto& constraint : optional) {
|
| + // http://w3c.github.io/mediacapture-main/getusermedia.html#dfn-selectsettings
|
| + for (const auto& constraint_set : constraints.advanced()) {
|
| media::VideoCaptureFormats current_candidates = candidates;
|
| - FilterFormatsByConstraint(constraint, false, ¤t_candidates);
|
| + std::string unsatisfied_constraint;
|
| + FilterFormatsByConstraints(constraint_set, ¤t_candidates,
|
| + &unsatisfied_constraint);
|
| if (!current_candidates.empty())
|
| candidates = current_candidates;
|
| }
|
| @@ -303,6 +265,8 @@ media::VideoCaptureFormat GetBestFormatBasedOnArea(
|
| best_format = &format;
|
| }
|
| }
|
| + DVLOG(3) << "GetBestFormatBasedOnArea chose format "
|
| + << media::VideoCaptureFormat::ToString(*best_format);
|
| return *best_format;
|
| }
|
|
|
| @@ -337,7 +301,7 @@ MediaStreamVideoSource* MediaStreamVideoSource::GetVideoSource(
|
| return static_cast<MediaStreamVideoSource*>(source.extraData());
|
| }
|
|
|
| -// static
|
| +// static, deprecated
|
| bool MediaStreamVideoSource::IsConstraintSupported(const std::string& name) {
|
| return std::find(kSupportedConstraints,
|
| kSupportedConstraints + arraysize(kSupportedConstraints),
|
| @@ -374,16 +338,16 @@ void MediaStreamVideoSource::AddTrack(
|
| // Tab capture and Screen capture needs the maximum requested height
|
| // and width to decide on the resolution.
|
| int max_requested_width = 0;
|
| - GetMandatoryConstraintValueAsInteger(constraints, kMaxWidth,
|
| - &max_requested_width);
|
| + if (constraints.basic().width.hasMax())
|
| + max_requested_width = constraints.basic().width.max();
|
|
|
| int max_requested_height = 0;
|
| - GetMandatoryConstraintValueAsInteger(constraints, kMaxHeight,
|
| - &max_requested_height);
|
| + if (constraints.basic().height.hasMax())
|
| + max_requested_height = constraints.basic().height.max();
|
|
|
| double max_requested_frame_rate = kDefaultFrameRate;
|
| - GetConstraintValueAsDouble(constraints, kMaxFrameRate,
|
| - &max_requested_frame_rate);
|
| + if (constraints.basic().frameRate.hasMax())
|
| + max_requested_frame_rate = constraints.basic().frameRate.max();
|
|
|
| state_ = RETRIEVING_CAPABILITIES;
|
| GetCurrentSupportedFormats(
|
| @@ -459,6 +423,7 @@ void MediaStreamVideoSource::OnSupportedFormats(
|
| ¤t_format_,
|
| &fulfilled_constraints)) {
|
| SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded);
|
| + DVLOG(3) << "OnSupportedFormats failed to find an usable format";
|
| // This object can be deleted after calling FinalizeAddTrack. See comment
|
| // in the header file.
|
| FinalizeAddTrack();
|
| @@ -480,7 +445,9 @@ bool MediaStreamVideoSource::FindBestFormatWithConstraints(
|
| media::VideoCaptureFormat* best_format,
|
| blink::WebMediaConstraints* fulfilled_constraints) {
|
| DCHECK(CalledOnValidThread());
|
| - // Find the first constraints that we can fulfill.
|
| + DVLOG(3) << "MediaStreamVideoSource::FindBestFormatWithConstraints "
|
| + << "with " << formats.size() << " formats";
|
| + // Find the first track descriptor that can fulfil the constraints.
|
| for (const auto& track : track_descriptors_) {
|
| const blink::WebMediaConstraints& track_constraints = track.constraints;
|
|
|
| @@ -488,11 +455,12 @@ bool MediaStreamVideoSource::FindBestFormatWithConstraints(
|
| // no mandatory constraints have been specified. That just means that
|
| // we will start with whatever format is native to the source.
|
| if (formats.empty() && !HasMandatoryConstraints(track_constraints)) {
|
| + DVLOG(3) << "No mandatory constraints and no formats";
|
| *fulfilled_constraints = track_constraints;
|
| *best_format = media::VideoCaptureFormat();
|
| return true;
|
| }
|
| - blink::WebString unsatisfied_constraint;
|
| + std::string unsatisfied_constraint;
|
| const media::VideoCaptureFormats filtered_formats =
|
| FilterFormats(track_constraints, formats, &unsatisfied_constraint);
|
| if (filtered_formats.empty())
|
| @@ -501,8 +469,10 @@ bool MediaStreamVideoSource::FindBestFormatWithConstraints(
|
| // A request with constraints that can be fulfilled.
|
| *fulfilled_constraints = track_constraints;
|
| *best_format = GetBestCaptureFormat(filtered_formats, track_constraints);
|
| + DVLOG(3) << "Found a track that matches the constraints";
|
| return true;
|
| }
|
| + DVLOG(3) << "No usable format found";
|
| return false;
|
| }
|
|
|
| @@ -536,12 +506,14 @@ void MediaStreamVideoSource::FinalizeAddTrack() {
|
| track_descriptors.swap(track_descriptors_);
|
| for (const auto& track : track_descriptors) {
|
| MediaStreamRequestResult result = MEDIA_DEVICE_OK;
|
| - blink::WebString unsatisfied_constraint;
|
| + std::string unsatisfied_constraint;
|
|
|
| if (HasMandatoryConstraints(track.constraints) &&
|
| FilterFormats(track.constraints, formats, &unsatisfied_constraint)
|
| .empty()) {
|
| result = MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED;
|
| + DVLOG(3) << "FinalizeAddTrack() ignoring device on constraint "
|
| + << unsatisfied_constraint;
|
| }
|
|
|
| if (state_ != STARTED && result == MEDIA_DEVICE_OK)
|
| @@ -557,8 +529,8 @@ void MediaStreamVideoSource::FinalizeAddTrack() {
|
| &min_aspect_ratio,
|
| &max_aspect_ratio);
|
| double max_frame_rate = 0.0f;
|
| - GetConstraintValueAsDouble(track.constraints,
|
| - kMaxFrameRate, &max_frame_rate);
|
| + if (track.constraints.basic().frameRate.hasMax())
|
| + max_frame_rate = track.constraints.basic().frameRate.max();
|
|
|
| track_adapter_->AddTrack(track.track, track.frame_callback, max_width,
|
| max_height, min_aspect_ratio, max_aspect_ratio,
|
| @@ -568,7 +540,8 @@ void MediaStreamVideoSource::FinalizeAddTrack() {
|
| DVLOG(3) << "FinalizeAddTrack() result " << result;
|
|
|
| if (!track.callback.is_null())
|
| - track.callback.Run(this, result, unsatisfied_constraint);
|
| + track.callback.Run(this, result,
|
| + blink::WebString::fromUTF8(unsatisfied_constraint));
|
| }
|
| }
|
|
|
|
|