1 /*
2 * Copyright 2011 The LibYuv Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <stdlib.h>
12 #include <string.h>
13 #include <time.h>
14
15 #include "../unit_test/unit_test.h"
16 #include "libyuv/basic_types.h"
17 #include "libyuv/compare.h"
18 #include "libyuv/cpu_id.h"
19 #include "libyuv/video_common.h"
20
21 namespace libyuv {
22
23 // hash seed of 5381 recommended.
ReferenceHashDjb2(const uint8 * src,uint64 count,uint32 seed)24 static uint32 ReferenceHashDjb2(const uint8* src, uint64 count, uint32 seed) {
25 uint32 hash = seed;
26 if (count > 0) {
27 do {
28 hash = hash * 33 + *src++;
29 } while (--count);
30 }
31 return hash;
32 }
33
TEST_F(LibYUVBaseTest,Djb2_Test)34 TEST_F(LibYUVBaseTest, Djb2_Test) {
35 const int kMaxTest = benchmark_width_ * benchmark_height_;
36 align_buffer_page_end(src_a, kMaxTest);
37 align_buffer_page_end(src_b, kMaxTest);
38
39 const char* fox =
40 "The quick brown fox jumps over the lazy dog"
41 " and feels as if he were in the seventh heaven of typography"
42 " together with Hermann Zapf";
43 uint32 foxhash = HashDjb2(reinterpret_cast<const uint8*>(fox), 131, 5381);
44 const uint32 kExpectedFoxHash = 2611006483u;
45 EXPECT_EQ(kExpectedFoxHash, foxhash);
46
47 for (int i = 0; i < kMaxTest; ++i) {
48 src_a[i] = (fastrand() & 0xff);
49 src_b[i] = (fastrand() & 0xff);
50 }
51 // Compare different buffers. Expect hash is different.
52 uint32 h1 = HashDjb2(src_a, kMaxTest, 5381);
53 uint32 h2 = HashDjb2(src_b, kMaxTest, 5381);
54 EXPECT_NE(h1, h2);
55
56 // Make last half same. Expect hash is different.
57 memcpy(src_a + kMaxTest / 2, src_b + kMaxTest / 2, kMaxTest / 2);
58 h1 = HashDjb2(src_a, kMaxTest, 5381);
59 h2 = HashDjb2(src_b, kMaxTest, 5381);
60 EXPECT_NE(h1, h2);
61
62 // Make first half same. Expect hash is different.
63 memcpy(src_a + kMaxTest / 2, src_a, kMaxTest / 2);
64 memcpy(src_b + kMaxTest / 2, src_b, kMaxTest / 2);
65 memcpy(src_a, src_b, kMaxTest / 2);
66 h1 = HashDjb2(src_a, kMaxTest, 5381);
67 h2 = HashDjb2(src_b, kMaxTest, 5381);
68 EXPECT_NE(h1, h2);
69
70 // Make same. Expect hash is same.
71 memcpy(src_a, src_b, kMaxTest);
72 h1 = HashDjb2(src_a, kMaxTest, 5381);
73 h2 = HashDjb2(src_b, kMaxTest, 5381);
74 EXPECT_EQ(h1, h2);
75
76 // Mask seed different. Expect hash is different.
77 memcpy(src_a, src_b, kMaxTest);
78 h1 = HashDjb2(src_a, kMaxTest, 5381);
79 h2 = HashDjb2(src_b, kMaxTest, 1234);
80 EXPECT_NE(h1, h2);
81
82 // Make one byte different in middle. Expect hash is different.
83 memcpy(src_a, src_b, kMaxTest);
84 ++src_b[kMaxTest / 2];
85 h1 = HashDjb2(src_a, kMaxTest, 5381);
86 h2 = HashDjb2(src_b, kMaxTest, 5381);
87 EXPECT_NE(h1, h2);
88
89 // Make first byte different. Expect hash is different.
90 memcpy(src_a, src_b, kMaxTest);
91 ++src_b[0];
92 h1 = HashDjb2(src_a, kMaxTest, 5381);
93 h2 = HashDjb2(src_b, kMaxTest, 5381);
94 EXPECT_NE(h1, h2);
95
96 // Make last byte different. Expect hash is different.
97 memcpy(src_a, src_b, kMaxTest);
98 ++src_b[kMaxTest - 1];
99 h1 = HashDjb2(src_a, kMaxTest, 5381);
100 h2 = HashDjb2(src_b, kMaxTest, 5381);
101 EXPECT_NE(h1, h2);
102
103 // Make a zeros. Test different lengths. Expect hash is different.
104 memset(src_a, 0, kMaxTest);
105 h1 = HashDjb2(src_a, kMaxTest, 5381);
106 h2 = HashDjb2(src_a, kMaxTest / 2, 5381);
107 EXPECT_NE(h1, h2);
108
109 // Make a zeros and seed of zero. Test different lengths. Expect hash is same.
110 memset(src_a, 0, kMaxTest);
111 h1 = HashDjb2(src_a, kMaxTest, 0);
112 h2 = HashDjb2(src_a, kMaxTest / 2, 0);
113 EXPECT_EQ(h1, h2);
114
115 free_aligned_buffer_page_end(src_a);
116 free_aligned_buffer_page_end(src_b);
117 }
118
TEST_F(LibYUVBaseTest,BenchmarkDjb2_Opt)119 TEST_F(LibYUVBaseTest, BenchmarkDjb2_Opt) {
120 const int kMaxTest = benchmark_width_ * benchmark_height_;
121 align_buffer_page_end(src_a, kMaxTest);
122
123 for (int i = 0; i < kMaxTest; ++i) {
124 src_a[i] = i;
125 }
126 uint32 h2 = ReferenceHashDjb2(src_a, kMaxTest, 5381);
127 uint32 h1;
128 for (int i = 0; i < benchmark_iterations_; ++i) {
129 h1 = HashDjb2(src_a, kMaxTest, 5381);
130 }
131 EXPECT_EQ(h1, h2);
132 free_aligned_buffer_page_end(src_a);
133 }
134
TEST_F(LibYUVBaseTest,BenchmarkDjb2_Unaligned)135 TEST_F(LibYUVBaseTest, BenchmarkDjb2_Unaligned) {
136 const int kMaxTest = benchmark_width_ * benchmark_height_;
137 align_buffer_page_end(src_a, kMaxTest + 1);
138 for (int i = 0; i < kMaxTest; ++i) {
139 src_a[i + 1] = i;
140 }
141 uint32 h2 = ReferenceHashDjb2(src_a + 1, kMaxTest, 5381);
142 uint32 h1;
143 for (int i = 0; i < benchmark_iterations_; ++i) {
144 h1 = HashDjb2(src_a + 1, kMaxTest, 5381);
145 }
146 EXPECT_EQ(h1, h2);
147 free_aligned_buffer_page_end(src_a);
148 }
149
TEST_F(LibYUVBaseTest,BenchmarkARGBDetect_Opt)150 TEST_F(LibYUVBaseTest, BenchmarkARGBDetect_Opt) {
151 uint32 fourcc;
152 const int kMaxTest = benchmark_width_ * benchmark_height_ * 4;
153 align_buffer_page_end(src_a, kMaxTest);
154 for (int i = 0; i < kMaxTest; ++i) {
155 src_a[i] = 255;
156 }
157
158 src_a[0] = 0;
159 fourcc = ARGBDetect(src_a, benchmark_width_ * 4, benchmark_width_,
160 benchmark_height_);
161 EXPECT_EQ(static_cast<uint32>(libyuv::FOURCC_BGRA), fourcc);
162 src_a[0] = 255;
163 src_a[3] = 0;
164 fourcc = ARGBDetect(src_a, benchmark_width_ * 4, benchmark_width_,
165 benchmark_height_);
166 EXPECT_EQ(static_cast<uint32>(libyuv::FOURCC_ARGB), fourcc);
167 src_a[3] = 255;
168
169 for (int i = 0; i < benchmark_iterations_; ++i) {
170 fourcc = ARGBDetect(src_a, benchmark_width_ * 4, benchmark_width_,
171 benchmark_height_);
172 }
173 EXPECT_EQ(0u, fourcc);
174
175 free_aligned_buffer_page_end(src_a);
176 }
177
TEST_F(LibYUVBaseTest,BenchmarkARGBDetect_Unaligned)178 TEST_F(LibYUVBaseTest, BenchmarkARGBDetect_Unaligned) {
179 uint32 fourcc;
180 const int kMaxTest = benchmark_width_ * benchmark_height_ * 4 + 1;
181 align_buffer_page_end(src_a, kMaxTest);
182 for (int i = 1; i < kMaxTest; ++i) {
183 src_a[i] = 255;
184 }
185
186 src_a[0 + 1] = 0;
187 fourcc = ARGBDetect(src_a + 1, benchmark_width_ * 4, benchmark_width_,
188 benchmark_height_);
189 EXPECT_EQ(static_cast<uint32>(libyuv::FOURCC_BGRA), fourcc);
190 src_a[0 + 1] = 255;
191 src_a[3 + 1] = 0;
192 fourcc = ARGBDetect(src_a + 1, benchmark_width_ * 4, benchmark_width_,
193 benchmark_height_);
194 EXPECT_EQ(static_cast<uint32>(libyuv::FOURCC_ARGB), fourcc);
195 src_a[3 + 1] = 255;
196
197 for (int i = 0; i < benchmark_iterations_; ++i) {
198 fourcc = ARGBDetect(src_a + 1, benchmark_width_ * 4, benchmark_width_,
199 benchmark_height_);
200 }
201 EXPECT_EQ(0u, fourcc);
202
203 free_aligned_buffer_page_end(src_a);
204 }
TEST_F(LibYUVBaseTest,BenchmarkSumSquareError_Opt)205 TEST_F(LibYUVBaseTest, BenchmarkSumSquareError_Opt) {
206 const int kMaxWidth = 4096 * 3;
207 align_buffer_page_end(src_a, kMaxWidth);
208 align_buffer_page_end(src_b, kMaxWidth);
209 memset(src_a, 0, kMaxWidth);
210 memset(src_b, 0, kMaxWidth);
211
212 memcpy(src_a, "test0123test4567", 16);
213 memcpy(src_b, "tick0123tock4567", 16);
214 uint64 h1 = ComputeSumSquareError(src_a, src_b, 16);
215 EXPECT_EQ(790u, h1);
216
217 for (int i = 0; i < kMaxWidth; ++i) {
218 src_a[i] = i;
219 src_b[i] = i;
220 }
221 memset(src_a, 0, kMaxWidth);
222 memset(src_b, 0, kMaxWidth);
223
224 int count =
225 benchmark_iterations_ *
226 ((benchmark_width_ * benchmark_height_ + kMaxWidth - 1) / kMaxWidth);
227 for (int i = 0; i < count; ++i) {
228 h1 = ComputeSumSquareError(src_a, src_b, kMaxWidth);
229 }
230
231 EXPECT_EQ(0u, h1);
232
233 free_aligned_buffer_page_end(src_a);
234 free_aligned_buffer_page_end(src_b);
235 }
236
TEST_F(LibYUVBaseTest,SumSquareError)237 TEST_F(LibYUVBaseTest, SumSquareError) {
238 const int kMaxWidth = 4096 * 3;
239 align_buffer_page_end(src_a, kMaxWidth);
240 align_buffer_page_end(src_b, kMaxWidth);
241 memset(src_a, 0, kMaxWidth);
242 memset(src_b, 0, kMaxWidth);
243
244 uint64 err;
245 err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
246
247 EXPECT_EQ(0u, err);
248
249 memset(src_a, 1, kMaxWidth);
250 err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
251
252 EXPECT_EQ(static_cast<int>(err), kMaxWidth);
253
254 memset(src_a, 190, kMaxWidth);
255 memset(src_b, 193, kMaxWidth);
256 err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
257
258 EXPECT_EQ(static_cast<int>(err), kMaxWidth * 3 * 3);
259
260 for (int i = 0; i < kMaxWidth; ++i) {
261 src_a[i] = (fastrand() & 0xff);
262 src_b[i] = (fastrand() & 0xff);
263 }
264
265 MaskCpuFlags(disable_cpu_flags_);
266 uint64 c_err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
267
268 MaskCpuFlags(benchmark_cpu_info_);
269 uint64 opt_err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
270
271 EXPECT_EQ(c_err, opt_err);
272
273 free_aligned_buffer_page_end(src_a);
274 free_aligned_buffer_page_end(src_b);
275 }
276
TEST_F(LibYUVBaseTest,BenchmarkPsnr_Opt)277 TEST_F(LibYUVBaseTest, BenchmarkPsnr_Opt) {
278 align_buffer_page_end(src_a, benchmark_width_ * benchmark_height_);
279 align_buffer_page_end(src_b, benchmark_width_ * benchmark_height_);
280 for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
281 src_a[i] = i;
282 src_b[i] = i;
283 }
284
285 MaskCpuFlags(benchmark_cpu_info_);
286
287 double opt_time = get_time();
288 for (int i = 0; i < benchmark_iterations_; ++i)
289 CalcFramePsnr(src_a, benchmark_width_, src_b, benchmark_width_,
290 benchmark_width_, benchmark_height_);
291
292 opt_time = (get_time() - opt_time) / benchmark_iterations_;
293 printf("BenchmarkPsnr_Opt - %8.2f us opt\n", opt_time * 1e6);
294
295 EXPECT_EQ(0, 0);
296
297 free_aligned_buffer_page_end(src_a);
298 free_aligned_buffer_page_end(src_b);
299 }
300
TEST_F(LibYUVBaseTest,BenchmarkPsnr_Unaligned)301 TEST_F(LibYUVBaseTest, BenchmarkPsnr_Unaligned) {
302 align_buffer_page_end(src_a, benchmark_width_ * benchmark_height_ + 1);
303 align_buffer_page_end(src_b, benchmark_width_ * benchmark_height_);
304 for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
305 src_a[i + 1] = i;
306 src_b[i] = i;
307 }
308
309 MaskCpuFlags(benchmark_cpu_info_);
310
311 double opt_time = get_time();
312 for (int i = 0; i < benchmark_iterations_; ++i)
313 CalcFramePsnr(src_a + 1, benchmark_width_, src_b, benchmark_width_,
314 benchmark_width_, benchmark_height_);
315
316 opt_time = (get_time() - opt_time) / benchmark_iterations_;
317 printf("BenchmarkPsnr_Opt - %8.2f us opt\n", opt_time * 1e6);
318
319 EXPECT_EQ(0, 0);
320
321 free_aligned_buffer_page_end(src_a);
322 free_aligned_buffer_page_end(src_b);
323 }
324
TEST_F(LibYUVBaseTest,Psnr)325 TEST_F(LibYUVBaseTest, Psnr) {
326 const int kSrcWidth = benchmark_width_;
327 const int kSrcHeight = benchmark_height_;
328 const int b = 128;
329 const int kSrcPlaneSize = (kSrcWidth + b * 2) * (kSrcHeight + b * 2);
330 const int kSrcStride = 2 * b + kSrcWidth;
331 align_buffer_page_end(src_a, kSrcPlaneSize);
332 align_buffer_page_end(src_b, kSrcPlaneSize);
333 memset(src_a, 0, kSrcPlaneSize);
334 memset(src_b, 0, kSrcPlaneSize);
335
336 double err;
337 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
338 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
339 kSrcHeight);
340
341 EXPECT_EQ(err, kMaxPsnr);
342
343 memset(src_a, 255, kSrcPlaneSize);
344
345 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
346 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
347 kSrcHeight);
348
349 EXPECT_EQ(err, 0.0);
350
351 memset(src_a, 1, kSrcPlaneSize);
352
353 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
354 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
355 kSrcHeight);
356
357 EXPECT_GT(err, 48.0);
358 EXPECT_LT(err, 49.0);
359
360 for (int i = 0; i < kSrcPlaneSize; ++i) {
361 src_a[i] = i;
362 }
363
364 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
365 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
366 kSrcHeight);
367
368 EXPECT_GT(err, 2.0);
369 if (kSrcWidth * kSrcHeight >= 256) {
370 EXPECT_LT(err, 6.0);
371 }
372
373 memset(src_a, 0, kSrcPlaneSize);
374 memset(src_b, 0, kSrcPlaneSize);
375
376 for (int i = b; i < (kSrcHeight + b); ++i) {
377 for (int j = b; j < (kSrcWidth + b); ++j) {
378 src_a[(i * kSrcStride) + j] = (fastrand() & 0xff);
379 src_b[(i * kSrcStride) + j] = (fastrand() & 0xff);
380 }
381 }
382
383 MaskCpuFlags(disable_cpu_flags_);
384 double c_err, opt_err;
385
386 c_err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
387 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
388 kSrcHeight);
389
390 MaskCpuFlags(benchmark_cpu_info_);
391
392 opt_err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
393 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
394 kSrcHeight);
395
396 EXPECT_EQ(opt_err, c_err);
397
398 free_aligned_buffer_page_end(src_a);
399 free_aligned_buffer_page_end(src_b);
400 }
401
TEST_F(LibYUVBaseTest,DISABLED_BenchmarkSsim_Opt)402 TEST_F(LibYUVBaseTest, DISABLED_BenchmarkSsim_Opt) {
403 align_buffer_page_end(src_a, benchmark_width_ * benchmark_height_);
404 align_buffer_page_end(src_b, benchmark_width_ * benchmark_height_);
405 for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
406 src_a[i] = i;
407 src_b[i] = i;
408 }
409
410 MaskCpuFlags(benchmark_cpu_info_);
411
412 double opt_time = get_time();
413 for (int i = 0; i < benchmark_iterations_; ++i)
414 CalcFrameSsim(src_a, benchmark_width_, src_b, benchmark_width_,
415 benchmark_width_, benchmark_height_);
416
417 opt_time = (get_time() - opt_time) / benchmark_iterations_;
418 printf("BenchmarkSsim_Opt - %8.2f us opt\n", opt_time * 1e6);
419
420 EXPECT_EQ(0, 0); // Pass if we get this far.
421
422 free_aligned_buffer_page_end(src_a);
423 free_aligned_buffer_page_end(src_b);
424 }
425
TEST_F(LibYUVBaseTest,Ssim)426 TEST_F(LibYUVBaseTest, Ssim) {
427 const int kSrcWidth = benchmark_width_;
428 const int kSrcHeight = benchmark_height_;
429 const int b = 128;
430 const int kSrcPlaneSize = (kSrcWidth + b * 2) * (kSrcHeight + b * 2);
431 const int kSrcStride = 2 * b + kSrcWidth;
432 align_buffer_page_end(src_a, kSrcPlaneSize);
433 align_buffer_page_end(src_b, kSrcPlaneSize);
434 memset(src_a, 0, kSrcPlaneSize);
435 memset(src_b, 0, kSrcPlaneSize);
436
437 if (kSrcWidth <= 8 || kSrcHeight <= 8) {
438 printf("warning - Ssim size too small. Testing function executes.\n");
439 }
440
441 double err;
442 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
443 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
444 kSrcHeight);
445
446 if (kSrcWidth > 8 && kSrcHeight > 8) {
447 EXPECT_EQ(err, 1.0);
448 }
449
450 memset(src_a, 255, kSrcPlaneSize);
451
452 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
453 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
454 kSrcHeight);
455
456 if (kSrcWidth > 8 && kSrcHeight > 8) {
457 EXPECT_LT(err, 0.0001);
458 }
459
460 memset(src_a, 1, kSrcPlaneSize);
461
462 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
463 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
464 kSrcHeight);
465
466 if (kSrcWidth > 8 && kSrcHeight > 8) {
467 EXPECT_GT(err, 0.0001);
468 EXPECT_LT(err, 0.9);
469 }
470
471 for (int i = 0; i < kSrcPlaneSize; ++i) {
472 src_a[i] = i;
473 }
474
475 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
476 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
477 kSrcHeight);
478
479 if (kSrcWidth > 8 && kSrcHeight > 8) {
480 EXPECT_GT(err, 0.0);
481 EXPECT_LT(err, 0.01);
482 }
483
484 for (int i = b; i < (kSrcHeight + b); ++i) {
485 for (int j = b; j < (kSrcWidth + b); ++j) {
486 src_a[(i * kSrcStride) + j] = (fastrand() & 0xff);
487 src_b[(i * kSrcStride) + j] = (fastrand() & 0xff);
488 }
489 }
490
491 MaskCpuFlags(disable_cpu_flags_);
492 double c_err, opt_err;
493
494 c_err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
495 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
496 kSrcHeight);
497
498 MaskCpuFlags(benchmark_cpu_info_);
499
500 opt_err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
501 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
502 kSrcHeight);
503
504 if (kSrcWidth > 8 && kSrcHeight > 8) {
505 EXPECT_EQ(opt_err, c_err);
506 }
507
508 free_aligned_buffer_page_end(src_a);
509 free_aligned_buffer_page_end(src_b);
510 }
511
512 } // namespace libyuv
513