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
21namespace libyuv {
22
23// hash seed of 5381 recommended.
24static 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
34TEST_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
119TEST_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
135TEST_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
150TEST_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
178TEST_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}
205TEST_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
237TEST_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
277TEST_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
301TEST_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
325TEST_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
402TEST_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
426TEST_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