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 = "The quick brown fox jumps over the lazy dog"
40      " and feels as if he were in the seventh heaven of typography"
41      " together with Hermann Zapf";
42  uint32 foxhash = HashDjb2(reinterpret_cast<const uint8*>(fox), 131, 5381);
43  const uint32 kExpectedFoxHash = 2611006483u;
44  EXPECT_EQ(kExpectedFoxHash, foxhash);
45
46  for (int i = 0; i < kMaxTest; ++i) {
47    src_a[i] = (fastrand() & 0xff);
48    src_b[i] = (fastrand() & 0xff);
49  }
50  // Compare different buffers. Expect hash is different.
51  uint32 h1 = HashDjb2(src_a, kMaxTest, 5381);
52  uint32 h2 = HashDjb2(src_b, kMaxTest, 5381);
53  EXPECT_NE(h1, h2);
54
55  // Make last half same. Expect hash is different.
56  memcpy(src_a + kMaxTest / 2, src_b + kMaxTest / 2, kMaxTest / 2);
57  h1 = HashDjb2(src_a, kMaxTest, 5381);
58  h2 = HashDjb2(src_b, kMaxTest, 5381);
59  EXPECT_NE(h1, h2);
60
61  // Make first half same. Expect hash is different.
62  memcpy(src_a + kMaxTest / 2, src_a, kMaxTest / 2);
63  memcpy(src_b + kMaxTest / 2, src_b, kMaxTest / 2);
64  memcpy(src_a, src_b, kMaxTest / 2);
65  h1 = HashDjb2(src_a, kMaxTest, 5381);
66  h2 = HashDjb2(src_b, kMaxTest, 5381);
67  EXPECT_NE(h1, h2);
68
69  // Make same. Expect hash is same.
70  memcpy(src_a, src_b, kMaxTest);
71  h1 = HashDjb2(src_a, kMaxTest, 5381);
72  h2 = HashDjb2(src_b, kMaxTest, 5381);
73  EXPECT_EQ(h1, h2);
74
75  // Mask seed different. Expect hash is different.
76  memcpy(src_a, src_b, kMaxTest);
77  h1 = HashDjb2(src_a, kMaxTest, 5381);
78  h2 = HashDjb2(src_b, kMaxTest, 1234);
79  EXPECT_NE(h1, h2);
80
81  // Make one byte different in middle. Expect hash is different.
82  memcpy(src_a, src_b, kMaxTest);
83  ++src_b[kMaxTest / 2];
84  h1 = HashDjb2(src_a, kMaxTest, 5381);
85  h2 = HashDjb2(src_b, kMaxTest, 5381);
86  EXPECT_NE(h1, h2);
87
88  // Make first byte different. Expect hash is different.
89  memcpy(src_a, src_b, kMaxTest);
90  ++src_b[0];
91  h1 = HashDjb2(src_a, kMaxTest, 5381);
92  h2 = HashDjb2(src_b, kMaxTest, 5381);
93  EXPECT_NE(h1, h2);
94
95  // Make last byte different. Expect hash is different.
96  memcpy(src_a, src_b, kMaxTest);
97  ++src_b[kMaxTest - 1];
98  h1 = HashDjb2(src_a, kMaxTest, 5381);
99  h2 = HashDjb2(src_b, kMaxTest, 5381);
100  EXPECT_NE(h1, h2);
101
102  // Make a zeros. Test different lengths. Expect hash is different.
103  memset(src_a, 0, kMaxTest);
104  h1 = HashDjb2(src_a, kMaxTest, 5381);
105  h2 = HashDjb2(src_a, kMaxTest / 2, 5381);
106  EXPECT_NE(h1, h2);
107
108  // Make a zeros and seed of zero. Test different lengths. Expect hash is same.
109  memset(src_a, 0, kMaxTest);
110  h1 = HashDjb2(src_a, kMaxTest, 0);
111  h2 = HashDjb2(src_a, kMaxTest / 2, 0);
112  EXPECT_EQ(h1, h2);
113
114  free_aligned_buffer_page_end(src_a);
115  free_aligned_buffer_page_end(src_b);
116}
117
118TEST_F(LibYUVBaseTest, BenchmarkDjb2_Opt) {
119  const int kMaxTest = benchmark_width_ * benchmark_height_;
120  align_buffer_page_end(src_a, kMaxTest);
121
122  for (int i = 0; i < kMaxTest; ++i) {
123    src_a[i] = i;
124  }
125  uint32 h2 = ReferenceHashDjb2(src_a, kMaxTest, 5381);
126  uint32 h1;
127  for (int i = 0; i < benchmark_iterations_; ++i) {
128    h1 = HashDjb2(src_a, kMaxTest, 5381);
129  }
130  EXPECT_EQ(h1, h2);
131  free_aligned_buffer_page_end(src_a);
132}
133
134TEST_F(LibYUVBaseTest, BenchmarkDjb2_Unaligned) {
135  const int kMaxTest = benchmark_width_ * benchmark_height_;
136  align_buffer_page_end(src_a, kMaxTest + 1);
137  for (int i = 0; i < kMaxTest; ++i) {
138    src_a[i + 1] = i;
139  }
140  uint32 h2 = ReferenceHashDjb2(src_a + 1, kMaxTest, 5381);
141  uint32 h1;
142  for (int i = 0; i < benchmark_iterations_; ++i) {
143    h1 = HashDjb2(src_a + 1, kMaxTest, 5381);
144  }
145  EXPECT_EQ(h1, h2);
146  free_aligned_buffer_page_end(src_a);
147}
148
149TEST_F(LibYUVBaseTest, BenchmarkARGBDetect_Opt) {
150  uint32 fourcc;
151  const int kMaxTest = benchmark_width_ * benchmark_height_ * 4;
152  align_buffer_page_end(src_a, kMaxTest);
153  for (int i = 0; i < kMaxTest; ++i) {
154    src_a[i] = 255;
155  }
156
157  src_a[0] = 0;
158  fourcc = ARGBDetect(src_a, benchmark_width_ * 4,
159                      benchmark_width_, benchmark_height_);
160  EXPECT_EQ(libyuv::FOURCC_BGRA, fourcc);
161  src_a[0] = 255;
162  src_a[3] = 0;
163  fourcc = ARGBDetect(src_a, benchmark_width_ * 4,
164                      benchmark_width_, benchmark_height_);
165  EXPECT_EQ(libyuv::FOURCC_ARGB, fourcc);
166  src_a[3] = 255;
167
168  for (int i = 0; i < benchmark_iterations_; ++i) {
169    fourcc = ARGBDetect(src_a, benchmark_width_ * 4,
170                        benchmark_width_, benchmark_height_);
171  }
172  EXPECT_EQ(0, fourcc);
173
174  free_aligned_buffer_page_end(src_a);
175}
176
177TEST_F(LibYUVBaseTest, BenchmarkARGBDetect_Unaligned) {
178  uint32 fourcc;
179  const int kMaxTest = benchmark_width_ * benchmark_height_ * 4 + 1;
180  align_buffer_page_end(src_a, kMaxTest);
181  for (int i = 1; i < kMaxTest; ++i) {
182    src_a[i] = 255;
183  }
184
185  src_a[0 + 1] = 0;
186  fourcc = ARGBDetect(src_a + 1, benchmark_width_ * 4,
187                      benchmark_width_, benchmark_height_);
188  EXPECT_EQ(libyuv::FOURCC_BGRA, fourcc);
189  src_a[0 + 1] = 255;
190  src_a[3 + 1] = 0;
191  fourcc = ARGBDetect(src_a + 1, benchmark_width_ * 4,
192                      benchmark_width_, benchmark_height_);
193  EXPECT_EQ(libyuv::FOURCC_ARGB, fourcc);
194  src_a[3 + 1] = 255;
195
196  for (int i = 0; i < benchmark_iterations_; ++i) {
197    fourcc = ARGBDetect(src_a + 1, benchmark_width_ * 4,
198                        benchmark_width_, benchmark_height_);
199  }
200  EXPECT_EQ(0, fourcc);
201
202  free_aligned_buffer_page_end(src_a);
203}
204TEST_F(LibYUVBaseTest, BenchmarkSumSquareError_Opt) {
205  const int kMaxWidth = 4096 * 3;
206  align_buffer_page_end(src_a, kMaxWidth);
207  align_buffer_page_end(src_b, kMaxWidth);
208  memset(src_a, 0, kMaxWidth);
209  memset(src_b, 0, kMaxWidth);
210
211  memcpy(src_a, "test0123test4567", 16);
212  memcpy(src_b, "tick0123tock4567", 16);
213  uint64 h1 = ComputeSumSquareError(src_a, src_b, 16);
214  EXPECT_EQ(790u, h1);
215
216  for (int i = 0; i < kMaxWidth; ++i) {
217    src_a[i] = i;
218    src_b[i] = i;
219  }
220  memset(src_a, 0, kMaxWidth);
221  memset(src_b, 0, kMaxWidth);
222
223  int count = benchmark_iterations_ *
224    ((benchmark_width_ * benchmark_height_ + kMaxWidth - 1) / kMaxWidth);
225  for (int i = 0; i < count; ++i) {
226    h1 = ComputeSumSquareError(src_a, src_b, kMaxWidth);
227  }
228
229  EXPECT_EQ(0, h1);
230
231  free_aligned_buffer_page_end(src_a);
232  free_aligned_buffer_page_end(src_b);
233}
234
235TEST_F(LibYUVBaseTest, SumSquareError) {
236  const int kMaxWidth = 4096 * 3;
237  align_buffer_page_end(src_a, kMaxWidth);
238  align_buffer_page_end(src_b, kMaxWidth);
239  memset(src_a, 0, kMaxWidth);
240  memset(src_b, 0, kMaxWidth);
241
242  uint64 err;
243  err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
244
245  EXPECT_EQ(0, err);
246
247  memset(src_a, 1, kMaxWidth);
248  err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
249
250  EXPECT_EQ(err, kMaxWidth);
251
252  memset(src_a, 190, kMaxWidth);
253  memset(src_b, 193, kMaxWidth);
254  err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
255
256  EXPECT_EQ(kMaxWidth * 3 * 3, err);
257
258  for (int i = 0; i < kMaxWidth; ++i) {
259    src_a[i] = (fastrand() & 0xff);
260    src_b[i] = (fastrand() & 0xff);
261  }
262
263  MaskCpuFlags(disable_cpu_flags_);
264  uint64 c_err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
265
266  MaskCpuFlags(benchmark_cpu_info_);
267  uint64 opt_err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
268
269  EXPECT_EQ(c_err, opt_err);
270
271  free_aligned_buffer_page_end(src_a);
272  free_aligned_buffer_page_end(src_b);
273}
274
275TEST_F(LibYUVBaseTest, BenchmarkPsnr_Opt) {
276  align_buffer_page_end(src_a, benchmark_width_ * benchmark_height_);
277  align_buffer_page_end(src_b, benchmark_width_ * benchmark_height_);
278  for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
279    src_a[i] = i;
280    src_b[i] = i;
281  }
282
283  MaskCpuFlags(benchmark_cpu_info_);
284
285  double opt_time = get_time();
286  for (int i = 0; i < benchmark_iterations_; ++i)
287    CalcFramePsnr(src_a, benchmark_width_,
288                  src_b, benchmark_width_,
289                  benchmark_width_, benchmark_height_);
290
291  opt_time = (get_time() - opt_time) / benchmark_iterations_;
292  printf("BenchmarkPsnr_Opt - %8.2f us opt\n", opt_time * 1e6);
293
294  EXPECT_EQ(0, 0);
295
296  free_aligned_buffer_page_end(src_a);
297  free_aligned_buffer_page_end(src_b);
298}
299
300TEST_F(LibYUVBaseTest, BenchmarkPsnr_Unaligned) {
301  align_buffer_page_end(src_a, benchmark_width_ * benchmark_height_ + 1);
302  align_buffer_page_end(src_b, benchmark_width_ * benchmark_height_);
303  for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
304    src_a[i + 1] = i;
305    src_b[i] = i;
306  }
307
308  MaskCpuFlags(benchmark_cpu_info_);
309
310  double opt_time = get_time();
311  for (int i = 0; i < benchmark_iterations_; ++i)
312    CalcFramePsnr(src_a + 1, benchmark_width_,
313                  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,
339                      kSrcWidth, 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,
347                      kSrcWidth, 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,
355                      kSrcWidth, 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,
366                      kSrcWidth, 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,
388                        kSrcWidth, 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,
394                          kSrcWidth, 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_,
415                  src_b, benchmark_width_,
416                  benchmark_width_, benchmark_height_);
417
418  opt_time = (get_time() - opt_time) / benchmark_iterations_;
419  printf("BenchmarkSsim_Opt - %8.2f us opt\n", opt_time * 1e6);
420
421  EXPECT_EQ(0, 0);  // Pass if we get this far.
422
423  free_aligned_buffer_page_end(src_a);
424  free_aligned_buffer_page_end(src_b);
425}
426
427TEST_F(LibYUVBaseTest, Ssim) {
428  const int kSrcWidth = benchmark_width_;
429  const int kSrcHeight = benchmark_height_;
430  const int b = 128;
431  const int kSrcPlaneSize = (kSrcWidth + b * 2) * (kSrcHeight + b * 2);
432  const int kSrcStride = 2 * b + kSrcWidth;
433  align_buffer_page_end(src_a, kSrcPlaneSize);
434  align_buffer_page_end(src_b, kSrcPlaneSize);
435  memset(src_a, 0, kSrcPlaneSize);
436  memset(src_b, 0, kSrcPlaneSize);
437
438  if (kSrcWidth <=8 || kSrcHeight <= 8) {
439    printf("warning - Ssim size too small.  Testing function executes.\n");
440  }
441
442  double err;
443  err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
444                      src_b + kSrcStride * b + b, kSrcStride,
445                      kSrcWidth, kSrcHeight);
446
447  if (kSrcWidth > 8 && kSrcHeight > 8) {
448    EXPECT_EQ(err, 1.0);
449  }
450
451  memset(src_a, 255, kSrcPlaneSize);
452
453  err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
454                      src_b + kSrcStride * b + b, kSrcStride,
455                      kSrcWidth, kSrcHeight);
456
457  if (kSrcWidth > 8 && kSrcHeight > 8) {
458    EXPECT_LT(err, 0.0001);
459  }
460
461  memset(src_a, 1, kSrcPlaneSize);
462
463  err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
464                      src_b + kSrcStride * b + b, kSrcStride,
465                      kSrcWidth, kSrcHeight);
466
467  if (kSrcWidth > 8 && kSrcHeight > 8) {
468    EXPECT_GT(err, 0.0001);
469    EXPECT_LT(err, 0.9);
470  }
471
472  for (int i = 0; i < kSrcPlaneSize; ++i) {
473    src_a[i] = i;
474  }
475
476  err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
477                      src_b + kSrcStride * b + b, kSrcStride,
478                      kSrcWidth, kSrcHeight);
479
480  if (kSrcWidth > 8 && kSrcHeight > 8) {
481    EXPECT_GT(err, 0.0);
482    EXPECT_LT(err, 0.01);
483  }
484
485  for (int i = b; i < (kSrcHeight + b); ++i) {
486    for (int j = b; j < (kSrcWidth + b); ++j) {
487      src_a[(i * kSrcStride) + j] = (fastrand() & 0xff);
488      src_b[(i * kSrcStride) + j] = (fastrand() & 0xff);
489    }
490  }
491
492  MaskCpuFlags(disable_cpu_flags_);
493  double c_err, opt_err;
494
495  c_err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
496                        src_b + kSrcStride * b + b, kSrcStride,
497                        kSrcWidth, kSrcHeight);
498
499  MaskCpuFlags(benchmark_cpu_info_);
500
501  opt_err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
502                          src_b + kSrcStride * b + b, kSrcStride,
503                          kSrcWidth, kSrcHeight);
504
505  if (kSrcWidth > 8 && kSrcHeight > 8) {
506    EXPECT_EQ(opt_err, c_err);
507  }
508
509  free_aligned_buffer_page_end(src_a);
510  free_aligned_buffer_page_end(src_b);
511}
512
513}  // namespace libyuv
514