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.num_levels = 256;
49 ycbcr_format.chroma_subsampling_x = 2;
50 ycbcr_format.chroma_subsampling_y = 1;
51 ycbcr_format.cb_x_position = 0.0f; // Doesn't really matter here, since Y is constant.
52 ycbcr_format.cb_y_position = 0.5f;
53 ycbcr_format.cr_x_position = 0.0f;
54 ycbcr_format.cr_y_position = 0.5f;
56 YCbCr422InterleavedInput *input = new YCbCr422InterleavedInput(format, ycbcr_format, width, height);
57 input->set_pixel_data(uyvy);
58 tester.get_chain()->add_input(input);
60 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
62 // Y'CbCr isn't 100% accurate (the input values are rounded),
63 // so we need some leeway.
64 expect_equal(expected_data, out_data, 4 * width, height, 0.025, 0.002);
67 TEST(YCbCr422InterleavedInputTest, LumaLinearInterpolation) {
70 const int out_width = width * 3;
72 // Black, white, black and then gray.
73 unsigned char uyvy[width * height * 2] = {
80 float expected_data[out_width * height] = {
81 0.0, /**/0.0, 0.333, 0.667, /**/1.0, 0.667, 0.333, /**/0.0, 0.167, 0.333, /**/0.5, 0.5
83 float out_data[out_width * height];
85 EffectChainTester tester(NULL, out_width, height);
88 format.color_space = COLORSPACE_sRGB;
89 format.gamma_curve = GAMMA_sRGB;
91 YCbCrFormat ycbcr_format;
92 ycbcr_format.luma_coefficients = YCBCR_REC_601;
93 ycbcr_format.full_range = false;
94 ycbcr_format.num_levels = 256;
95 ycbcr_format.chroma_subsampling_x = 2;
96 ycbcr_format.chroma_subsampling_y = 1;
97 ycbcr_format.cb_x_position = 0.0f; // Doesn't really matter here, since U/V are constant.
98 ycbcr_format.cb_y_position = 0.5f;
99 ycbcr_format.cr_x_position = 0.0f;
100 ycbcr_format.cr_y_position = 0.5f;
102 YCbCr422InterleavedInput *input = new YCbCr422InterleavedInput(format, ycbcr_format, width, height);
103 input->set_pixel_data(uyvy);
104 tester.get_chain()->add_input(input);
106 ResizeEffect *upscale = new ResizeEffect();
107 ASSERT_TRUE(upscale->set_int("width", out_width));
108 ASSERT_TRUE(upscale->set_int("height", height));
109 tester.get_chain()->add_effect(upscale);
111 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
113 // Y'CbCr isn't 100% accurate (the input values are rounded),
114 // so we need some leeway.
115 expect_equal(expected_data, out_data, out_width, height, 0.025, 0.002);
118 // Adapted from the YCbCrInput test of the same name.
119 TEST(YCbCr422InterleavedInputTest, DifferentCbAndCrPositioning) {
121 const int height = 4;
123 unsigned char uyvy[width * height * 2] = {
124 /*U=*/ 64, /*Y=*/126, /*V=*/ 48, /*Y=*/126, /*U=*/128, /*Y=*/126, /*V=*/128, /*Y=*/126,
125 /*U=*/128, /*Y=*/126, /*V=*/128, /*Y=*/126, /*U=*/192, /*Y=*/126, /*V=*/208, /*Y=*/126,
126 /*U=*/128, /*Y=*/126, /*V=*/128, /*Y=*/126, /*U=*/128, /*Y=*/126, /*V=*/128, /*Y=*/126,
127 /*U=*/128, /*Y=*/126, /*V=*/128, /*Y=*/126, /*U=*/128, /*Y=*/126, /*V=*/128, /*Y=*/126,
130 // Chroma samples in this case are always co-sited with a luma sample;
131 // their associated color values and position are marked off in comments.
132 float expected_data_blue[width * height] = {
133 0.000 /* 0.0 */, 0.250, 0.500 /* 0.5 */, 0.500,
134 0.500 /* 0.5 */, 0.750, 1.000 /* 1.0 */, 1.000,
135 0.500 /* 0.5 */, 0.500, 0.500 /* 0.5 */, 0.500,
136 0.500 /* 0.5 */, 0.500, 0.500 /* 0.5 */, 0.500,
138 float expected_data_red[width * height] = {
139 0.000, 0.000 /* 0.0 */, 0.250, 0.500 /* 0.5 */,
140 0.500, 0.500 /* 0.5 */, 0.750, 1.000 /* 1.0 */,
141 0.500, 0.500 /* 0.5 */, 0.500, 0.500 /* 0.5 */,
142 0.500, 0.500 /* 0.5 */, 0.500, 0.500 /* 0.5 */,
144 float out_data[width * height];
146 EffectChainTester tester(NULL, width, height);
149 format.color_space = COLORSPACE_sRGB;
150 format.gamma_curve = GAMMA_sRGB;
152 YCbCrFormat ycbcr_format;
153 ycbcr_format.luma_coefficients = YCBCR_REC_601;
154 ycbcr_format.full_range = false;
155 ycbcr_format.num_levels = 256;
156 ycbcr_format.chroma_subsampling_x = 2;
157 ycbcr_format.chroma_subsampling_y = 1;
158 ycbcr_format.cb_x_position = 0.0f;
159 ycbcr_format.cb_y_position = 0.5f;
160 ycbcr_format.cr_x_position = 1.0f;
161 ycbcr_format.cr_y_position = 0.5f;
163 YCbCr422InterleavedInput *input = new YCbCr422InterleavedInput(format, ycbcr_format, width, height);
164 input->set_pixel_data(uyvy);
165 tester.get_chain()->add_input(input);
167 // Y'CbCr isn't 100% accurate (the input values are rounded),
168 // so we need some leeway.
169 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
170 expect_equal(expected_data_red, out_data, width, height, 0.02, 0.002);
172 tester.run(out_data, GL_BLUE, COLORSPACE_sRGB, GAMMA_sRGB);
173 expect_equal(expected_data_blue, out_data, width, height, 0.01, 0.001);
176 TEST(YCbCr422InterleavedInputTest, PBO) {
178 const int height = 5;
180 // Pure-color test inputs, calculated with the formulas in Rec. 601
182 unsigned char uyvy[width * height * 2] = {
183 /*U=*/128, /*Y=*/ 16, /*V=*/128, /*Y=*/ 16,
184 /*U=*/128, /*Y=*/235, /*V=*/128, /*Y=*/235,
185 /*U=*/ 90, /*Y=*/ 81, /*V=*/240, /*Y=*/ 81,
186 /*U=*/ 54, /*Y=*/145, /*V=*/ 34, /*Y=*/145,
187 /*U=*/240, /*Y=*/ 41, /*V=*/110, /*Y=*/ 41,
190 float expected_data[4 * width * height] = {
191 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0,
192 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
193 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0,
194 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
195 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0,
197 float out_data[4 * width * height];
200 glGenBuffers(1, &pbo);
201 glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
202 glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, width * height * 2, uyvy, GL_STREAM_DRAW);
203 glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
205 EffectChainTester tester(NULL, width, height);
208 format.color_space = COLORSPACE_sRGB;
209 format.gamma_curve = GAMMA_sRGB;
211 YCbCrFormat ycbcr_format;
212 ycbcr_format.luma_coefficients = YCBCR_REC_601;
213 ycbcr_format.full_range = false;
214 ycbcr_format.num_levels = 256;
215 ycbcr_format.chroma_subsampling_x = 2;
216 ycbcr_format.chroma_subsampling_y = 1;
217 ycbcr_format.cb_x_position = 0.0f; // Doesn't really matter here, since Y is constant.
218 ycbcr_format.cb_y_position = 0.5f;
219 ycbcr_format.cr_x_position = 0.0f;
220 ycbcr_format.cr_y_position = 0.5f;
222 YCbCr422InterleavedInput *input = new YCbCr422InterleavedInput(format, ycbcr_format, width, height);
223 input->set_pixel_data((unsigned char *)BUFFER_OFFSET(0), pbo);
224 tester.get_chain()->add_input(input);
226 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
228 // Y'CbCr isn't 100% accurate (the input values are rounded),
229 // so we need some leeway.
230 expect_equal(expected_data, out_data, 4 * width, height, 0.025, 0.002);
232 glDeleteBuffers(1, &pbo);