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
20namespace libyuv {
21
22// hash seed of 5381 recommended.
23static uint32 ReferenceHashDjb2(const uint8* src, uint64 count, uint32 seed) {
24  uint32 hash = seed;
25  if (count > 0) {
26    do {
27      hash = hash * 33 + *src++;
28    } while (--count);
29  }
30  return hash;
31}
32
33TEST_F(libyuvTest, TestDjb2) {
34  const int kMaxTest = 2049;
35  align_buffer_16(src_a, kMaxTest)
36
37  for (int i = 0; i < kMaxTest; ++i) {
38    src_a[i] = i;
39  }
40  for (int i = 0; i < kMaxTest; ++i) {
41    uint32 h1 = HashDjb2(src_a, kMaxTest, 5381);
42    uint32 h2 = ReferenceHashDjb2(src_a, kMaxTest, 5381);
43    EXPECT_EQ(h1, h2);
44  }
45  // Hash constant generator using for tables in compare
46  int h = 1;
47  for (int i = 0; i <= 16 ; ++i) {
48    printf("%08x ", h);
49    h *= 33;
50  }
51  printf("\n");
52
53  free_aligned_buffer_16(src_a)
54}
55
56TEST_F(libyuvTest, BenchmakDjb2_C) {
57  const int kMaxTest = 1280 * 720;
58  align_buffer_16(src_a, kMaxTest)
59
60  for (int i = 0; i < kMaxTest; ++i) {
61    src_a[i] = i;
62  }
63  uint32 h2 = ReferenceHashDjb2(src_a, kMaxTest, 5381);
64  uint32 h1;
65  MaskCpuFlags(kCpuInitialized);
66  for (int i = 0; i < benchmark_iterations_; ++i) {
67    h1 = HashDjb2(src_a, kMaxTest, 5381);
68  }
69  MaskCpuFlags(-1);
70  EXPECT_EQ(h1, h2);
71  free_aligned_buffer_16(src_a)
72}
73
74TEST_F(libyuvTest, BenchmakDjb2_OPT) {
75  const int kMaxTest = 1280 * 720;
76  align_buffer_16(src_a, kMaxTest)
77
78  for (int i = 0; i < kMaxTest; ++i) {
79    src_a[i] = i;
80  }
81  uint32 h2 = ReferenceHashDjb2(src_a, kMaxTest, 5381);
82  uint32 h1;
83  for (int i = 0; i < benchmark_iterations_; ++i) {
84    h1 = HashDjb2(src_a, kMaxTest, 5381);
85  }
86  EXPECT_EQ(h1, h2);
87  free_aligned_buffer_16(src_a)
88}
89
90TEST_F(libyuvTest, BenchmakDjb2_Unaligned_OPT) {
91  const int kMaxTest = 1280 * 720;
92  align_buffer_16(src_a, kMaxTest + 1)
93
94  for (int i = 0; i < kMaxTest; ++i) {
95    src_a[i + 1] = i;
96  }
97  uint32 h2 = ReferenceHashDjb2(src_a + 1, kMaxTest, 5381);
98  uint32 h1;
99  for (int i = 0; i < benchmark_iterations_; ++i) {
100    h1 = HashDjb2(src_a + 1, kMaxTest, 5381);
101  }
102  EXPECT_EQ(h1, h2);
103  free_aligned_buffer_16(src_a)
104}
105
106TEST_F(libyuvTest, BenchmarkSumSquareError_C) {
107  const int kMaxWidth = 4096 * 3;
108  align_buffer_16(src_a, kMaxWidth)
109  align_buffer_16(src_b, kMaxWidth)
110
111  for (int i = 0; i < kMaxWidth; ++i) {
112    src_a[i] = i;
113    src_b[i] = i;
114  }
115
116  MaskCpuFlags(kCpuInitialized);
117  for (int i = 0; i < benchmark_iterations_; ++i) {
118    ComputeSumSquareError(src_a, src_b, kMaxWidth);
119  }
120
121  MaskCpuFlags(-1);
122
123  EXPECT_EQ(0, 0);
124
125  free_aligned_buffer_16(src_a)
126  free_aligned_buffer_16(src_b)
127}
128
129TEST_F(libyuvTest, BenchmarkSumSquareError_OPT) {
130  const int kMaxWidth = 4096 * 3;
131  align_buffer_16(src_a, kMaxWidth)
132  align_buffer_16(src_b, kMaxWidth)
133
134  for (int i = 0; i < kMaxWidth; ++i) {
135    src_a[i] = i;
136    src_b[i] = i;
137  }
138
139  for (int i = 0; i < benchmark_iterations_; ++i) {
140    ComputeSumSquareError(src_a, src_b, kMaxWidth);
141  }
142
143  EXPECT_EQ(0, 0);
144
145  free_aligned_buffer_16(src_a)
146  free_aligned_buffer_16(src_b)
147}
148
149TEST_F(libyuvTest, SumSquareError) {
150  const int kMaxWidth = 4096 * 3;
151  align_buffer_16(src_a, kMaxWidth)
152  align_buffer_16(src_b, kMaxWidth)
153
154  memset(src_a, 0, kMaxWidth);
155  memset(src_b, 0, kMaxWidth);
156
157  uint64 err;
158  err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
159
160  EXPECT_EQ(err, 0);
161
162  memset(src_a, 1, kMaxWidth);
163  err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
164
165  EXPECT_EQ(err, kMaxWidth);
166
167  memset(src_a, 190, kMaxWidth);
168  memset(src_b, 193, kMaxWidth);
169  err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
170
171  EXPECT_EQ(err, (kMaxWidth * 3 * 3));
172
173  srandom(time(NULL));
174
175  for (int i = 0; i < kMaxWidth; ++i) {
176    src_a[i] = (random() & 0xff);
177    src_b[i] = (random() & 0xff);
178  }
179
180  MaskCpuFlags(kCpuInitialized);
181  uint64 c_err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
182
183  MaskCpuFlags(-1);
184  uint64 opt_err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
185
186  EXPECT_EQ(c_err, opt_err);
187
188  free_aligned_buffer_16(src_a)
189  free_aligned_buffer_16(src_b)
190}
191
192TEST_F(libyuvTest, BenchmarkPsnr_C) {
193  align_buffer_16(src_a, benchmark_width_ * benchmark_height_)
194  align_buffer_16(src_b, benchmark_width_ * benchmark_height_)
195
196  for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
197    src_a[i] = i;
198    src_b[i] = i;
199  }
200
201  MaskCpuFlags(kCpuInitialized);
202
203  double c_time = get_time();
204  for (int i = 0; i < benchmark_iterations_; ++i)
205    CalcFramePsnr(src_a, benchmark_width_,
206                  src_b, benchmark_width_,
207                  benchmark_width_, benchmark_height_);
208
209  c_time = (get_time() - c_time) / benchmark_iterations_;
210  printf("BenchmarkPsnr_C - %8.2f us c\n", c_time * 1e6);
211
212  MaskCpuFlags(-1);
213
214  EXPECT_EQ(0, 0);
215
216  free_aligned_buffer_16(src_a)
217  free_aligned_buffer_16(src_b)
218}
219
220TEST_F(libyuvTest, BenchmarkPsnr_OPT) {
221  align_buffer_16(src_a, benchmark_width_ * benchmark_height_)
222  align_buffer_16(src_b, benchmark_width_ * benchmark_height_)
223
224  for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
225    src_a[i] = i;
226    src_b[i] = i;
227  }
228
229  MaskCpuFlags(-1);
230
231  double opt_time = get_time();
232  for (int i = 0; i < benchmark_iterations_; ++i)
233    CalcFramePsnr(src_a, benchmark_width_,
234                  src_b, benchmark_width_,
235                  benchmark_width_, benchmark_height_);
236
237  opt_time = (get_time() - opt_time) / benchmark_iterations_;
238  printf("BenchmarkPsnr_OPT - %8.2f us opt\n", opt_time * 1e6);
239
240  EXPECT_EQ(0, 0);
241
242  free_aligned_buffer_16(src_a)
243  free_aligned_buffer_16(src_b)
244}
245
246TEST_F(libyuvTest, Psnr) {
247  const int kSrcWidth = 1280;
248  const int kSrcHeight = 720;
249  const int b = 128;
250  const int kSrcPlaneSize = (kSrcWidth + b * 2) * (kSrcHeight + b * 2);
251  const int kSrcStride = 2 * b + kSrcWidth;
252  align_buffer_16(src_a, kSrcPlaneSize)
253  align_buffer_16(src_b, kSrcPlaneSize)
254
255  memset(src_a, 0, kSrcPlaneSize);
256  memset(src_b, 0, kSrcPlaneSize);
257
258  double err;
259  err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
260                      src_b + kSrcStride * b + b, kSrcStride,
261                      kSrcWidth, kSrcHeight);
262
263  EXPECT_EQ(err, kMaxPsnr);
264
265  memset(src_a, 255, kSrcPlaneSize);
266
267  err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
268                      src_b + kSrcStride * b + b, kSrcStride,
269                      kSrcWidth, kSrcHeight);
270
271  EXPECT_EQ(err, 0.0);
272
273  memset(src_a, 1, kSrcPlaneSize);
274
275  err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
276                      src_b + kSrcStride * b + b, kSrcStride,
277                      kSrcWidth, kSrcHeight);
278
279  EXPECT_GT(err, 48.0);
280  EXPECT_LT(err, 49.0);
281
282  for (int i = 0; i < kSrcPlaneSize; ++i)
283    src_a[i] = i;
284
285  err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
286                      src_b + kSrcStride * b + b, kSrcStride,
287                      kSrcWidth, kSrcHeight);
288
289  EXPECT_GT(err, 4.0);
290  EXPECT_LT(err, 5.0);
291
292  srandom(time(NULL));
293
294  memset(src_a, 0, kSrcPlaneSize);
295  memset(src_b, 0, kSrcPlaneSize);
296
297  for (int i = b; i < (kSrcHeight + b); ++i) {
298    for (int j = b; j < (kSrcWidth + b); ++j) {
299      src_a[(i * kSrcStride) + j] = (random() & 0xff);
300      src_b[(i * kSrcStride) + j] = (random() & 0xff);
301    }
302  }
303
304  MaskCpuFlags(kCpuInitialized);
305  double c_err, opt_err;
306
307  c_err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
308                        src_b + kSrcStride * b + b, kSrcStride,
309                        kSrcWidth, kSrcHeight);
310
311  MaskCpuFlags(-1);
312
313  opt_err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
314                          src_b + kSrcStride * b + b, kSrcStride,
315                          kSrcWidth, kSrcHeight);
316
317  EXPECT_EQ(opt_err, c_err);
318
319  free_aligned_buffer_16(src_a)
320  free_aligned_buffer_16(src_b)
321}
322
323TEST_F(libyuvTest, BenchmarkSsim_C) {
324  align_buffer_16(src_a, benchmark_width_ * benchmark_height_)
325  align_buffer_16(src_b, benchmark_width_ * benchmark_height_)
326
327  for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
328    src_a[i] = i;
329    src_b[i] = i;
330  }
331
332  MaskCpuFlags(kCpuInitialized);
333
334  double c_time = get_time();
335  for (int i = 0; i < benchmark_iterations_; ++i)
336    CalcFrameSsim(src_a, benchmark_width_,
337                  src_b, benchmark_width_,
338                  benchmark_width_, benchmark_height_);
339
340  c_time = (get_time() - c_time) / benchmark_iterations_;
341  printf("BenchmarkSsim_C - %8.2f us c\n", c_time * 1e6);
342
343  MaskCpuFlags(-1);
344
345  EXPECT_EQ(0, 0);
346
347  free_aligned_buffer_16(src_a)
348  free_aligned_buffer_16(src_b)
349}
350
351TEST_F(libyuvTest, BenchmarkSsim_OPT) {
352  align_buffer_16(src_a, benchmark_width_ * benchmark_height_)
353  align_buffer_16(src_b, benchmark_width_ * benchmark_height_)
354
355  for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
356    src_a[i] = i;
357    src_b[i] = i;
358  }
359
360  MaskCpuFlags(-1);
361
362  double opt_time = get_time();
363  for (int i = 0; i < benchmark_iterations_; ++i)
364    CalcFrameSsim(src_a, benchmark_width_,
365                  src_b, benchmark_width_,
366                  benchmark_width_, benchmark_height_);
367
368  opt_time = (get_time() - opt_time) / benchmark_iterations_;
369  printf("BenchmarkPsnr_OPT - %8.2f us opt\n", opt_time * 1e6);
370
371  EXPECT_EQ(0, 0);
372
373  free_aligned_buffer_16(src_a)
374  free_aligned_buffer_16(src_b)
375}
376
377TEST_F(libyuvTest, Ssim) {
378  const int kSrcWidth = 1280;
379  const int kSrcHeight = 720;
380  const int b = 128;
381  const int kSrcPlaneSize = (kSrcWidth + b * 2) * (kSrcHeight + b * 2);
382  const int kSrcStride = 2 * b + kSrcWidth;
383  align_buffer_16(src_a, kSrcPlaneSize)
384  align_buffer_16(src_b, kSrcPlaneSize)
385
386  memset(src_a, 0, kSrcPlaneSize);
387  memset(src_b, 0, kSrcPlaneSize);
388
389  double err;
390  err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
391                      src_b + kSrcStride * b + b, kSrcStride,
392                      kSrcWidth, kSrcHeight);
393
394  EXPECT_EQ(err, 1.0);
395
396  memset(src_a, 255, kSrcPlaneSize);
397
398  err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
399                      src_b + kSrcStride * b + b, kSrcStride,
400                      kSrcWidth, kSrcHeight);
401
402  EXPECT_LT(err, 0.0001);
403
404  memset(src_a, 1, kSrcPlaneSize);
405
406  err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
407                      src_b + kSrcStride * b + b, kSrcStride,
408                      kSrcWidth, kSrcHeight);
409
410  EXPECT_GT(err, 0.8);
411  EXPECT_LT(err, 0.9);
412
413  for (int i = 0; i < kSrcPlaneSize; ++i)
414    src_a[i] = i;
415
416  err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
417                      src_b + kSrcStride * b + b, kSrcStride,
418                      kSrcWidth, kSrcHeight);
419
420  EXPECT_GT(err, 0.008);
421  EXPECT_LT(err, 0.009);
422
423  srandom(time(NULL));
424  for (int i = b; i < (kSrcHeight + b); ++i) {
425    for (int j = b; j < (kSrcWidth + b); ++j) {
426      src_a[(i * kSrcStride) + j] = (random() & 0xff);
427      src_b[(i * kSrcStride) + j] = (random() & 0xff);
428    }
429  }
430
431  MaskCpuFlags(kCpuInitialized);
432  double c_err, opt_err;
433
434  c_err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
435                        src_b + kSrcStride * b + b, kSrcStride,
436                        kSrcWidth, kSrcHeight);
437
438  MaskCpuFlags(-1);
439
440  opt_err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
441                          src_b + kSrcStride * b + b, kSrcStride,
442                          kSrcWidth, kSrcHeight);
443
444  EXPECT_EQ(opt_err, c_err);
445
446  free_aligned_buffer_16(src_a)
447  free_aligned_buffer_16(src_b)
448}
449
450}  // namespace libyuv
451