xref: /aosp_15_r20/external/openscreen/cast/streaming/capture_recommendations.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
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