Add support for Y'CbCr output.
[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 }  // namespace movit