1 // Unit tests for DeinterlaceEffect.
4 #include <benchmark/benchmark.h>
10 #include "effect_chain.h"
11 #include "gtest/gtest.h"
12 #include "image_format.h"
14 #include "deinterlace_effect.h"
15 #include "test_util.h"
21 TEST(DeinterlaceTest, ConstantColor) {
27 float expected_data[] = {
36 EffectChainTester tester(NULL, 2, 6);
37 Effect *input1 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 2, 3);
38 Effect *input2 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 2, 3);
39 Effect *input3 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 2, 3);
40 Effect *input4 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 2, 3);
41 Effect *input5 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 2, 3);
42 Effect *deinterlace_effect = tester.get_chain()->add_effect(new DeinterlaceEffect(), input1, input2, input3, input4, input5);
44 ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 0));
45 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
46 expect_equal(expected_data, out_data, 2, 6);
48 ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 1));
49 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
50 expect_equal(expected_data, out_data, 2, 6);
53 // Also tests that top/bottom change works like expected.
54 TEST(DeinterlaceTest, VerticalInterpolation) {
57 float data[width * height] = {
58 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.2f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f,
59 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Differs from previous.
61 float expected_data_top[width * height * 2] = {
62 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.2f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Unchanged.
63 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.3f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f,
64 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Unchanged.
65 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Repeated.
67 float expected_data_bottom[width * height * 2] = {
68 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.2f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Repeated
69 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.2f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Unchanged.
70 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.3f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f,
71 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, // Unchanged.
73 float neg_blowout_data[width * height];
74 float pos_blowout_data[width * height];
75 float out_data[width * height * 2];
77 // Set previous and next fields to something so big that all the temporal checks
78 // are effectively turned off.
79 fill(neg_blowout_data, neg_blowout_data + width * height, -100.0f);
80 fill(pos_blowout_data, pos_blowout_data + width * height, 100.0f);
82 EffectChainTester tester(NULL, width, height * 2);
83 Effect *input1 = tester.add_input(neg_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
84 Effect *input2 = tester.add_input(neg_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
85 Effect *input3 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
86 Effect *input4 = tester.add_input(pos_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
87 Effect *input5 = tester.add_input(pos_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
88 Effect *deinterlace_effect = tester.get_chain()->add_effect(new DeinterlaceEffect(), input1, input2, input3, input4, input5);
90 ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 0));
91 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
92 expect_equal(expected_data_top, out_data, width, height * 2);
94 ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 1));
95 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
96 expect_equal(expected_data_bottom, out_data, width, height * 2);
99 TEST(DeinterlaceTest, DiagonalInterpolation) {
100 const int width = 11;
101 const int height = 3;
102 float data[width * height] = {
103 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.2f, 0.6f, 0.8f, 0.0f, 0.0f,
104 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, 0.0f, // Offset two pixels, one value modified.
105 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, // Offset four the other way.
108 // Expected degrees are marked in comments. Mostly we want +45 for the second line
109 // and -63 for the fourth, but due to the score being over three neighboring pixels,
110 // sometimes it doesn't work ideally like that.
111 float expected_data_top[width * height * 2] = {
112 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.2f, 0.6f, 0.8f, 0.0f, 0.0f, // Unchanged.
113 // | / / / / / / / / / |
114 // 0 +45 +45 +45 +45 +45 +45 +45 +45 +45 0
115 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.3f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f,
116 // | / / / / / / / / / |
117 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, 0.0f, 0.0f, 0.0f, 0.0f, // Unchanged.
119 // 0 -45 -63 -63 -63 -63 -63 -63 +63! +63! +63!
120 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.2f, 0.3f, 0.2f,
122 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, // Unchanged.
123 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.6f, 0.4f, 0.6f, 0.8f, // Repeated.
125 float neg_blowout_data[width * height];
126 float pos_blowout_data[width * height];
127 float out_data[width * height * 2];
129 // Set previous and next fields to something so big that all the temporal checks
130 // are effectively turned off.
131 fill(neg_blowout_data, neg_blowout_data + width * height, -100.0f);
132 fill(pos_blowout_data, pos_blowout_data + width * height, 100.0f);
134 EffectChainTester tester(NULL, width, height * 2);
135 Effect *input1 = tester.add_input(neg_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
136 Effect *input2 = tester.add_input(neg_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
137 Effect *input3 = tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
138 Effect *input4 = tester.add_input(pos_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
139 Effect *input5 = tester.add_input(pos_blowout_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
140 Effect *deinterlace_effect = tester.get_chain()->add_effect(new DeinterlaceEffect(), input1, input2, input3, input4, input5);
142 ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 0));
143 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR, OUTPUT_ALPHA_FORMAT_PREMULTIPLIED);
144 expect_equal(expected_data_top, out_data, width, height * 2);
147 TEST(DeinterlaceTest, FlickerBox) {
149 const int height = 4;
150 float white_data[width * height] = {
151 1.0f, 1.0f, 1.0f, 1.0f,
152 1.0f, 1.0f, 1.0f, 1.0f,
153 1.0f, 1.0f, 1.0f, 1.0f,
154 1.0f, 1.0f, 1.0f, 1.0f,
156 float black_data[width * height] = {
157 0.0f, 0.0f, 0.0f, 0.0f,
158 0.0f, 0.0f, 0.0f, 0.0f,
159 0.0f, 0.0f, 0.0f, 0.0f,
160 0.0f, 0.0f, 0.0f, 0.0f,
162 float striped_data[width * height * 2] = {
163 1.0f, 1.0f, 1.0f, 1.0f,
164 0.0f, 0.0f, 0.0f, 0.0f,
165 1.0f, 1.0f, 1.0f, 1.0f,
166 0.0f, 0.0f, 0.0f, 0.0f,
167 1.0f, 1.0f, 1.0f, 1.0f,
168 0.0f, 0.0f, 0.0f, 0.0f,
169 1.0f, 1.0f, 1.0f, 1.0f,
170 0.0f, 0.0f, 0.0f, 0.0f,
172 float out_data[width * height * 2];
175 EffectChainTester tester(NULL, width, height * 2);
176 Effect *white_input = tester.add_input(white_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
177 Effect *black_input = tester.add_input(black_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
178 Effect *deinterlace_effect = tester.get_chain()->add_effect(new DeinterlaceEffect(), white_input, black_input, white_input, black_input, white_input);
180 ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 0));
181 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR, OUTPUT_ALPHA_FORMAT_PREMULTIPLIED);
182 expect_equal(white_data, out_data, width, height);
183 expect_equal(white_data, out_data + width * height, width, height);
187 EffectChainTester tester(NULL, width, height * 2);
188 Effect *white_input = tester.add_input(white_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
189 Effect *black_input = tester.add_input(black_data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, height);
190 Effect *deinterlace_effect = tester.get_chain()->add_effect(new DeinterlaceEffect(), white_input, black_input, white_input, black_input, white_input);
192 ASSERT_TRUE(deinterlace_effect->set_int("enable_spatial_interlacing_check", 0));
193 ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 0));
194 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR, OUTPUT_ALPHA_FORMAT_PREMULTIPLIED);
195 expect_equal(striped_data, out_data, width, height * 2);
199 #ifdef HAVE_BENCHMARK
200 void BM_DeinterlaceEffect_Gray(benchmark::State &state)
202 unsigned width = state.range(0), height = state.range(1);
203 unsigned field_height = height / 2;
205 float *field1 = new float[width * field_height];
206 float *field2 = new float[width * field_height];
207 float *field3 = new float[width * field_height];
208 float *field4 = new float[width * field_height];
209 float *field5 = new float[width * field_height];
210 float *out_data = new float[width * height];
212 for (unsigned i = 0; i < width * field_height; ++i) {
220 EffectChainTester tester(NULL, width, height);
221 Effect *input1 = tester.add_input(field1, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, field_height);
222 Effect *input2 = tester.add_input(field2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, field_height);
223 Effect *input3 = tester.add_input(field3, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, field_height);
224 Effect *input4 = tester.add_input(field4, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, field_height);
225 Effect *input5 = tester.add_input(field5, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, field_height);
226 Effect *deinterlace_effect = tester.get_chain()->add_effect(new DeinterlaceEffect(), input1, input2, input3, input4, input5);
228 ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 0));
230 tester.benchmark(state, out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR, OUTPUT_ALPHA_FORMAT_PREMULTIPLIED);
239 BENCHMARK(BM_DeinterlaceEffect_Gray)->Args({720, 576})->Args({1280, 720})->Args({1920, 1080})->UseRealTime()->Unit(benchmark::kMicrosecond);