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