summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/api/video/color_space.cc
blob: a0cd32edb2ca8479269ae9c0884fd1ca53c31497 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
 *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "api/video/color_space.h"

namespace webrtc {
namespace {
// Try to convert `enum_value` into the enum class T. `enum_bitmask` is created
// by the funciton below. Returns true if conversion was successful, false
// otherwise.
template <typename T>
bool SetFromUint8(uint8_t enum_value, uint64_t enum_bitmask, T* out) {
  if ((enum_value < 64) && ((enum_bitmask >> enum_value) & 1)) {
    *out = static_cast<T>(enum_value);
    return true;
  }
  return false;
}

// This function serves as an assert for the constexpr function below. It's on
// purpose not declared as constexpr so that it causes a build problem if enum
// values of 64 or above are used. The bitmask and the code generating it would
// have to be extended if the standard is updated to include enum values >= 64.
int EnumMustBeLessThan64() {
  return -1;
}

template <typename T, size_t N>
constexpr int MakeMask(const int index, const int length, T (&values)[N]) {
  return length > 1
             ? (MakeMask(index, 1, values) +
                MakeMask(index + 1, length - 1, values))
             : (static_cast<uint8_t>(values[index]) < 64
                    ? (uint64_t{1} << static_cast<uint8_t>(values[index]))
                    : EnumMustBeLessThan64());
}

// Create a bitmask where each bit corresponds to one potential enum value.
// `values` should be an array listing all possible enum values. The bit is set
// to one if the corresponding enum exists. Only works for enums with values
// less than 64.
template <typename T, size_t N>
constexpr uint64_t CreateEnumBitmask(T (&values)[N]) {
  return MakeMask(0, N, values);
}

bool SetChromaSitingFromUint8(uint8_t enum_value,
                              ColorSpace::ChromaSiting* chroma_siting) {
  constexpr ColorSpace::ChromaSiting kChromaSitings[] = {
      ColorSpace::ChromaSiting::kUnspecified,
      ColorSpace::ChromaSiting::kCollocated, ColorSpace::ChromaSiting::kHalf};
  constexpr uint64_t enum_bitmask = CreateEnumBitmask(kChromaSitings);

  return SetFromUint8(enum_value, enum_bitmask, chroma_siting);
}

}  // namespace

ColorSpace::ColorSpace() = default;
ColorSpace::ColorSpace(const ColorSpace& other) = default;
ColorSpace::ColorSpace(ColorSpace&& other) = default;
ColorSpace& ColorSpace::operator=(const ColorSpace& other) = default;

ColorSpace::ColorSpace(PrimaryID primaries,
                       TransferID transfer,
                       MatrixID matrix,
                       RangeID range)
    : ColorSpace(primaries,
                 transfer,
                 matrix,
                 range,
                 ChromaSiting::kUnspecified,
                 ChromaSiting::kUnspecified,
                 nullptr) {}

ColorSpace::ColorSpace(PrimaryID primaries,
                       TransferID transfer,
                       MatrixID matrix,
                       RangeID range,
                       ChromaSiting chroma_siting_horz,
                       ChromaSiting chroma_siting_vert,
                       const HdrMetadata* hdr_metadata)
    : primaries_(primaries),
      transfer_(transfer),
      matrix_(matrix),
      range_(range),
      chroma_siting_horizontal_(chroma_siting_horz),
      chroma_siting_vertical_(chroma_siting_vert),
      hdr_metadata_(hdr_metadata ? absl::make_optional(*hdr_metadata)
                                 : absl::nullopt) {}

ColorSpace::PrimaryID ColorSpace::primaries() const {
  return primaries_;
}

ColorSpace::TransferID ColorSpace::transfer() const {
  return transfer_;
}

ColorSpace::MatrixID ColorSpace::matrix() const {
  return matrix_;
}

ColorSpace::RangeID ColorSpace::range() const {
  return range_;
}

ColorSpace::ChromaSiting ColorSpace::chroma_siting_horizontal() const {
  return chroma_siting_horizontal_;
}

ColorSpace::ChromaSiting ColorSpace::chroma_siting_vertical() const {
  return chroma_siting_vertical_;
}

const HdrMetadata* ColorSpace::hdr_metadata() const {
  return hdr_metadata_ ? &*hdr_metadata_ : nullptr;
}

bool ColorSpace::set_primaries_from_uint8(uint8_t enum_value) {
  constexpr PrimaryID kPrimaryIds[] = {
      PrimaryID::kBT709,      PrimaryID::kUnspecified, PrimaryID::kBT470M,
      PrimaryID::kBT470BG,    PrimaryID::kSMPTE170M,   PrimaryID::kSMPTE240M,
      PrimaryID::kFILM,       PrimaryID::kBT2020,      PrimaryID::kSMPTEST428,
      PrimaryID::kSMPTEST431, PrimaryID::kSMPTEST432,  PrimaryID::kJEDECP22};
  constexpr uint64_t enum_bitmask = CreateEnumBitmask(kPrimaryIds);

  return SetFromUint8(enum_value, enum_bitmask, &primaries_);
}

bool ColorSpace::set_transfer_from_uint8(uint8_t enum_value) {
  constexpr TransferID kTransferIds[] = {
      TransferID::kBT709,       TransferID::kUnspecified,
      TransferID::kGAMMA22,     TransferID::kGAMMA28,
      TransferID::kSMPTE170M,   TransferID::kSMPTE240M,
      TransferID::kLINEAR,      TransferID::kLOG,
      TransferID::kLOG_SQRT,    TransferID::kIEC61966_2_4,
      TransferID::kBT1361_ECG,  TransferID::kIEC61966_2_1,
      TransferID::kBT2020_10,   TransferID::kBT2020_12,
      TransferID::kSMPTEST2084, TransferID::kSMPTEST428,
      TransferID::kARIB_STD_B67};
  constexpr uint64_t enum_bitmask = CreateEnumBitmask(kTransferIds);

  return SetFromUint8(enum_value, enum_bitmask, &transfer_);
}

bool ColorSpace::set_matrix_from_uint8(uint8_t enum_value) {
  constexpr MatrixID kMatrixIds[] = {
      MatrixID::kRGB,       MatrixID::kBT709,       MatrixID::kUnspecified,
      MatrixID::kFCC,       MatrixID::kBT470BG,     MatrixID::kSMPTE170M,
      MatrixID::kSMPTE240M, MatrixID::kYCOCG,       MatrixID::kBT2020_NCL,
      MatrixID::kBT2020_CL, MatrixID::kSMPTE2085,   MatrixID::kCDNCLS,
      MatrixID::kCDCLS,     MatrixID::kBT2100_ICTCP};
  constexpr uint64_t enum_bitmask = CreateEnumBitmask(kMatrixIds);

  return SetFromUint8(enum_value, enum_bitmask, &matrix_);
}

bool ColorSpace::set_range_from_uint8(uint8_t enum_value) {
  constexpr RangeID kRangeIds[] = {RangeID::kInvalid, RangeID::kLimited,
                                   RangeID::kFull, RangeID::kDerived};
  constexpr uint64_t enum_bitmask = CreateEnumBitmask(kRangeIds);

  return SetFromUint8(enum_value, enum_bitmask, &range_);
}

bool ColorSpace::set_chroma_siting_horizontal_from_uint8(uint8_t enum_value) {
  return SetChromaSitingFromUint8(enum_value, &chroma_siting_horizontal_);
}

bool ColorSpace::set_chroma_siting_vertical_from_uint8(uint8_t enum_value) {
  return SetChromaSitingFromUint8(enum_value, &chroma_siting_vertical_);
}

void ColorSpace::set_hdr_metadata(const HdrMetadata* hdr_metadata) {
  hdr_metadata_ =
      hdr_metadata ? absl::make_optional(*hdr_metadata) : absl::nullopt;
}

}  // namespace webrtc