]> git.sesse.net Git - movit/blob - ycbcr_conversion_effect_test.cpp
Add a mode for YCbCrInput where Cb and Cr are in the same texture.
[movit] / ycbcr_conversion_effect_test.cpp
1 // Unit tests for YCbCrConversionEffect. Mostly done by leveraging
2 // YCbCrInput and seeing that the right thing comes out at the
3 // other end.
4
5 #include <epoxy/gl.h>
6 #include <math.h>
7
8 #include "effect_chain.h"
9 #include "gtest/gtest.h"
10 #include "image_format.h"
11 #include "test_util.h"
12 #include "util.h"
13 #include "ycbcr_input.h"
14
15 namespace movit {
16
17 TEST(YCbCrConversionEffectTest, BasicInOut) {
18         const int width = 1;
19         const int height = 5;
20
21         // Pure-color test inputs, calculated with the formulas in Rec. 601
22         // section 2.5.4.
23         unsigned char y[width * height] = {
24                 16, 235, 81, 145, 41,
25         };
26         unsigned char cb[width * height] = {
27                 128, 128, 90, 54, 240,
28         };
29         unsigned char cr[width * height] = {
30                 128, 128, 240, 34, 110,
31         };
32         unsigned char expected_data[width * height * 4] = {
33                 // The same data, just rearranged.
34                  16, 128, 128, 255,
35                 235, 128, 128, 255,
36                  81,  90, 240, 255,
37                 145,  54,  34, 255,
38                  41, 240, 110, 255
39         };
40
41         unsigned char out_data[width * height * 4];
42
43         EffectChainTester tester(NULL, width, height);
44
45         ImageFormat format;
46         format.color_space = COLORSPACE_sRGB;
47         format.gamma_curve = GAMMA_sRGB;
48
49         YCbCrFormat ycbcr_format;
50         ycbcr_format.luma_coefficients = YCBCR_REC_601;
51         ycbcr_format.full_range = false;
52         ycbcr_format.num_levels = 256;
53         ycbcr_format.chroma_subsampling_x = 1;
54         ycbcr_format.chroma_subsampling_y = 1;
55         ycbcr_format.cb_x_position = 0.5f;
56         ycbcr_format.cb_y_position = 0.5f;
57         ycbcr_format.cr_x_position = 0.5f;
58         ycbcr_format.cr_y_position = 0.5f;
59
60         tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format);
61
62         YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
63         input->set_pixel_data(0, y);
64         input->set_pixel_data(1, cb);
65         input->set_pixel_data(2, cr);
66         tester.get_chain()->add_input(input);
67
68         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
69         expect_equal(expected_data, out_data, 4 * width, height);
70 }
71
72 TEST(YCbCrConversionEffectTest, ClampToValidRange) {
73         const int width = 1;
74         const int height = 6;
75
76         // Some out-of-range of at-range values.
77         // Y should be clamped to 16-235 and Cb/Cr to 16-240.
78         // (Alpha should still be 255.)
79         unsigned char y[width * height] = {
80                 0, 10, 16, 235, 240, 255
81         };
82         unsigned char cb[width * height] = {
83                 0, 10, 16, 235, 240, 255,
84         };
85         unsigned char cr[width * height] = {
86                 255, 240, 235, 16, 10, 0,
87         };
88         unsigned char expected_data[width * height * 4] = {
89                 16, 16, 240, 255,
90                 16, 16, 240, 255,
91                 16, 16, 235, 255,
92                 235, 235, 16, 255,
93                 235, 240, 16, 255,
94                 235, 240, 16, 255,
95         };
96
97         unsigned char out_data[width * height * 4];
98
99         EffectChainTester tester(NULL, width, height);
100
101         ImageFormat format;
102         format.color_space = COLORSPACE_sRGB;
103         format.gamma_curve = GAMMA_sRGB;
104
105         YCbCrFormat ycbcr_format;
106         ycbcr_format.luma_coefficients = YCBCR_REC_601;
107         ycbcr_format.full_range = false;
108         ycbcr_format.num_levels = 256;
109         ycbcr_format.chroma_subsampling_x = 1;
110         ycbcr_format.chroma_subsampling_y = 1;
111         ycbcr_format.cb_x_position = 0.5f;
112         ycbcr_format.cb_y_position = 0.5f;
113         ycbcr_format.cr_x_position = 0.5f;
114         ycbcr_format.cr_y_position = 0.5f;
115
116         tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format);
117
118         YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
119         input->set_pixel_data(0, y);
120         input->set_pixel_data(1, cb);
121         input->set_pixel_data(2, cr);
122         tester.get_chain()->add_input(input);
123
124         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
125         expect_equal(expected_data, out_data, 4 * width, height);
126 }
127
128 TEST(YCbCrConversionEffectTest, LimitedRangeToFullRange) {
129         const int width = 1;
130         const int height = 5;
131
132         // Pure-color test inputs, calculated with the formulas in Rec. 601
133         // section 2.5.4.
134         unsigned char y[width * height] = {
135                 16, 235, 81, 145, 41,
136         };
137         unsigned char cb[width * height] = {
138                 128, 128, 90, 54, 240,
139         };
140         unsigned char cr[width * height] = {
141                 128, 128, 240, 34, 110,
142         };
143         unsigned char expected_data[width * height * 4] = {
144                 // Range now from 0-255 for all components, and values in-between
145                 // also adjusted a bit.
146                   0, 128, 128, 255,
147                 255, 128, 128, 255,
148                  76,  85, 255, 255,
149                 150,  44,  21, 255,
150                  29, 255, 107, 255
151         };
152
153         unsigned char out_data[width * height * 4];
154
155         EffectChainTester tester(NULL, width, height);
156
157         ImageFormat format;
158         format.color_space = COLORSPACE_sRGB;
159         format.gamma_curve = GAMMA_sRGB;
160
161         YCbCrFormat ycbcr_format;
162         ycbcr_format.luma_coefficients = YCBCR_REC_601;
163         ycbcr_format.full_range = true;
164         ycbcr_format.num_levels = 256;
165         ycbcr_format.chroma_subsampling_x = 1;
166         ycbcr_format.chroma_subsampling_y = 1;
167         ycbcr_format.cb_x_position = 0.5f;
168         ycbcr_format.cb_y_position = 0.5f;
169         ycbcr_format.cr_x_position = 0.5f;
170         ycbcr_format.cr_y_position = 0.5f;
171
172         tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format);
173
174         ycbcr_format.full_range = false;
175         YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
176         input->set_pixel_data(0, y);
177         input->set_pixel_data(1, cb);
178         input->set_pixel_data(2, cr);
179         tester.get_chain()->add_input(input);
180
181         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
182         expect_equal(expected_data, out_data, 4 * width, height);
183 }
184
185 TEST(YCbCrConversionEffectTest, PlanarOutput) {
186         const int width = 1;
187         const int height = 5;
188
189         // Pure-color test inputs, calculated with the formulas in Rec. 601
190         // section 2.5.4.
191         unsigned char y[width * height] = {
192                 16, 235, 81, 145, 41,
193         };
194         unsigned char cb[width * height] = {
195                 128, 128, 90, 54, 240,
196         };
197         unsigned char cr[width * height] = {
198                 128, 128, 240, 34, 110,
199         };
200
201         unsigned char out_y[width * height], out_cb[width * height], out_cr[width * height];
202
203         EffectChainTester tester(NULL, width, height);
204
205         ImageFormat format;
206         format.color_space = COLORSPACE_sRGB;
207         format.gamma_curve = GAMMA_sRGB;
208
209         YCbCrFormat ycbcr_format;
210         ycbcr_format.luma_coefficients = YCBCR_REC_601;
211         ycbcr_format.full_range = false;
212         ycbcr_format.num_levels = 256;
213         ycbcr_format.chroma_subsampling_x = 1;
214         ycbcr_format.chroma_subsampling_y = 1;
215         ycbcr_format.cb_x_position = 0.5f;
216         ycbcr_format.cb_y_position = 0.5f;
217         ycbcr_format.cr_x_position = 0.5f;
218         ycbcr_format.cr_y_position = 0.5f;
219
220         tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format, YCBCR_OUTPUT_PLANAR);
221
222         YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
223         input->set_pixel_data(0, y);
224         input->set_pixel_data(1, cb);
225         input->set_pixel_data(2, cr);
226         tester.get_chain()->add_input(input);
227
228         tester.run(out_y, out_cb, out_cr, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
229         expect_equal(y, out_y, width, height);
230         expect_equal(cb, out_cb, width, height);
231         expect_equal(cr, out_cr, width, height);
232 }
233
234 TEST(YCbCrConversionEffectTest, SplitLumaAndChroma) {
235         const int width = 1;
236         const int height = 5;
237
238         // Pure-color test inputs, calculated with the formulas in Rec. 601
239         // section 2.5.4.
240         unsigned char y[width * height] = {
241                 16, 235, 81, 145, 41,
242         };
243         unsigned char cb[width * height] = {
244                 128, 128, 90, 54, 240,
245         };
246         unsigned char cr[width * height] = {
247                 128, 128, 240, 34, 110,
248         };
249
250         // The R and A data, rearranged. Note: The G and B channels
251         // (the middle columns) are undefined. If we change the behavior,
252         // the test will need to be updated, but a failure is expected.
253         unsigned char expected_y[width * height * 4] = {
254                  16, /*undefined:*/  16, /*undefined:*/  16, 255,
255                 235, /*undefined:*/ 235, /*undefined:*/ 235, 255,
256                  81, /*undefined:*/  81, /*undefined:*/  81, 255,
257                 145, /*undefined:*/ 145, /*undefined:*/ 145, 255,
258                  41, /*undefined:*/  41, /*undefined:*/  41, 255,
259         };
260
261         // Just the Cb and Cr data, rearranged. The B and A channels
262         // are undefined, as below.
263         unsigned char expected_cbcr[width * height * 4] = {
264                 128, 128, /*undefined:*/ 128, /*undefined:*/ 255,
265                 128, 128, /*undefined:*/ 128, /*undefined:*/ 255,
266                  90, 240, /*undefined:*/ 240, /*undefined:*/ 255,
267                  54,  34, /*undefined:*/  34, /*undefined:*/ 255,
268                 240, 110, /*undefined:*/ 110, /*undefined:*/ 255,
269         };
270
271         unsigned char out_y[width * height], out_cbcr[width * height * 4];
272
273         EffectChainTester tester(NULL, width, height);
274
275         ImageFormat format;
276         format.color_space = COLORSPACE_sRGB;
277         format.gamma_curve = GAMMA_sRGB;
278
279         YCbCrFormat ycbcr_format;
280         ycbcr_format.luma_coefficients = YCBCR_REC_601;
281         ycbcr_format.full_range = false;
282         ycbcr_format.num_levels = 256;
283         ycbcr_format.chroma_subsampling_x = 1;
284         ycbcr_format.chroma_subsampling_y = 1;
285         ycbcr_format.cb_x_position = 0.5f;
286         ycbcr_format.cb_y_position = 0.5f;
287         ycbcr_format.cr_x_position = 0.5f;
288         ycbcr_format.cr_y_position = 0.5f;
289
290         tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format, YCBCR_OUTPUT_SPLIT_Y_AND_CBCR);
291
292         YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
293         input->set_pixel_data(0, y);
294         input->set_pixel_data(1, cb);
295         input->set_pixel_data(2, cr);
296         tester.get_chain()->add_input(input);
297
298         tester.run(out_y, out_cbcr, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
299         expect_equal(expected_y, out_y, width * 4, height);
300         expect_equal(expected_cbcr, out_cbcr, width * 4, height);
301 }
302
303 }  // namespace movit