X-Git-Url: https://git.sesse.net/?p=movit;a=blobdiff_plain;f=ycbcr_input_test.cpp;h=7792b289ef6c1e43e8fd06cdc12dab700e412a46;hp=a5032af657de73935aabaef79983b3d7603a28c7;hb=98f458e22ce732e6c50a9856d7fd636dca49b4c3;hpb=274627c966f53780991e9f80887aa1906b592751 diff --git a/ycbcr_input_test.cpp b/ycbcr_input_test.cpp index a5032af..7792b28 100644 --- a/ycbcr_input_test.cpp +++ b/ycbcr_input_test.cpp @@ -69,6 +69,55 @@ TEST(YCbCrInputTest, Simple444) { expect_equal(expected_data, out_data, 4 * width, height, 0.025, 0.002); } +TEST(YCbCrInputTest, Interleaved444) { + const int width = 1; + const int height = 5; + + // Same data as Simple444, just rearranged. + unsigned char data[width * height * 3] = { + 16, 128, 128, + 235, 128, 128, + 81, 90, 240, + 145, 54, 34, + 41, 240, 110, + }; + float expected_data[4 * width * height] = { + 0.0, 0.0, 0.0, 1.0, + 1.0, 1.0, 1.0, 1.0, + 1.0, 0.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 1.0, + 0.0, 0.0, 1.0, 1.0, + }; + float out_data[4 * width * height]; + + EffectChainTester tester(NULL, width, height); + + ImageFormat format; + format.color_space = COLORSPACE_sRGB; + format.gamma_curve = GAMMA_sRGB; + + YCbCrFormat ycbcr_format; + ycbcr_format.luma_coefficients = YCBCR_REC_601; + ycbcr_format.full_range = false; + ycbcr_format.num_levels = 256; + ycbcr_format.chroma_subsampling_x = 1; + ycbcr_format.chroma_subsampling_y = 1; + ycbcr_format.cb_x_position = 0.5f; + ycbcr_format.cb_y_position = 0.5f; + ycbcr_format.cr_x_position = 0.5f; + ycbcr_format.cr_y_position = 0.5f; + + YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height, YCBCR_INPUT_INTERLEAVED); + input->set_pixel_data(0, data); + tester.get_chain()->add_input(input); + + tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB); + + // Y'CbCr isn't 100% accurate (the input values are rounded), + // so we need some leeway. + expect_equal(expected_data, out_data, 4 * width, height, 0.025, 0.002); +} + TEST(YCbCrInputTest, FullRangeRec601) { const int width = 1; const int height = 5; @@ -688,6 +737,36 @@ TEST(YCbCrTest, WikipediaJPEGMatrices) { EXPECT_NEAR(128.0, offset[2] * 255.0, 1e-3); } +TEST(YCbCrTest, BlackmagicForwardMatrix) { + YCbCrFormat ycbcr_format; + ycbcr_format.luma_coefficients = YCBCR_REC_709; + ycbcr_format.full_range = false; + ycbcr_format.num_levels = 256; + + float offset[3]; + Eigen::Matrix3d ycbcr_to_rgb; + compute_ycbcr_matrix(ycbcr_format, offset, &ycbcr_to_rgb); + + Eigen::Matrix3d rgb_to_ycbcr = ycbcr_to_rgb.inverse(); + + // Values from DeckLink SDK documentation. + EXPECT_NEAR( 0.183, rgb_to_ycbcr(0,0), 1e-3); + EXPECT_NEAR( 0.614, rgb_to_ycbcr(0,1), 1e-3); + EXPECT_NEAR( 0.062, rgb_to_ycbcr(0,2), 1e-3); + + EXPECT_NEAR(-0.101, rgb_to_ycbcr(1,0), 1e-3); + EXPECT_NEAR(-0.338, rgb_to_ycbcr(1,1), 1e-3); + EXPECT_NEAR( 0.439, rgb_to_ycbcr(1,2), 1e-3); + + EXPECT_NEAR( 0.439, rgb_to_ycbcr(2,0), 1e-3); + EXPECT_NEAR(-0.399, rgb_to_ycbcr(2,1), 1e-3); + EXPECT_NEAR(-0.040, rgb_to_ycbcr(2,2), 1e-3); + + EXPECT_NEAR( 16.0, offset[0] * 255.0, 1e-3); + EXPECT_NEAR(128.0, offset[1] * 255.0, 1e-3); + EXPECT_NEAR(128.0, offset[2] * 255.0, 1e-3); +} + TEST(YCbCrInputTest, NoData) { const int width = 1; const int height = 5; @@ -719,4 +798,64 @@ TEST(YCbCrInputTest, NoData) { // Don't care what the output was, just that it does not crash. } +TEST(YCbCrInputTest, TenBitInterleaved) { + const int width = 1; + const int height = 5; + + // Pure-color inputs, calculated using formulas 3.2, 3.3 and 3.4 from + // Rec. 709. (Except the first two, which are obvious given the 64–940 + // range of luminance.) + unsigned expanded_data[width * height * 3] = { + 64, 512, 512, + 940, 512, 512, + 250, 409, 960, + 691, 167, 105, + 127, 960, 471, + }; + float expected_data[4 * width * height] = { + 0.0, 0.0, 0.0, 1.0, + 1.0, 1.0, 1.0, 1.0, + 1.0, 0.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 1.0, + 0.0, 0.0, 1.0, 1.0, + }; + float out_data[4 * width * height]; + + // Pack 32:32:32 to 10:10:10:2. + uint32_t data[width * height]; + for (unsigned i = 0; i < width * height; ++i) { + data[i] = + expanded_data[i * 3 + 0] | + (expanded_data[i * 3 + 1] << 10) | + (expanded_data[i * 3 + 2] << 20); + } + + EffectChainTester tester(NULL, width, height); + + ImageFormat format; + format.color_space = COLORSPACE_sRGB; + format.gamma_curve = GAMMA_sRGB; + + YCbCrFormat ycbcr_format; + ycbcr_format.luma_coefficients = YCBCR_REC_709; + ycbcr_format.full_range = false; + ycbcr_format.num_levels = 1024; // 10-bit. + ycbcr_format.chroma_subsampling_x = 1; + ycbcr_format.chroma_subsampling_y = 1; + ycbcr_format.cb_x_position = 0.5f; + ycbcr_format.cb_y_position = 0.5f; + ycbcr_format.cr_x_position = 0.5f; + ycbcr_format.cr_y_position = 0.5f; + + YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height, YCBCR_INPUT_INTERLEAVED, GL_UNSIGNED_INT_2_10_10_10_REV); + input->set_pixel_data(0, data); + tester.get_chain()->add_input(input); + + tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB); + + // We can set much tighter limits on this than 8-bit Y'CbCr; + // even tighter than the default limits. + expect_equal(expected_data, out_data, 4 * width, height, 0.002, 0.0003); +} + } // namespace movit