In ResampleEffect, precompute the Lanczos function into a table.
[movit] / ycbcr_422interleaved_input_test.cpp
1 // Unit tests for YCbCr422InterleavedInput.
2
3 #include <epoxy/gl.h>
4 #include <stddef.h>
5
6 #include "effect_chain.h"
7 #include "gtest/gtest.h"
8 #include "test_util.h"
9 #include "util.h"
10 #include "resize_effect.h"
11 #include "ycbcr_422interleaved_input.h"
12
13 namespace movit {
14
15 // Adapted from the Simple444 test from YCbCrInputTest.
16 TEST(YCbCr422InterleavedInputTest, Simple422) {
17         const int width = 2;
18         const int height = 5;
19
20         // Pure-color test inputs, calculated with the formulas in Rec. 601
21         // section 2.5.4.
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,
28         };
29
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,
36         };
37         float out_data[4 * width * height];
38
39         EffectChainTester tester(NULL, width, height);
40
41         ImageFormat format;
42         format.color_space = COLORSPACE_sRGB;
43         format.gamma_curve = GAMMA_sRGB;
44
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;
55
56         YCbCr422InterleavedInput *input = new YCbCr422InterleavedInput(format, ycbcr_format, width, height);
57         input->set_pixel_data(uyvy);
58         tester.get_chain()->add_input(input);
59
60         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
61
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);
65 }
66
67 TEST(YCbCr422InterleavedInputTest, LumaLinearInterpolation) {
68         const int width = 4;
69         const int height = 1;
70         const int out_width = width * 3;
71
72         // Black, white, black and then gray.
73         unsigned char uyvy[width * height * 2] = {
74                 /*U=*/128, /*Y=*/ 16,
75                 /*V=*/128, /*Y=*/235,
76                 /*U=*/128, /*Y=*/ 16,
77                 /*V=*/128, /*Y=*/128,
78         };
79
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
82         };
83         float out_data[out_width * height];
84
85         EffectChainTester tester(NULL, out_width, height);
86
87         ImageFormat format;
88         format.color_space = COLORSPACE_sRGB;
89         format.gamma_curve = GAMMA_sRGB;
90
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;
101
102         YCbCr422InterleavedInput *input = new YCbCr422InterleavedInput(format, ycbcr_format, width, height);
103         input->set_pixel_data(uyvy);
104         tester.get_chain()->add_input(input);
105
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);
110
111         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
112
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);
116 }
117
118 // Adapted from the YCbCrInput test of the same name.
119 TEST(YCbCr422InterleavedInputTest, DifferentCbAndCrPositioning) {
120         const int width = 4;
121         const int height = 4;
122
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,
128         };
129
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, 
137         };
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 */, 
143         };
144         float out_data[width * height];
145
146         EffectChainTester tester(NULL, width, height);
147
148         ImageFormat format;
149         format.color_space = COLORSPACE_sRGB;
150         format.gamma_curve = GAMMA_sRGB;
151
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;
162
163         YCbCr422InterleavedInput *input = new YCbCr422InterleavedInput(format, ycbcr_format, width, height);
164         input->set_pixel_data(uyvy);
165         tester.get_chain()->add_input(input);
166
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);
171
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);
174 }
175
176 TEST(YCbCr422InterleavedInputTest, PBO) {
177         const int width = 2;
178         const int height = 5;
179
180         // Pure-color test inputs, calculated with the formulas in Rec. 601
181         // section 2.5.4.
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,
188         };
189
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,
196         };
197         float out_data[4 * width * height];
198
199         GLuint pbo;
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);
204
205         EffectChainTester tester(NULL, width, height);
206
207         ImageFormat format;
208         format.color_space = COLORSPACE_sRGB;
209         format.gamma_curve = GAMMA_sRGB;
210
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;
221
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);
225
226         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
227
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);
231
232         glDeleteBuffers(1, &pbo);
233 }
234
235 }  // namespace movit