1 /*
2  *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "api/video/color_space.h"
12 
13 namespace webrtc {
14 namespace {
15 // Try to convert |enum_value| into the enum class T. |enum_bitmask| is created
16 // by the funciton below. Returns true if conversion was successful, false
17 // otherwise.
18 template <typename T>
SetFromUint8(uint8_t enum_value,uint64_t enum_bitmask,T * out)19 bool SetFromUint8(uint8_t enum_value, uint64_t enum_bitmask, T* out) {
20   if ((enum_value < 64) && ((enum_bitmask >> enum_value) & 1)) {
21     *out = static_cast<T>(enum_value);
22     return true;
23   }
24   return false;
25 }
26 
27 // This function serves as an assert for the constexpr function below. It's on
28 // purpose not declared as constexpr so that it causes a build problem if enum
29 // values of 64 or above are used. The bitmask and the code generating it would
30 // have to be extended if the standard is updated to include enum values >= 64.
EnumMustBeLessThan64()31 int EnumMustBeLessThan64() {
32   return -1;
33 }
34 
35 template <typename T, size_t N>
MakeMask(const int index,const int length,T (& values)[N])36 constexpr int MakeMask(const int index, const int length, T (&values)[N]) {
37   return length > 1
38              ? (MakeMask(index, 1, values) +
39                 MakeMask(index + 1, length - 1, values))
40              : (static_cast<uint8_t>(values[index]) < 64
41                     ? (uint64_t{1} << static_cast<uint8_t>(values[index]))
42                     : EnumMustBeLessThan64());
43 }
44 
45 // Create a bitmask where each bit corresponds to one potential enum value.
46 // |values| should be an array listing all possible enum values. The bit is set
47 // to one if the corresponding enum exists. Only works for enums with values
48 // less than 64.
49 template <typename T, size_t N>
CreateEnumBitmask(T (& values)[N])50 constexpr uint64_t CreateEnumBitmask(T (&values)[N]) {
51   return MakeMask(0, N, values);
52 }
53 
SetChromaSitingFromUint8(uint8_t enum_value,ColorSpace::ChromaSiting * chroma_siting)54 bool SetChromaSitingFromUint8(uint8_t enum_value,
55                               ColorSpace::ChromaSiting* chroma_siting) {
56   constexpr ColorSpace::ChromaSiting kChromaSitings[] = {
57       ColorSpace::ChromaSiting::kUnspecified,
58       ColorSpace::ChromaSiting::kCollocated, ColorSpace::ChromaSiting::kHalf};
59   constexpr uint64_t enum_bitmask = CreateEnumBitmask(kChromaSitings);
60 
61   return SetFromUint8(enum_value, enum_bitmask, chroma_siting);
62 }
63 
64 }  // namespace
65 
66 ColorSpace::ColorSpace() = default;
67 ColorSpace::ColorSpace(const ColorSpace& other) = default;
68 ColorSpace::ColorSpace(ColorSpace&& other) = default;
69 ColorSpace& ColorSpace::operator=(const ColorSpace& other) = default;
70 
ColorSpace(PrimaryID primaries,TransferID transfer,MatrixID matrix,RangeID range)71 ColorSpace::ColorSpace(PrimaryID primaries,
72                        TransferID transfer,
73                        MatrixID matrix,
74                        RangeID range)
75     : ColorSpace(primaries,
76                  transfer,
77                  matrix,
78                  range,
79                  ChromaSiting::kUnspecified,
80                  ChromaSiting::kUnspecified,
81                  nullptr) {}
82 
ColorSpace(PrimaryID primaries,TransferID transfer,MatrixID matrix,RangeID range,ChromaSiting chroma_siting_horz,ChromaSiting chroma_siting_vert,const HdrMetadata * hdr_metadata)83 ColorSpace::ColorSpace(PrimaryID primaries,
84                        TransferID transfer,
85                        MatrixID matrix,
86                        RangeID range,
87                        ChromaSiting chroma_siting_horz,
88                        ChromaSiting chroma_siting_vert,
89                        const HdrMetadata* hdr_metadata)
90     : primaries_(primaries),
91       transfer_(transfer),
92       matrix_(matrix),
93       range_(range),
94       chroma_siting_horizontal_(chroma_siting_horz),
95       chroma_siting_vertical_(chroma_siting_vert),
96       hdr_metadata_(hdr_metadata ? absl::make_optional(*hdr_metadata)
97                                  : absl::nullopt) {}
98 
primaries() const99 ColorSpace::PrimaryID ColorSpace::primaries() const {
100   return primaries_;
101 }
102 
transfer() const103 ColorSpace::TransferID ColorSpace::transfer() const {
104   return transfer_;
105 }
106 
matrix() const107 ColorSpace::MatrixID ColorSpace::matrix() const {
108   return matrix_;
109 }
110 
range() const111 ColorSpace::RangeID ColorSpace::range() const {
112   return range_;
113 }
114 
chroma_siting_horizontal() const115 ColorSpace::ChromaSiting ColorSpace::chroma_siting_horizontal() const {
116   return chroma_siting_horizontal_;
117 }
118 
chroma_siting_vertical() const119 ColorSpace::ChromaSiting ColorSpace::chroma_siting_vertical() const {
120   return chroma_siting_vertical_;
121 }
122 
hdr_metadata() const123 const HdrMetadata* ColorSpace::hdr_metadata() const {
124   return hdr_metadata_ ? &*hdr_metadata_ : nullptr;
125 }
126 
set_primaries_from_uint8(uint8_t enum_value)127 bool ColorSpace::set_primaries_from_uint8(uint8_t enum_value) {
128   constexpr PrimaryID kPrimaryIds[] = {
129       PrimaryID::kBT709,      PrimaryID::kUnspecified, PrimaryID::kBT470M,
130       PrimaryID::kBT470BG,    PrimaryID::kSMPTE170M,   PrimaryID::kSMPTE240M,
131       PrimaryID::kFILM,       PrimaryID::kBT2020,      PrimaryID::kSMPTEST428,
132       PrimaryID::kSMPTEST431, PrimaryID::kSMPTEST432,  PrimaryID::kJEDECP22};
133   constexpr uint64_t enum_bitmask = CreateEnumBitmask(kPrimaryIds);
134 
135   return SetFromUint8(enum_value, enum_bitmask, &primaries_);
136 }
137 
set_transfer_from_uint8(uint8_t enum_value)138 bool ColorSpace::set_transfer_from_uint8(uint8_t enum_value) {
139   constexpr TransferID kTransferIds[] = {
140       TransferID::kBT709,       TransferID::kUnspecified,
141       TransferID::kGAMMA22,     TransferID::kGAMMA28,
142       TransferID::kSMPTE170M,   TransferID::kSMPTE240M,
143       TransferID::kLINEAR,      TransferID::kLOG,
144       TransferID::kLOG_SQRT,    TransferID::kIEC61966_2_4,
145       TransferID::kBT1361_ECG,  TransferID::kIEC61966_2_1,
146       TransferID::kBT2020_10,   TransferID::kBT2020_12,
147       TransferID::kSMPTEST2084, TransferID::kSMPTEST428,
148       TransferID::kARIB_STD_B67};
149   constexpr uint64_t enum_bitmask = CreateEnumBitmask(kTransferIds);
150 
151   return SetFromUint8(enum_value, enum_bitmask, &transfer_);
152 }
153 
set_matrix_from_uint8(uint8_t enum_value)154 bool ColorSpace::set_matrix_from_uint8(uint8_t enum_value) {
155   constexpr MatrixID kMatrixIds[] = {
156       MatrixID::kRGB,       MatrixID::kBT709,       MatrixID::kUnspecified,
157       MatrixID::kFCC,       MatrixID::kBT470BG,     MatrixID::kSMPTE170M,
158       MatrixID::kSMPTE240M, MatrixID::kYCOCG,       MatrixID::kBT2020_NCL,
159       MatrixID::kBT2020_CL, MatrixID::kSMPTE2085,   MatrixID::kCDNCLS,
160       MatrixID::kCDCLS,     MatrixID::kBT2100_ICTCP};
161   constexpr uint64_t enum_bitmask = CreateEnumBitmask(kMatrixIds);
162 
163   return SetFromUint8(enum_value, enum_bitmask, &matrix_);
164 }
165 
set_range_from_uint8(uint8_t enum_value)166 bool ColorSpace::set_range_from_uint8(uint8_t enum_value) {
167   constexpr RangeID kRangeIds[] = {RangeID::kInvalid, RangeID::kLimited,
168                                    RangeID::kFull, RangeID::kDerived};
169   constexpr uint64_t enum_bitmask = CreateEnumBitmask(kRangeIds);
170 
171   return SetFromUint8(enum_value, enum_bitmask, &range_);
172 }
173 
set_chroma_siting_horizontal_from_uint8(uint8_t enum_value)174 bool ColorSpace::set_chroma_siting_horizontal_from_uint8(uint8_t enum_value) {
175   return SetChromaSitingFromUint8(enum_value, &chroma_siting_horizontal_);
176 }
177 
set_chroma_siting_vertical_from_uint8(uint8_t enum_value)178 bool ColorSpace::set_chroma_siting_vertical_from_uint8(uint8_t enum_value) {
179   return SetChromaSitingFromUint8(enum_value, &chroma_siting_vertical_);
180 }
181 
set_hdr_metadata(const HdrMetadata * hdr_metadata)182 void ColorSpace::set_hdr_metadata(const HdrMetadata* hdr_metadata) {
183   hdr_metadata_ =
184       hdr_metadata ? absl::make_optional(*hdr_metadata) : absl::nullopt;
185 }
186 
187 }  // namespace webrtc
188