diff --git a/api/video/color_space.cc b/api/video/color_space.cc index 2f07e003a3..ad138abe80 100644 --- a/api/video/color_space.cc +++ b/api/video/color_space.cc @@ -10,6 +10,48 @@ #include "api/video/color_space.h" +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 +bool SetFromUint8(uint8_t enum_value, uint64_t enum_bitmask, T* out) { + if ((enum_value < 64) && ((enum_bitmask >> enum_value) & 1)) { + *out = static_cast(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 +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(values[index]) < 64 + ? (uint64_t{1} << static_cast(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 +constexpr uint64_t CreateEnumBitmask(T (&values)[N]) { + return MakeMask(0, N, values); +} + +} // namespace + namespace webrtc { ColorSpace::ColorSpace() = default; @@ -55,4 +97,57 @@ 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::kInvalid, 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::kInvalid, 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, MatrixID::kInvalid}; + 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_); +} + +void ColorSpace::set_hdr_metadata(const HdrMetadata* hdr_metadata) { + hdr_metadata_ = + hdr_metadata ? absl::make_optional(*hdr_metadata) : absl::nullopt; +} + } // namespace webrtc diff --git a/api/video/color_space.h b/api/video/color_space.h index 385734a450..79a15f59b3 100644 --- a/api/video/color_space.h +++ b/api/video/color_space.h @@ -48,6 +48,8 @@ class ColorSpace { kSMPTEST431 = 11, kSMPTEST432 = 12, kJEDECP22 = 22, // Identical to EBU3213-E + // When adding/removing entries here, please make sure to do the + // corresponding change to kPrimaryIds. }; enum class TransferID : uint8_t { @@ -70,6 +72,8 @@ class ColorSpace { kSMPTEST2084 = 16, kSMPTEST428 = 17, kARIB_STD_B67 = 18, + // When adding/removing entries here, please make sure to do the + // corresponding change to kTransferIds. }; enum class MatrixID : uint8_t { @@ -88,7 +92,9 @@ class ColorSpace { kCDNCLS = 12, kCDCLS = 13, kBT2100_ICTCP = 14, - kInvalid = 255 + kInvalid = 63, + // When adding/removing entries here, please make sure to do the + // corresponding change to kMatrixIds. }; enum class RangeID { @@ -100,7 +106,9 @@ class ColorSpace { // Full RGB color range with RGB valees from 0 to 255. kFull = 2, // Range is defined by MatrixCoefficients/TransferCharacteristics. - kDerived = 3 + kDerived = 3, + // When adding/removing entries here, please make sure to do the + // corresponding change to kRangeIds. }; ColorSpace(); @@ -130,6 +138,12 @@ class ColorSpace { RangeID range() const; const HdrMetadata* hdr_metadata() const; + bool set_primaries_from_uint8(uint8_t enum_value); + bool set_transfer_from_uint8(uint8_t enum_value); + bool set_matrix_from_uint8(uint8_t enum_value); + bool set_range_from_uint8(uint8_t enum_value); + void set_hdr_metadata(const HdrMetadata* hdr_metadata); + private: PrimaryID primaries_ = PrimaryID::kInvalid; TransferID transfer_ = TransferID::kInvalid; diff --git a/api/video/test/BUILD.gn b/api/video/test/BUILD.gn index cba42458d2..c8269efdc0 100644 --- a/api/video/test/BUILD.gn +++ b/api/video/test/BUILD.gn @@ -11,10 +11,12 @@ import("../../../webrtc.gni") rtc_source_set("rtc_api_video_unittests") { testonly = true sources = [ + "color_space_unittest.cc", "video_bitrate_allocation_unittest.cc", ] deps = [ "..:video_bitrate_allocation", + "..:video_frame", "../../../test:test_support", ] } diff --git a/api/video/test/color_space_unittest.cc b/api/video/test/color_space_unittest.cc new file mode 100644 index 0000000000..b71bcef86a --- /dev/null +++ b/api/video/test/color_space_unittest.cc @@ -0,0 +1,55 @@ +/* + * 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 + +#include "api/video/color_space.h" +#include "test/gtest.h" + +namespace webrtc { +TEST(ColorSpace, TestSettingPrimariesFromUint8) { + ColorSpace color_space; + EXPECT_TRUE(color_space.set_primaries_from_uint8( + static_cast(ColorSpace::PrimaryID::kBT470BG))); + EXPECT_EQ(ColorSpace::PrimaryID::kBT470BG, color_space.primaries()); + EXPECT_FALSE(color_space.set_primaries_from_uint8(3)); + EXPECT_FALSE(color_space.set_primaries_from_uint8(23)); + EXPECT_FALSE(color_space.set_primaries_from_uint8(64)); +} + +TEST(ColorSpace, TestSettingTransferFromUint8) { + ColorSpace color_space; + EXPECT_TRUE(color_space.set_transfer_from_uint8( + static_cast(ColorSpace::TransferID::kBT2020_10))); + EXPECT_EQ(ColorSpace::TransferID::kBT2020_10, color_space.transfer()); + EXPECT_FALSE(color_space.set_transfer_from_uint8(3)); + EXPECT_FALSE(color_space.set_transfer_from_uint8(19)); + EXPECT_FALSE(color_space.set_transfer_from_uint8(128)); +} + +TEST(ColorSpace, TestSettingMatrixFromUint8) { + ColorSpace color_space; + EXPECT_TRUE(color_space.set_matrix_from_uint8( + static_cast(ColorSpace::MatrixID::kCDNCLS))); + EXPECT_EQ(ColorSpace::MatrixID::kCDNCLS, color_space.matrix()); + EXPECT_FALSE(color_space.set_matrix_from_uint8(3)); + EXPECT_FALSE(color_space.set_matrix_from_uint8(15)); + EXPECT_FALSE(color_space.set_matrix_from_uint8(255)); +} + +TEST(ColorSpace, TestSettingRangeFromUint8) { + ColorSpace color_space; + EXPECT_TRUE(color_space.set_range_from_uint8( + static_cast(ColorSpace::RangeID::kFull))); + EXPECT_EQ(ColorSpace::RangeID::kFull, color_space.range()); + EXPECT_FALSE(color_space.set_range_from_uint8(4)); +} + +} // namespace webrtc