Add chroma siting to ColorSpace
Bug: webrtc:8651 Change-Id: I82263e8b6cdcc3ebf699f5e3ebbde04e46982efb Reviewed-on: https://webrtc-review.googlesource.com/c/113424 Reviewed-by: Niels Moller <nisse@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Johannes Kron <kron@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25944}
This commit is contained in:
parent
1ec2a16121
commit
b47ccc38e7
@ -10,6 +10,7 @@
|
||||
|
||||
#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
|
||||
@ -50,9 +51,17 @@ constexpr uint64_t CreateEnumBitmask(T (&values)[N]) {
|
||||
return MakeMask(0, N, values);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
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);
|
||||
|
||||
namespace webrtc {
|
||||
return SetFromUint8(enum_value, enum_bitmask, chroma_siting);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ColorSpace::ColorSpace() = default;
|
||||
ColorSpace::ColorSpace(const ColorSpace& other) = default;
|
||||
@ -63,17 +72,27 @@ ColorSpace::ColorSpace(PrimaryID primaries,
|
||||
TransferID transfer,
|
||||
MatrixID matrix,
|
||||
RangeID range)
|
||||
: ColorSpace(primaries, transfer, matrix, range, nullptr) {}
|
||||
: 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) {}
|
||||
|
||||
@ -93,13 +112,21 @@ 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::kBT709, PrimaryID::kUnspecified, PrimaryID::kBT470M,
|
||||
PrimaryID::kBT470BG, PrimaryID::kSMPTE170M, PrimaryID::kSMPTE240M,
|
||||
PrimaryID::kFILM, PrimaryID::kBT2020, PrimaryID::kSMPTEST428,
|
||||
PrimaryID::kSMPTEST431, PrimaryID::kSMPTEST432, PrimaryID::kJEDECP22};
|
||||
@ -110,7 +137,7 @@ bool ColorSpace::set_primaries_from_uint8(uint8_t enum_value) {
|
||||
|
||||
bool ColorSpace::set_transfer_from_uint8(uint8_t enum_value) {
|
||||
constexpr TransferID kTransferIds[] = {
|
||||
TransferID::kBT709, TransferID::kUNSPECIFIED,
|
||||
TransferID::kBT709, TransferID::kUnspecified,
|
||||
TransferID::kGAMMA22, TransferID::kGAMMA28,
|
||||
TransferID::kSMPTE170M, TransferID::kSMPTE240M,
|
||||
TransferID::kLINEAR, TransferID::kLOG,
|
||||
@ -126,7 +153,7 @@ bool ColorSpace::set_transfer_from_uint8(uint8_t enum_value) {
|
||||
|
||||
bool ColorSpace::set_matrix_from_uint8(uint8_t enum_value) {
|
||||
constexpr MatrixID kMatrixIds[] = {
|
||||
MatrixID::kRGB, MatrixID::kBT709, MatrixID::kUNSPECIFIED,
|
||||
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,
|
||||
@ -144,6 +171,14 @@ bool ColorSpace::set_range_from_uint8(uint8_t enum_value) {
|
||||
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;
|
||||
|
||||
@ -36,7 +36,7 @@ class ColorSpace {
|
||||
enum class PrimaryID : uint8_t {
|
||||
// The indices are equal to the values specified in T-REC H.273 Table 2.
|
||||
kBT709 = 1,
|
||||
kUNSPECIFIED = 2,
|
||||
kUnspecified = 2,
|
||||
kBT470M = 4,
|
||||
kBT470BG = 5,
|
||||
kSMPTE170M = 6, // Identical to BT601
|
||||
@ -54,7 +54,7 @@ class ColorSpace {
|
||||
enum class TransferID : uint8_t {
|
||||
// The indices are equal to the values specified in T-REC H.273 Table 3.
|
||||
kBT709 = 1,
|
||||
kUNSPECIFIED = 2,
|
||||
kUnspecified = 2,
|
||||
kGAMMA22 = 4,
|
||||
kGAMMA28 = 5,
|
||||
kSMPTE170M = 6,
|
||||
@ -78,7 +78,7 @@ class ColorSpace {
|
||||
// The indices are equal to the values specified in T-REC H.273 Table 4.
|
||||
kRGB = 0,
|
||||
kBT709 = 1,
|
||||
kUNSPECIFIED = 2,
|
||||
kUnspecified = 2,
|
||||
kFCC = 4,
|
||||
kBT470BG = 5,
|
||||
kSMPTE170M = 6,
|
||||
@ -108,6 +108,19 @@ class ColorSpace {
|
||||
// corresponding change to kRangeIds.
|
||||
};
|
||||
|
||||
enum class ChromaSiting {
|
||||
// Chroma siting specifies how chroma is subsampled relative to the luma
|
||||
// samples in a YUV video frame.
|
||||
// The indices are equal to the values specified at
|
||||
// https://www.webmproject.org/docs/container/#colour for the element
|
||||
// ChromaSitingVert and ChromaSitingHorz.
|
||||
kUnspecified = 0,
|
||||
kCollocated = 1,
|
||||
kHalf = 2,
|
||||
// When adding/removing entries here, please make sure to do the
|
||||
// corresponding change to kChromaSitings.
|
||||
};
|
||||
|
||||
ColorSpace();
|
||||
ColorSpace(const ColorSpace& other);
|
||||
ColorSpace(ColorSpace&& other);
|
||||
@ -115,15 +128,19 @@ class ColorSpace {
|
||||
ColorSpace(PrimaryID primaries,
|
||||
TransferID transfer,
|
||||
MatrixID matrix,
|
||||
RangeID full_range);
|
||||
RangeID range);
|
||||
ColorSpace(PrimaryID primaries,
|
||||
TransferID transfer,
|
||||
MatrixID matrix,
|
||||
RangeID range,
|
||||
ChromaSiting chroma_siting_horizontal,
|
||||
ChromaSiting chroma_siting_vertical,
|
||||
const HdrMetadata* hdr_metadata);
|
||||
friend bool operator==(const ColorSpace& lhs, const ColorSpace& rhs) {
|
||||
return lhs.primaries_ == rhs.primaries_ && lhs.transfer_ == rhs.transfer_ &&
|
||||
lhs.matrix_ == rhs.matrix_ && lhs.range_ == rhs.range_ &&
|
||||
lhs.chroma_siting_horizontal_ == rhs.chroma_siting_horizontal_ &&
|
||||
lhs.chroma_siting_vertical_ == rhs.chroma_siting_vertical_ &&
|
||||
lhs.hdr_metadata_ == rhs.hdr_metadata_;
|
||||
}
|
||||
friend bool operator!=(const ColorSpace& lhs, const ColorSpace& rhs) {
|
||||
@ -134,22 +151,27 @@ class ColorSpace {
|
||||
TransferID transfer() const;
|
||||
MatrixID matrix() const;
|
||||
RangeID range() const;
|
||||
ChromaSiting chroma_siting_horizontal() const;
|
||||
ChromaSiting chroma_siting_vertical() 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);
|
||||
bool set_chroma_siting_horizontal_from_uint8(uint8_t enum_value);
|
||||
bool set_chroma_siting_vertical_from_uint8(uint8_t enum_value);
|
||||
void set_hdr_metadata(const HdrMetadata* hdr_metadata);
|
||||
|
||||
private:
|
||||
PrimaryID primaries_ = PrimaryID::kUNSPECIFIED;
|
||||
TransferID transfer_ = TransferID::kUNSPECIFIED;
|
||||
MatrixID matrix_ = MatrixID::kUNSPECIFIED;
|
||||
PrimaryID primaries_ = PrimaryID::kUnspecified;
|
||||
TransferID transfer_ = TransferID::kUnspecified;
|
||||
MatrixID matrix_ = MatrixID::kUnspecified;
|
||||
RangeID range_ = RangeID::kInvalid;
|
||||
ChromaSiting chroma_siting_horizontal_ = ChromaSiting::kUnspecified;
|
||||
ChromaSiting chroma_siting_vertical_ = ChromaSiting::kUnspecified;
|
||||
absl::optional<HdrMetadata> hdr_metadata_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_VIDEO_COLOR_SPACE_H_
|
||||
|
||||
@ -52,4 +52,22 @@ TEST(ColorSpace, TestSettingRangeFromUint8) {
|
||||
EXPECT_FALSE(color_space.set_range_from_uint8(4));
|
||||
}
|
||||
|
||||
TEST(ColorSpace, TestSettingChromaSitingHorizontalFromUint8) {
|
||||
ColorSpace color_space;
|
||||
EXPECT_TRUE(color_space.set_chroma_siting_horizontal_from_uint8(
|
||||
static_cast<uint8_t>(ColorSpace::ChromaSiting::kCollocated)));
|
||||
EXPECT_EQ(ColorSpace::ChromaSiting::kCollocated,
|
||||
color_space.chroma_siting_horizontal());
|
||||
EXPECT_FALSE(color_space.set_chroma_siting_horizontal_from_uint8(3));
|
||||
}
|
||||
|
||||
TEST(ColorSpace, TestSettingChromaSitingVerticalFromUint8) {
|
||||
ColorSpace color_space;
|
||||
EXPECT_TRUE(color_space.set_chroma_siting_vertical_from_uint8(
|
||||
static_cast<uint8_t>(ColorSpace::ChromaSiting::kHalf)));
|
||||
EXPECT_EQ(ColorSpace::ChromaSiting::kHalf,
|
||||
color_space.chroma_siting_vertical());
|
||||
EXPECT_FALSE(color_space.set_chroma_siting_vertical_from_uint8(3));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
namespace webrtc {
|
||||
|
||||
ColorSpace ExtractH264ColorSpace(AVCodecContext* codec) {
|
||||
ColorSpace::PrimaryID primaries = ColorSpace::PrimaryID::kUNSPECIFIED;
|
||||
ColorSpace::PrimaryID primaries = ColorSpace::PrimaryID::kUnspecified;
|
||||
switch (codec->color_primaries) {
|
||||
case AVCOL_PRI_BT709:
|
||||
primaries = ColorSpace::PrimaryID::kBT709;
|
||||
@ -55,7 +55,7 @@ ColorSpace ExtractH264ColorSpace(AVCodecContext* codec) {
|
||||
break;
|
||||
}
|
||||
|
||||
ColorSpace::TransferID transfer = ColorSpace::TransferID::kUNSPECIFIED;
|
||||
ColorSpace::TransferID transfer = ColorSpace::TransferID::kUnspecified;
|
||||
switch (codec->color_trc) {
|
||||
case AVCOL_TRC_BT709:
|
||||
transfer = ColorSpace::TransferID::kBT709;
|
||||
@ -112,7 +112,7 @@ ColorSpace ExtractH264ColorSpace(AVCodecContext* codec) {
|
||||
break;
|
||||
}
|
||||
|
||||
ColorSpace::MatrixID matrix = ColorSpace::MatrixID::kUNSPECIFIED;
|
||||
ColorSpace::MatrixID matrix = ColorSpace::MatrixID::kUnspecified;
|
||||
switch (codec->colorspace) {
|
||||
case AVCOL_SPC_RGB:
|
||||
matrix = ColorSpace::MatrixID::kRGB;
|
||||
|
||||
@ -72,10 +72,14 @@ TEST_F(TestH264Impl, MAYBE_EncodeDecode) {
|
||||
EXPECT_GT(I420PSNR(input_frame, decoded_frame.get()), 36);
|
||||
|
||||
const ColorSpace color_space = *decoded_frame->color_space();
|
||||
EXPECT_EQ(ColorSpace::PrimaryID::kUNSPECIFIED, color_space.primaries());
|
||||
EXPECT_EQ(ColorSpace::TransferID::kUNSPECIFIED, color_space.transfer());
|
||||
EXPECT_EQ(ColorSpace::MatrixID::kUNSPECIFIED, color_space.matrix());
|
||||
EXPECT_EQ(ColorSpace::PrimaryID::kUnspecified, color_space.primaries());
|
||||
EXPECT_EQ(ColorSpace::TransferID::kUnspecified, color_space.transfer());
|
||||
EXPECT_EQ(ColorSpace::MatrixID::kUnspecified, color_space.matrix());
|
||||
EXPECT_EQ(ColorSpace::RangeID::kLimited, color_space.range());
|
||||
EXPECT_EQ(ColorSpace::ChromaSiting::kUnspecified,
|
||||
color_space.chroma_siting_horizontal());
|
||||
EXPECT_EQ(ColorSpace::ChromaSiting::kUnspecified,
|
||||
color_space.chroma_siting_vertical());
|
||||
}
|
||||
|
||||
TEST_F(TestH264Impl, MAYBE_DecodedQpEqualsEncodedQp) {
|
||||
|
||||
@ -126,10 +126,11 @@ class TestVp9Impl : public VideoCodecUnitTest {
|
||||
|
||||
ColorSpace CreateTestColorSpace() const {
|
||||
HdrMetadata hdr_metadata = CreateTestHdrMetadata();
|
||||
ColorSpace color_space(ColorSpace::PrimaryID::kBT709,
|
||||
ColorSpace::TransferID::kGAMMA22,
|
||||
ColorSpace::MatrixID::kSMPTE2085,
|
||||
ColorSpace::RangeID::kFull, &hdr_metadata);
|
||||
ColorSpace color_space(
|
||||
ColorSpace::PrimaryID::kBT709, ColorSpace::TransferID::kGAMMA22,
|
||||
ColorSpace::MatrixID::kSMPTE2085, ColorSpace::RangeID::kFull,
|
||||
ColorSpace::ChromaSiting::kCollocated,
|
||||
ColorSpace::ChromaSiting::kCollocated, &hdr_metadata);
|
||||
return color_space;
|
||||
}
|
||||
};
|
||||
@ -157,10 +158,14 @@ TEST_F(TestVp9Impl, EncodeDecode) {
|
||||
EXPECT_GT(I420PSNR(input_frame, decoded_frame.get()), 36);
|
||||
|
||||
const ColorSpace color_space = *decoded_frame->color_space();
|
||||
EXPECT_EQ(ColorSpace::PrimaryID::kUNSPECIFIED, color_space.primaries());
|
||||
EXPECT_EQ(ColorSpace::TransferID::kUNSPECIFIED, color_space.transfer());
|
||||
EXPECT_EQ(ColorSpace::MatrixID::kUNSPECIFIED, color_space.matrix());
|
||||
EXPECT_EQ(ColorSpace::PrimaryID::kUnspecified, color_space.primaries());
|
||||
EXPECT_EQ(ColorSpace::TransferID::kUnspecified, color_space.transfer());
|
||||
EXPECT_EQ(ColorSpace::MatrixID::kUnspecified, color_space.matrix());
|
||||
EXPECT_EQ(ColorSpace::RangeID::kLimited, color_space.range());
|
||||
EXPECT_EQ(ColorSpace::ChromaSiting::kUnspecified,
|
||||
color_space.chroma_siting_horizontal());
|
||||
EXPECT_EQ(ColorSpace::ChromaSiting::kUnspecified,
|
||||
color_space.chroma_siting_vertical());
|
||||
}
|
||||
|
||||
// We only test the encoder here, since the decoded frame rotation is set based
|
||||
|
||||
@ -70,9 +70,9 @@ int GetCpuSpeed(int width, int height) {
|
||||
ColorSpace ExtractVP9ColorSpace(vpx_color_space_t space_t,
|
||||
vpx_color_range_t range_t,
|
||||
unsigned int bit_depth) {
|
||||
ColorSpace::PrimaryID primaries = ColorSpace::PrimaryID::kUNSPECIFIED;
|
||||
ColorSpace::TransferID transfer = ColorSpace::TransferID::kUNSPECIFIED;
|
||||
ColorSpace::MatrixID matrix = ColorSpace::MatrixID::kUNSPECIFIED;
|
||||
ColorSpace::PrimaryID primaries = ColorSpace::PrimaryID::kUnspecified;
|
||||
ColorSpace::TransferID transfer = ColorSpace::TransferID::kUnspecified;
|
||||
ColorSpace::MatrixID matrix = ColorSpace::MatrixID::kUnspecified;
|
||||
switch (space_t) {
|
||||
case VPX_CS_BT_601:
|
||||
case VPX_CS_SMPTE_170:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user