]> git.sesse.net Git - movit/blob - colorspace_conversion_effect_test.cpp
Release Movit 1.7.1.
[movit] / colorspace_conversion_effect_test.cpp
1 // Unit tests for ColorspaceConversionEffect.
2
3 #include <epoxy/gl.h>
4
5 #include "colorspace_conversion_effect.h"
6 #include "gtest/gtest.h"
7 #include "test_util.h"
8
9 namespace movit {
10
11 TEST(ColorspaceConversionEffectTest, Reversible) {
12         float data[] = {
13                 0.0f, 0.0f, 0.0f, 1.0f,
14                 1.0f, 1.0f, 1.0f, 1.0f,
15                 1.0f, 0.0f, 0.0f, 1.0f,
16                 0.0f, 1.0f, 0.0f, 1.0f,
17                 0.0f, 0.0f, 1.0f, 1.0f,
18                 0.0f, 1.0f, 1.0f, 0.5f,
19         };
20         float temp_data[4 * 6], out_data[4 * 6];
21
22         {
23                 EffectChainTester tester(data, 1, 6, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
24                 tester.run(temp_data, GL_RGBA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
25         }
26         {
27                 EffectChainTester tester(temp_data, 1, 6, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
28                 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
29         }
30
31         expect_equal(data, out_data, 4, 6);
32 }
33
34 TEST(ColorspaceConversionEffectTest, sRGB_Primaries) {
35         float data[] = {
36                 0.0f, 0.0f, 0.0f, 1.0f,
37                 1.0f, 1.0f, 1.0f, 1.0f,
38                 1.0f, 0.0f, 0.0f, 1.0f,
39                 0.0f, 1.0f, 0.0f, 1.0f,
40                 0.0f, 0.0f, 1.0f, 1.0f,
41         };
42         float out_data[4 * 5];
43
44         EffectChainTester tester(data, 1, 5, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA32F);
45         tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
46
47         // Black should stay black.
48         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
49         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
50         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
51         EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
52
53         // White point should be D65.
54         // XYZ values from http://en.wikipedia.org/wiki/CIE_Standard_Illuminant_D65.
55         EXPECT_NEAR(0.9505, out_data[1 * 4 + 0], 1e-3);
56         EXPECT_NEAR(1.0000, out_data[1 * 4 + 1], 1e-3);
57         EXPECT_NEAR(1.0889, out_data[1 * 4 + 2], 1e-3);
58         EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
59
60         float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
61         float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
62         float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
63         EXPECT_NEAR(0.3127, white_x, 1e-3);
64         EXPECT_NEAR(0.3290, white_y, 1e-3);
65         EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
66
67         // Convert the primaries from XYZ to xyz, and compare to the references
68         // given by Rec. 709 (which are shared with sRGB).
69
70         float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
71         float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
72         float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
73         EXPECT_NEAR(0.640, red_x, 1e-3);
74         EXPECT_NEAR(0.330, red_y, 1e-3);
75         EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
76
77         float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
78         float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
79         float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
80         EXPECT_NEAR(0.300, green_x, 1e-3);
81         EXPECT_NEAR(0.600, green_y, 1e-3);
82         EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
83
84         float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
85         float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
86         float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
87         EXPECT_NEAR(0.150, blue_x, 1e-3);
88         EXPECT_NEAR(0.060, blue_y, 1e-3);
89         EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
90
91         // The forward matrix should be exactly as specified in the standard,
92         // up to floating-point precision. (We're not compliant with the
93         // inverse matrix, but we should be very close.)
94         EXPECT_FLOAT_EQ(0.4124f, out_data[2 * 4 + 0]);
95         EXPECT_FLOAT_EQ(0.2126f, out_data[2 * 4 + 1]);
96         EXPECT_FLOAT_EQ(0.0193f, out_data[2 * 4 + 2]);
97
98         EXPECT_FLOAT_EQ(0.3576f, out_data[3 * 4 + 0]);
99         EXPECT_FLOAT_EQ(0.7152f, out_data[3 * 4 + 1]);
100         EXPECT_FLOAT_EQ(0.1192f, out_data[3 * 4 + 2]);
101
102         EXPECT_FLOAT_EQ(0.1805f, out_data[4 * 4 + 0]);
103         EXPECT_FLOAT_EQ(0.0722f, out_data[4 * 4 + 1]);
104         EXPECT_FLOAT_EQ(0.9505f, out_data[4 * 4 + 2]);
105 }
106
107 TEST(ColorspaceConversionEffectTest, Rec601_525_Primaries) {
108         float data[] = {
109                 0.0f, 0.0f, 0.0f, 1.0f,
110                 1.0f, 1.0f, 1.0f, 1.0f,
111                 1.0f, 0.0f, 0.0f, 1.0f,
112                 0.0f, 1.0f, 0.0f, 1.0f,
113                 0.0f, 0.0f, 1.0f, 1.0f,
114         };
115         float out_data[4 * 5];
116
117         EffectChainTester tester(data, 1, 5, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
118         tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
119
120         // Black should stay black.
121         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
122         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
123         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
124         EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
125
126         // Convert the primaries from XYZ to xyz, and compare to the references
127         // given by Rec. 601.
128         float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
129         float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
130         float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
131         EXPECT_NEAR(0.3127, white_x, 1e-3);
132         EXPECT_NEAR(0.3290, white_y, 1e-3);
133         EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
134
135         float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
136         float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
137         float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
138         EXPECT_NEAR(0.630, red_x, 1e-3);
139         EXPECT_NEAR(0.340, red_y, 1e-3);
140         EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
141
142         float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
143         float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
144         float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
145         EXPECT_NEAR(0.310, green_x, 1e-3);
146         EXPECT_NEAR(0.595, green_y, 1e-3);
147         EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
148
149         float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
150         float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
151         float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
152         EXPECT_NEAR(0.155, blue_x, 1e-3);
153         EXPECT_NEAR(0.070, blue_y, 1e-3);
154         EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
155 }
156
157 TEST(ColorspaceConversionEffectTest, Rec601_625_Primaries) {
158         float data[] = {
159                 0.0f, 0.0f, 0.0f, 1.0f,
160                 1.0f, 1.0f, 1.0f, 1.0f,
161                 1.0f, 0.0f, 0.0f, 1.0f,
162                 0.0f, 1.0f, 0.0f, 1.0f,
163                 0.0f, 0.0f, 1.0f, 1.0f,
164         };
165         float out_data[4 * 5];
166
167         EffectChainTester tester(data, 1, 5, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_REC_601_625, GAMMA_LINEAR);
168         tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
169
170         // Black should stay black.
171         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
172         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
173         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
174         EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
175
176         // Convert the primaries from XYZ to xyz, and compare to the references
177         // given by Rec. 601.
178         float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
179         float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
180         float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
181         EXPECT_NEAR(0.3127, white_x, 1e-3);
182         EXPECT_NEAR(0.3290, white_y, 1e-3);
183         EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
184
185         float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
186         float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
187         float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
188         EXPECT_NEAR(0.640, red_x, 1e-3);
189         EXPECT_NEAR(0.330, red_y, 1e-3);
190         EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
191
192         float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
193         float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
194         float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
195         EXPECT_NEAR(0.290, green_x, 1e-3);
196         EXPECT_NEAR(0.600, green_y, 1e-3);
197         EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
198
199         float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
200         float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
201         float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
202         EXPECT_NEAR(0.150, blue_x, 1e-3);
203         EXPECT_NEAR(0.060, blue_y, 1e-3);
204         EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
205 }
206
207 TEST(ColorspaceConversionEffectTest, Rec2020_Primaries) {
208         float data[] = {
209                 0.0f, 0.0f, 0.0f, 1.0f,
210                 1.0f, 1.0f, 1.0f, 1.0f,
211                 1.0f, 0.0f, 0.0f, 1.0f,
212                 0.0f, 1.0f, 0.0f, 1.0f,
213                 0.0f, 0.0f, 1.0f, 1.0f,
214         };
215         float out_data[4 * 5];
216
217         EffectChainTester tester(data, 1, 5, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_REC_2020, GAMMA_LINEAR);
218         tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
219
220         // Black should stay black.
221         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
222         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
223         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
224         EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
225
226         // Convert the primaries from XYZ to xyz, and compare to the references
227         // given by Rec. 2020.
228         float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
229         float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
230         float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
231         EXPECT_NEAR(0.3127, white_x, 1e-3);
232         EXPECT_NEAR(0.3290, white_y, 1e-3);
233         EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
234
235         float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
236         float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
237         float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
238         EXPECT_NEAR(0.708, red_x, 1e-3);
239         EXPECT_NEAR(0.292, red_y, 1e-3);
240         EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
241
242         float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
243         float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
244         float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
245         EXPECT_NEAR(0.170, green_x, 1e-3);
246         EXPECT_NEAR(0.797, green_y, 1e-3);
247         EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
248
249         float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
250         float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
251         float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
252         EXPECT_NEAR(0.131, blue_x, 1e-3);
253         EXPECT_NEAR(0.046, blue_y, 1e-3);
254         EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
255 }
256
257 TEST(ColorspaceConversionEffectTest, sRGBToRec601_525) {
258         float data[] = {
259                 0.0f, 0.0f, 0.0f, 1.0f,
260                 1.0f, 1.0f, 1.0f, 1.0f,
261                 1.0f, 0.0f, 0.0f, 1.0f,
262                 0.0f, 1.0f, 0.0f, 1.0f,
263                 0.0f, 0.0f, 1.0f, 1.0f,
264                 0.0f, 1.0f, 1.0f, 0.5f,
265         };
266
267         // I have to admit that most of these come from the code itself;
268         // however, they do make sense if you look at the two gamuts
269         // in xy space.
270         float expected_data[] = {
271                 // Black should stay black.
272                 0.0f, 0.0f, 0.0f, 1.0f,
273
274                 // White should stay white (both use the D65 white point).
275                 1.0f, 1.0f, 1.0f, 1.0f,
276
277                 // sRGB red is slightly out-of-gamut for Rec. 601/525.
278                 1.064f, -0.020f, 0.0f, 1.0f,
279
280                 // Green too.
281                 -0.055f, 1.036f, 0.004f, 1.0f,
282
283                 // The blues are much closer; it _is_ still out-of-gamut,
284                 // but not actually more saturated (farther from the
285                 // white point).
286                 -0.010f, -0.017f, 0.994f, 1.0f,
287
288                 // Cyan is a mix of green and blue. Note: The alpha is kept.
289                 -0.065f, 1.0195f, 0.998f, 0.5f,
290         };
291         float out_data[4 * 6];
292
293         EffectChainTester tester(data, 1, 6, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
294         tester.run(out_data, GL_RGBA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
295
296         expect_equal(expected_data, out_data, 4, 6);
297 }
298
299 }  // namespace movit