xref: /aosp_15_r20/external/openscreen/cast/streaming/resolution.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "cast/streaming/resolution.h"
6 
7 #include <utility>
8 
9 #include "absl/strings/str_cat.h"
10 #include "absl/strings/str_split.h"
11 #include "cast/streaming/message_fields.h"
12 #include "platform/base/error.h"
13 #include "util/json/json_helpers.h"
14 #include "util/osp_logging.h"
15 
16 namespace openscreen {
17 namespace cast {
18 
19 namespace {
20 
21 /// Dimension properties.
22 // Width in pixels.
23 static constexpr char kWidth[] = "width";
24 
25 // Height in pixels.
26 static constexpr char kHeight[] = "height";
27 
28 // Frame rate as a rational decimal number or fraction.
29 // E.g. 30 and "3000/1001" are both valid representations.
30 static constexpr char kFrameRate[] = "frameRate";
31 
32 // Choice of epsilon for double comparison allows for proper comparison
33 // for both aspect ratios and frame rates. For frame rates, it is based on the
34 // broadcast rate of 29.97fps, which is actually 29.976. For aspect ratios, it
35 // allows for a one-pixel difference at a 4K resolution, we want it to be
36 // relatively high to avoid false negative comparison results.
FrameRateEquals(double a,double b)37 bool FrameRateEquals(double a, double b) {
38   const double kEpsilonForFrameRateComparisons = .0001;
39   return std::abs(a - b) < kEpsilonForFrameRateComparisons;
40 }
41 
42 }  // namespace
43 
TryParse(const Json::Value & root,Resolution * out)44 bool Resolution::TryParse(const Json::Value& root, Resolution* out) {
45   if (!json::TryParseInt(root[kWidth], &(out->width)) ||
46       !json::TryParseInt(root[kHeight], &(out->height))) {
47     return false;
48   }
49   return out->IsValid();
50 }
51 
IsValid() const52 bool Resolution::IsValid() const {
53   return width > 0 && height > 0;
54 }
55 
ToJson() const56 Json::Value Resolution::ToJson() const {
57   OSP_DCHECK(IsValid());
58   Json::Value root;
59   root[kWidth] = width;
60   root[kHeight] = height;
61 
62   return root;
63 }
64 
operator ==(const Resolution & other) const65 bool Resolution::operator==(const Resolution& other) const {
66   return std::tie(width, height) == std::tie(other.width, other.height);
67 }
68 
operator !=(const Resolution & other) const69 bool Resolution::operator!=(const Resolution& other) const {
70   return !(*this == other);
71 }
72 
IsSupersetOf(const Resolution & other) const73 bool Resolution::IsSupersetOf(const Resolution& other) const {
74   return width >= other.width && height >= other.height;
75 }
76 
TryParse(const Json::Value & root,Dimensions * out)77 bool Dimensions::TryParse(const Json::Value& root, Dimensions* out) {
78   if (!json::TryParseInt(root[kWidth], &(out->width)) ||
79       !json::TryParseInt(root[kHeight], &(out->height)) ||
80       !(root[kFrameRate].isNull() ||
81         json::TryParseSimpleFraction(root[kFrameRate], &(out->frame_rate)))) {
82     return false;
83   }
84   return out->IsValid();
85 }
86 
IsValid() const87 bool Dimensions::IsValid() const {
88   return width > 0 && height > 0 && frame_rate.is_positive();
89 }
90 
ToJson() const91 Json::Value Dimensions::ToJson() const {
92   OSP_DCHECK(IsValid());
93   Json::Value root;
94   root[kWidth] = width;
95   root[kHeight] = height;
96   root[kFrameRate] = frame_rate.ToString();
97 
98   return root;
99 }
100 
operator ==(const Dimensions & other) const101 bool Dimensions::operator==(const Dimensions& other) const {
102   return (std::tie(width, height) == std::tie(other.width, other.height) &&
103           FrameRateEquals(static_cast<double>(frame_rate),
104                           static_cast<double>(other.frame_rate)));
105 }
106 
operator !=(const Dimensions & other) const107 bool Dimensions::operator!=(const Dimensions& other) const {
108   return !(*this == other);
109 }
110 
IsSupersetOf(const Dimensions & other) const111 bool Dimensions::IsSupersetOf(const Dimensions& other) const {
112   if (static_cast<double>(frame_rate) !=
113       static_cast<double>(other.frame_rate)) {
114     return static_cast<double>(frame_rate) >=
115            static_cast<double>(other.frame_rate);
116   }
117 
118   return ToResolution().IsSupersetOf(other.ToResolution());
119 }
120 
121 }  // namespace cast
122 }  // namespace openscreen
123