1*3f982cf4SFabien Sanglard // Copyright 2020 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard
5*3f982cf4SFabien Sanglard #include "cast/streaming/capture_recommendations.h"
6*3f982cf4SFabien Sanglard
7*3f982cf4SFabien Sanglard #include <algorithm>
8*3f982cf4SFabien Sanglard #include <utility>
9*3f982cf4SFabien Sanglard
10*3f982cf4SFabien Sanglard #include "cast/streaming/answer_messages.h"
11*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
12*3f982cf4SFabien Sanglard
13*3f982cf4SFabien Sanglard namespace openscreen {
14*3f982cf4SFabien Sanglard namespace cast {
15*3f982cf4SFabien Sanglard namespace capture_recommendations {
16*3f982cf4SFabien Sanglard namespace {
17*3f982cf4SFabien Sanglard
ApplyDisplay(const DisplayDescription & description,Recommendations * recommendations)18*3f982cf4SFabien Sanglard void ApplyDisplay(const DisplayDescription& description,
19*3f982cf4SFabien Sanglard Recommendations* recommendations) {
20*3f982cf4SFabien Sanglard recommendations->video.supports_scaling =
21*3f982cf4SFabien Sanglard (description.aspect_ratio_constraint &&
22*3f982cf4SFabien Sanglard (description.aspect_ratio_constraint.value() ==
23*3f982cf4SFabien Sanglard AspectRatioConstraint::kVariable));
24*3f982cf4SFabien Sanglard
25*3f982cf4SFabien Sanglard // We should never exceed the display's resolution, since it will always
26*3f982cf4SFabien Sanglard // force scaling.
27*3f982cf4SFabien Sanglard if (description.dimensions) {
28*3f982cf4SFabien Sanglard recommendations->video.maximum = description.dimensions.value();
29*3f982cf4SFabien Sanglard recommendations->video.bit_rate_limits.maximum =
30*3f982cf4SFabien Sanglard recommendations->video.maximum.effective_bit_rate();
31*3f982cf4SFabien Sanglard
32*3f982cf4SFabien Sanglard if (recommendations->video.maximum.width <
33*3f982cf4SFabien Sanglard recommendations->video.minimum.width) {
34*3f982cf4SFabien Sanglard recommendations->video.minimum =
35*3f982cf4SFabien Sanglard recommendations->video.maximum.ToResolution();
36*3f982cf4SFabien Sanglard }
37*3f982cf4SFabien Sanglard }
38*3f982cf4SFabien Sanglard
39*3f982cf4SFabien Sanglard // If the receiver gives us an aspect ratio that doesn't match the display
40*3f982cf4SFabien Sanglard // resolution they give us, the behavior is undefined from the spec.
41*3f982cf4SFabien Sanglard // Here we prioritize the aspect ratio, and the receiver can scale the frame
42*3f982cf4SFabien Sanglard // as they wish.
43*3f982cf4SFabien Sanglard double aspect_ratio = 0.0;
44*3f982cf4SFabien Sanglard if (description.aspect_ratio) {
45*3f982cf4SFabien Sanglard aspect_ratio = static_cast<double>(description.aspect_ratio->width) /
46*3f982cf4SFabien Sanglard description.aspect_ratio->height;
47*3f982cf4SFabien Sanglard recommendations->video.maximum.width =
48*3f982cf4SFabien Sanglard recommendations->video.maximum.height * aspect_ratio;
49*3f982cf4SFabien Sanglard } else if (description.dimensions) {
50*3f982cf4SFabien Sanglard aspect_ratio = static_cast<double>(description.dimensions->width) /
51*3f982cf4SFabien Sanglard description.dimensions->height;
52*3f982cf4SFabien Sanglard } else {
53*3f982cf4SFabien Sanglard return;
54*3f982cf4SFabien Sanglard }
55*3f982cf4SFabien Sanglard recommendations->video.minimum.width =
56*3f982cf4SFabien Sanglard recommendations->video.minimum.height * aspect_ratio;
57*3f982cf4SFabien Sanglard }
58*3f982cf4SFabien Sanglard
ApplyConstraints(const Constraints & constraints,Recommendations * recommendations)59*3f982cf4SFabien Sanglard void ApplyConstraints(const Constraints& constraints,
60*3f982cf4SFabien Sanglard Recommendations* recommendations) {
61*3f982cf4SFabien Sanglard // Audio has no fields in the display description, so we can safely
62*3f982cf4SFabien Sanglard // ignore the current recommendations when setting values here.
63*3f982cf4SFabien Sanglard if (constraints.audio.max_delay.has_value()) {
64*3f982cf4SFabien Sanglard recommendations->audio.max_delay = constraints.audio.max_delay.value();
65*3f982cf4SFabien Sanglard }
66*3f982cf4SFabien Sanglard recommendations->audio.max_channels = constraints.audio.max_channels;
67*3f982cf4SFabien Sanglard recommendations->audio.max_sample_rate = constraints.audio.max_sample_rate;
68*3f982cf4SFabien Sanglard
69*3f982cf4SFabien Sanglard recommendations->audio.bit_rate_limits = BitRateLimits{
70*3f982cf4SFabien Sanglard std::max(constraints.audio.min_bit_rate, kDefaultAudioMinBitRate),
71*3f982cf4SFabien Sanglard std::max(constraints.audio.max_bit_rate, kDefaultAudioMinBitRate)};
72*3f982cf4SFabien Sanglard
73*3f982cf4SFabien Sanglard // With video, we take the intersection of values of the constraints and
74*3f982cf4SFabien Sanglard // the display description.
75*3f982cf4SFabien Sanglard if (constraints.video.max_delay.has_value()) {
76*3f982cf4SFabien Sanglard recommendations->video.max_delay = constraints.video.max_delay.value();
77*3f982cf4SFabien Sanglard }
78*3f982cf4SFabien Sanglard
79*3f982cf4SFabien Sanglard if (constraints.video.max_pixels_per_second.has_value()) {
80*3f982cf4SFabien Sanglard recommendations->video.max_pixels_per_second =
81*3f982cf4SFabien Sanglard constraints.video.max_pixels_per_second.value();
82*3f982cf4SFabien Sanglard }
83*3f982cf4SFabien Sanglard
84*3f982cf4SFabien Sanglard recommendations->video.bit_rate_limits =
85*3f982cf4SFabien Sanglard BitRateLimits{std::max(constraints.video.min_bit_rate,
86*3f982cf4SFabien Sanglard recommendations->video.bit_rate_limits.minimum),
87*3f982cf4SFabien Sanglard std::min(constraints.video.max_bit_rate,
88*3f982cf4SFabien Sanglard recommendations->video.bit_rate_limits.maximum)};
89*3f982cf4SFabien Sanglard Dimensions dimensions = constraints.video.max_dimensions;
90*3f982cf4SFabien Sanglard if (dimensions.width <= kDefaultMinResolution.width) {
91*3f982cf4SFabien Sanglard recommendations->video.maximum = {kDefaultMinResolution.width,
92*3f982cf4SFabien Sanglard kDefaultMinResolution.height,
93*3f982cf4SFabien Sanglard kDefaultFrameRate};
94*3f982cf4SFabien Sanglard } else if (dimensions.width < recommendations->video.maximum.width) {
95*3f982cf4SFabien Sanglard recommendations->video.maximum = std::move(dimensions);
96*3f982cf4SFabien Sanglard }
97*3f982cf4SFabien Sanglard
98*3f982cf4SFabien Sanglard if (constraints.video.min_resolution) {
99*3f982cf4SFabien Sanglard const Resolution& min = constraints.video.min_resolution->ToResolution();
100*3f982cf4SFabien Sanglard if (kDefaultMinResolution.width < min.width) {
101*3f982cf4SFabien Sanglard recommendations->video.minimum = std::move(min);
102*3f982cf4SFabien Sanglard }
103*3f982cf4SFabien Sanglard }
104*3f982cf4SFabien Sanglard }
105*3f982cf4SFabien Sanglard
106*3f982cf4SFabien Sanglard } // namespace
107*3f982cf4SFabien Sanglard
operator ==(const BitRateLimits & other) const108*3f982cf4SFabien Sanglard bool BitRateLimits::operator==(const BitRateLimits& other) const {
109*3f982cf4SFabien Sanglard return std::tie(minimum, maximum) == std::tie(other.minimum, other.maximum);
110*3f982cf4SFabien Sanglard }
111*3f982cf4SFabien Sanglard
operator ==(const Audio & other) const112*3f982cf4SFabien Sanglard bool Audio::operator==(const Audio& other) const {
113*3f982cf4SFabien Sanglard return std::tie(bit_rate_limits, max_delay, max_channels, max_sample_rate) ==
114*3f982cf4SFabien Sanglard std::tie(other.bit_rate_limits, other.max_delay, other.max_channels,
115*3f982cf4SFabien Sanglard other.max_sample_rate);
116*3f982cf4SFabien Sanglard }
117*3f982cf4SFabien Sanglard
operator ==(const Video & other) const118*3f982cf4SFabien Sanglard bool Video::operator==(const Video& other) const {
119*3f982cf4SFabien Sanglard return std::tie(bit_rate_limits, minimum, maximum, supports_scaling,
120*3f982cf4SFabien Sanglard max_delay, max_pixels_per_second) ==
121*3f982cf4SFabien Sanglard std::tie(other.bit_rate_limits, other.minimum, other.maximum,
122*3f982cf4SFabien Sanglard other.supports_scaling, other.max_delay,
123*3f982cf4SFabien Sanglard other.max_pixels_per_second);
124*3f982cf4SFabien Sanglard }
125*3f982cf4SFabien Sanglard
operator ==(const Recommendations & other) const126*3f982cf4SFabien Sanglard bool Recommendations::operator==(const Recommendations& other) const {
127*3f982cf4SFabien Sanglard return std::tie(audio, video) == std::tie(other.audio, other.video);
128*3f982cf4SFabien Sanglard }
129*3f982cf4SFabien Sanglard
GetRecommendations(const Answer & answer)130*3f982cf4SFabien Sanglard Recommendations GetRecommendations(const Answer& answer) {
131*3f982cf4SFabien Sanglard Recommendations recommendations;
132*3f982cf4SFabien Sanglard if (answer.display.has_value() && answer.display->IsValid()) {
133*3f982cf4SFabien Sanglard ApplyDisplay(answer.display.value(), &recommendations);
134*3f982cf4SFabien Sanglard }
135*3f982cf4SFabien Sanglard if (answer.constraints.has_value() && answer.constraints->IsValid()) {
136*3f982cf4SFabien Sanglard ApplyConstraints(answer.constraints.value(), &recommendations);
137*3f982cf4SFabien Sanglard }
138*3f982cf4SFabien Sanglard return recommendations;
139*3f982cf4SFabien Sanglard }
140*3f982cf4SFabien Sanglard
141*3f982cf4SFabien Sanglard } // namespace capture_recommendations
142*3f982cf4SFabien Sanglard } // namespace cast
143*3f982cf4SFabien Sanglard } // namespace openscreen
144