1 // Unit tests for YCbCr422InterleavedInput.
6 #include "effect_chain.h"
7 #include "gtest/gtest.h"
10 #include "resize_effect.h"
11 #include "ycbcr_422interleaved_input.h"
15 // Adapted from the Simple444 test from YCbCrInputTest.
16 TEST(YCbCr422InterleavedInputTest, Simple422) {
20 // Pure-color test inputs, calculated with the formulas in Rec. 601
22 unsigned char uyvy[width * height * 2] = {
23 /*U=*/128, /*Y=*/ 16, /*V=*/128, /*Y=*/ 16,
24 /*U=*/128, /*Y=*/235, /*V=*/128, /*Y=*/235,
25 /*U=*/ 90, /*Y=*/ 81, /*V=*/240, /*Y=*/ 81,
26 /*U=*/ 54, /*Y=*/145, /*V=*/ 34, /*Y=*/145,
27 /*U=*/240, /*Y=*/ 41, /*V=*/110, /*Y=*/ 41,
30 float expected_data[4 * width * height] = {
31 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0,
32 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
33 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0,
34 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
35 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0,
37 float out_data[4 * width * height];
39 EffectChainTester tester(NULL, width, height);
42 format.color_space = COLORSPACE_sRGB;
43 format.gamma_curve = GAMMA_sRGB;
45 YCbCrFormat ycbcr_format;
46 ycbcr_format.luma_coefficients = YCBCR_REC_601;
47 ycbcr_format.full_range = false;
48 ycbcr_format.chroma_subsampling_x = 2;
49 ycbcr_format.chroma_subsampling_y = 1;
50 ycbcr_format.cb_x_position = 0.0f; // Doesn't really matter here, since Y is constant.
51 ycbcr_format.cb_y_position = 0.5f;
52 ycbcr_format.cr_x_position = 0.0f;
53 ycbcr_format.cr_y_position = 0.5f;
55 YCbCr422InterleavedInput *input = new YCbCr422InterleavedInput(format, ycbcr_format, width, height);
56 input->set_pixel_data(uyvy);
57 tester.get_chain()->add_input(input);
59 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
61 // Y'CbCr isn't 100% accurate (the input values are rounded),
62 // so we need some leeway.
63 expect_equal(expected_data, out_data, 4 * width, height, 0.025, 0.002);
66 TEST(YCbCr422InterleavedInputTest, LumaLinearInterpolation) {
69 const int out_width = width * 3;
71 // Black, white, black and then gray.
72 unsigned char uyvy[width * height * 2] = {
79 float expected_data[out_width * height] = {
80 0.0, /**/0.0, 0.333, 0.667, /**/1.0, 0.667, 0.333, /**/0.0, 0.167, 0.333, /**/0.5, 0.5
82 float out_data[out_width * height];
84 EffectChainTester tester(NULL, out_width, height);
87 format.color_space = COLORSPACE_sRGB;
88 format.gamma_curve = GAMMA_sRGB;
90 YCbCrFormat ycbcr_format;
91 ycbcr_format.luma_coefficients = YCBCR_REC_601;
92 ycbcr_format.full_range = false;
93 ycbcr_format.chroma_subsampling_x = 2;
94 ycbcr_format.chroma_subsampling_y = 1;
95 ycbcr_format.cb_x_position = 0.0f; // Doesn't really matter here, since U/V are constant.
96 ycbcr_format.cb_y_position = 0.5f;
97 ycbcr_format.cr_x_position = 0.0f;
98 ycbcr_format.cr_y_position = 0.5f;
100 YCbCr422InterleavedInput *input = new YCbCr422InterleavedInput(format, ycbcr_format, width, height);
101 input->set_pixel_data(uyvy);
102 tester.get_chain()->add_input(input);
104 ResizeEffect *upscale = new ResizeEffect();
105 ASSERT_TRUE(upscale->set_int("width", out_width));
106 ASSERT_TRUE(upscale->set_int("height", height));
107 tester.get_chain()->add_effect(upscale);
109 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
111 // Y'CbCr isn't 100% accurate (the input values are rounded),
112 // so we need some leeway.
113 expect_equal(expected_data, out_data, out_width, height, 0.025, 0.002);
116 // Adapted from the YCbCrInput test of the same name.
117 TEST(YCbCr422InterleavedInputTest, DifferentCbAndCrPositioning) {
119 const int height = 4;
121 unsigned char uyvy[width * height * 2] = {
122 /*U=*/ 64, /*Y=*/126, /*V=*/ 48, /*Y=*/126, /*U=*/128, /*Y=*/126, /*V=*/128, /*Y=*/126,
123 /*U=*/128, /*Y=*/126, /*V=*/128, /*Y=*/126, /*U=*/192, /*Y=*/126, /*V=*/208, /*Y=*/126,
124 /*U=*/128, /*Y=*/126, /*V=*/128, /*Y=*/126, /*U=*/128, /*Y=*/126, /*V=*/128, /*Y=*/126,
125 /*U=*/128, /*Y=*/126, /*V=*/128, /*Y=*/126, /*U=*/128, /*Y=*/126, /*V=*/128, /*Y=*/126,
128 // Chroma samples in this case are always co-sited with a luma sample;
129 // their associated color values and position are marked off in comments.
130 float expected_data_blue[width * height] = {
131 0.000 /* 0.0 */, 0.250, 0.500 /* 0.5 */, 0.500,
132 0.500 /* 0.5 */, 0.750, 1.000 /* 1.0 */, 1.000,
133 0.500 /* 0.5 */, 0.500, 0.500 /* 0.5 */, 0.500,
134 0.500 /* 0.5 */, 0.500, 0.500 /* 0.5 */, 0.500,
136 float expected_data_red[width * height] = {
137 0.000, 0.000 /* 0.0 */, 0.250, 0.500 /* 0.5 */,
138 0.500, 0.500 /* 0.5 */, 0.750, 1.000 /* 1.0 */,
139 0.500, 0.500 /* 0.5 */, 0.500, 0.500 /* 0.5 */,
140 0.500, 0.500 /* 0.5 */, 0.500, 0.500 /* 0.5 */,
142 float out_data[width * height];
144 EffectChainTester tester(NULL, width, height);
147 format.color_space = COLORSPACE_sRGB;
148 format.gamma_curve = GAMMA_sRGB;
150 YCbCrFormat ycbcr_format;
151 ycbcr_format.luma_coefficients = YCBCR_REC_601;
152 ycbcr_format.full_range = false;
153 ycbcr_format.chroma_subsampling_x = 2;
154 ycbcr_format.chroma_subsampling_y = 1;
155 ycbcr_format.cb_x_position = 0.0f;
156 ycbcr_format.cb_y_position = 0.5f;
157 ycbcr_format.cr_x_position = 1.0f;
158 ycbcr_format.cr_y_position = 0.5f;
160 YCbCr422InterleavedInput *input = new YCbCr422InterleavedInput(format, ycbcr_format, width, height);
161 input->set_pixel_data(uyvy);
162 tester.get_chain()->add_input(input);
164 // Y'CbCr isn't 100% accurate (the input values are rounded),
165 // so we need some leeway.
166 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
167 expect_equal(expected_data_red, out_data, width, height, 0.02, 0.002);
169 tester.run(out_data, GL_BLUE, COLORSPACE_sRGB, GAMMA_sRGB);
170 expect_equal(expected_data_blue, out_data, width, height, 0.01, 0.001);
173 TEST(YCbCr422InterleavedInputTest, PBO) {
175 const int height = 5;
177 // Pure-color test inputs, calculated with the formulas in Rec. 601
179 unsigned char uyvy[width * height * 2] = {
180 /*U=*/128, /*Y=*/ 16, /*V=*/128, /*Y=*/ 16,
181 /*U=*/128, /*Y=*/235, /*V=*/128, /*Y=*/235,
182 /*U=*/ 90, /*Y=*/ 81, /*V=*/240, /*Y=*/ 81,
183 /*U=*/ 54, /*Y=*/145, /*V=*/ 34, /*Y=*/145,
184 /*U=*/240, /*Y=*/ 41, /*V=*/110, /*Y=*/ 41,
187 float expected_data[4 * width * height] = {
188 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0,
189 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
190 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0,
191 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
192 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0,
194 float out_data[4 * width * height];
197 glGenBuffers(1, &pbo);
198 glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
199 glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, width * height * 2, uyvy, GL_STREAM_DRAW);
200 glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
202 EffectChainTester tester(NULL, width, height);
205 format.color_space = COLORSPACE_sRGB;
206 format.gamma_curve = GAMMA_sRGB;
208 YCbCrFormat ycbcr_format;
209 ycbcr_format.luma_coefficients = YCBCR_REC_601;
210 ycbcr_format.full_range = false;
211 ycbcr_format.chroma_subsampling_x = 2;
212 ycbcr_format.chroma_subsampling_y = 1;
213 ycbcr_format.cb_x_position = 0.0f; // Doesn't really matter here, since Y is constant.
214 ycbcr_format.cb_y_position = 0.5f;
215 ycbcr_format.cr_x_position = 0.0f;
216 ycbcr_format.cr_y_position = 0.5f;
218 YCbCr422InterleavedInput *input = new YCbCr422InterleavedInput(format, ycbcr_format, width, height);
219 input->set_pixel_data((unsigned char *)BUFFER_OFFSET(0), pbo);
220 tester.get_chain()->add_input(input);
222 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
224 // Y'CbCr isn't 100% accurate (the input values are rounded),
225 // so we need some leeway.
226 expect_equal(expected_data, out_data, 4 * width, height, 0.025, 0.002);
228 glDeleteBuffers(1, &pbo);