2 * Copyright 2011 The LibYuv Project Authors. All rights reserved.
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.
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/row.h"
23 // hash seed of 5381 recommended.
24 static uint32 ReferenceHashDjb2(const uint8* src, uint64 count, uint32 seed) {
28 hash = hash * 33 + *src++;
34 TEST_F(libyuvTest, Djb2_Test) {
35 const int kMaxTest = benchmark_width_ * benchmark_height_;
36 align_buffer_64(src_a, kMaxTest);
37 align_buffer_64(src_b, kMaxTest);
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);
46 for (int i = 0; i < kMaxTest; ++i) {
47 src_a[i] = (random() & 0xff);
48 src_b[i] = (random() & 0xff);
50 // Compare different buffers. Expect hash is different.
51 uint32 h1 = HashDjb2(src_a, kMaxTest, 5381);
52 uint32 h2 = HashDjb2(src_b, kMaxTest, 5381);
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);
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);
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);
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);
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);
88 // Make first byte different. Expect hash is different.
89 memcpy(src_a, src_b, kMaxTest);
91 h1 = HashDjb2(src_a, kMaxTest, 5381);
92 h2 = HashDjb2(src_b, kMaxTest, 5381);
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);
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);
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);
114 free_aligned_buffer_64(src_a);
115 free_aligned_buffer_64(src_b);
118 TEST_F(libyuvTest, BenchmarkDjb2_Opt) {
119 const int kMaxTest = benchmark_width_ * benchmark_height_;
120 align_buffer_64(src_a, kMaxTest);
122 for (int i = 0; i < kMaxTest; ++i) {
125 uint32 h2 = ReferenceHashDjb2(src_a, kMaxTest, 5381);
127 for (int i = 0; i < benchmark_iterations_; ++i) {
128 h1 = HashDjb2(src_a, kMaxTest, 5381);
131 free_aligned_buffer_64(src_a);
134 TEST_F(libyuvTest, BenchmarkDjb2_Unaligned) {
135 const int kMaxTest = benchmark_width_ * benchmark_height_;
136 align_buffer_64(src_a, kMaxTest + 1);
137 for (int i = 0; i < kMaxTest; ++i) {
140 uint32 h2 = ReferenceHashDjb2(src_a + 1, kMaxTest, 5381);
142 for (int i = 0; i < benchmark_iterations_; ++i) {
143 h1 = HashDjb2(src_a + 1, kMaxTest, 5381);
146 free_aligned_buffer_64(src_a);
149 TEST_F(libyuvTest, BenchmarkSumSquareError_Opt) {
150 const int kMaxWidth = 4096 * 3;
151 align_buffer_64(src_a, kMaxWidth);
152 align_buffer_64(src_b, kMaxWidth);
153 memset(src_a, 0, kMaxWidth);
154 memset(src_b, 0, kMaxWidth);
156 memcpy(src_a, "test0123test4567", 16);
157 memcpy(src_b, "tick0123tock4567", 16);
158 uint64 h1 = ComputeSumSquareError(src_a, src_b, 16);
161 for (int i = 0; i < kMaxWidth; ++i) {
165 memset(src_a, 0, kMaxWidth);
166 memset(src_b, 0, kMaxWidth);
168 int count = benchmark_iterations_ *
169 ((benchmark_width_ * benchmark_height_ + kMaxWidth - 1) / kMaxWidth);
170 for (int i = 0; i < count; ++i) {
171 h1 = ComputeSumSquareError(src_a, src_b, kMaxWidth);
176 free_aligned_buffer_64(src_a);
177 free_aligned_buffer_64(src_b);
180 TEST_F(libyuvTest, SumSquareError) {
181 const int kMaxWidth = 4096 * 3;
182 align_buffer_64(src_a, kMaxWidth);
183 align_buffer_64(src_b, kMaxWidth);
184 memset(src_a, 0, kMaxWidth);
185 memset(src_b, 0, kMaxWidth);
188 err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
192 memset(src_a, 1, kMaxWidth);
193 err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
195 EXPECT_EQ(err, kMaxWidth);
197 memset(src_a, 190, kMaxWidth);
198 memset(src_b, 193, kMaxWidth);
199 err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
201 EXPECT_EQ(kMaxWidth * 3 * 3, err);
205 for (int i = 0; i < kMaxWidth; ++i) {
206 src_a[i] = (random() & 0xff);
207 src_b[i] = (random() & 0xff);
211 uint64 c_err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
214 uint64 opt_err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
216 EXPECT_EQ(c_err, opt_err);
218 free_aligned_buffer_64(src_a);
219 free_aligned_buffer_64(src_b);
222 TEST_F(libyuvTest, BenchmarkPsnr_Opt) {
223 align_buffer_64(src_a, benchmark_width_ * benchmark_height_);
224 align_buffer_64(src_b, benchmark_width_ * benchmark_height_);
225 for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
232 double opt_time = get_time();
233 for (int i = 0; i < benchmark_iterations_; ++i)
234 CalcFramePsnr(src_a, benchmark_width_,
235 src_b, benchmark_width_,
236 benchmark_width_, benchmark_height_);
238 opt_time = (get_time() - opt_time) / benchmark_iterations_;
239 printf("BenchmarkPsnr_Opt - %8.2f us opt\n", opt_time * 1e6);
243 free_aligned_buffer_64(src_a);
244 free_aligned_buffer_64(src_b);
248 TEST_F(libyuvTest, BenchmarkPsnr_Unaligned) {
249 align_buffer_64(src_a, benchmark_width_ * benchmark_height_ + 1);
250 align_buffer_64(src_b, benchmark_width_ * benchmark_height_);
251 for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
258 double opt_time = get_time();
259 for (int i = 0; i < benchmark_iterations_; ++i)
260 CalcFramePsnr(src_a + 1, benchmark_width_,
261 src_b, benchmark_width_,
262 benchmark_width_, benchmark_height_);
264 opt_time = (get_time() - opt_time) / benchmark_iterations_;
265 printf("BenchmarkPsnr_Opt - %8.2f us opt\n", opt_time * 1e6);
269 free_aligned_buffer_64(src_a);
270 free_aligned_buffer_64(src_b);
273 TEST_F(libyuvTest, Psnr) {
274 const int kSrcWidth = benchmark_width_;
275 const int kSrcHeight = benchmark_height_;
277 const int kSrcPlaneSize = (kSrcWidth + b * 2) * (kSrcHeight + b * 2);
278 const int kSrcStride = 2 * b + kSrcWidth;
279 align_buffer_64(src_a, kSrcPlaneSize);
280 align_buffer_64(src_b, kSrcPlaneSize);
281 memset(src_a, 0, kSrcPlaneSize);
282 memset(src_b, 0, kSrcPlaneSize);
285 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
286 src_b + kSrcStride * b + b, kSrcStride,
287 kSrcWidth, kSrcHeight);
289 EXPECT_EQ(err, kMaxPsnr);
291 memset(src_a, 255, kSrcPlaneSize);
293 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
294 src_b + kSrcStride * b + b, kSrcStride,
295 kSrcWidth, kSrcHeight);
299 memset(src_a, 1, kSrcPlaneSize);
301 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
302 src_b + kSrcStride * b + b, kSrcStride,
303 kSrcWidth, kSrcHeight);
305 EXPECT_GT(err, 48.0);
306 EXPECT_LT(err, 49.0);
308 for (int i = 0; i < kSrcPlaneSize; ++i) {
312 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
313 src_b + kSrcStride * b + b, kSrcStride,
314 kSrcWidth, kSrcHeight);
317 if (kSrcWidth * kSrcHeight >= 256) {
323 memset(src_a, 0, kSrcPlaneSize);
324 memset(src_b, 0, kSrcPlaneSize);
326 for (int i = b; i < (kSrcHeight + b); ++i) {
327 for (int j = b; j < (kSrcWidth + b); ++j) {
328 src_a[(i * kSrcStride) + j] = (random() & 0xff);
329 src_b[(i * kSrcStride) + j] = (random() & 0xff);
334 double c_err, opt_err;
336 c_err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
337 src_b + kSrcStride * b + b, kSrcStride,
338 kSrcWidth, kSrcHeight);
342 opt_err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
343 src_b + kSrcStride * b + b, kSrcStride,
344 kSrcWidth, kSrcHeight);
346 EXPECT_EQ(opt_err, c_err);
348 free_aligned_buffer_64(src_a);
349 free_aligned_buffer_64(src_b);
352 TEST_F(libyuvTest, DISABLED_BenchmarkSsim_Opt) {
353 align_buffer_64(src_a, benchmark_width_ * benchmark_height_);
354 align_buffer_64(src_b, benchmark_width_ * benchmark_height_);
355 for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
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_);
368 opt_time = (get_time() - opt_time) / benchmark_iterations_;
369 printf("BenchmarkSsim_Opt - %8.2f us opt\n", opt_time * 1e6);
371 EXPECT_EQ(0, 0); // Pass if we get this far.
373 free_aligned_buffer_64(src_a);
374 free_aligned_buffer_64(src_b);
377 TEST_F(libyuvTest, Ssim) {
378 const int kSrcWidth = benchmark_width_;
379 const int kSrcHeight = benchmark_height_;
381 const int kSrcPlaneSize = (kSrcWidth + b * 2) * (kSrcHeight + b * 2);
382 const int kSrcStride = 2 * b + kSrcWidth;
383 align_buffer_64(src_a, kSrcPlaneSize);
384 align_buffer_64(src_b, kSrcPlaneSize);
385 memset(src_a, 0, kSrcPlaneSize);
386 memset(src_b, 0, kSrcPlaneSize);
388 if (kSrcWidth <=8 || kSrcHeight <= 8) {
389 printf("warning - Ssim size too small. Testing function executes.\n");
393 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
394 src_b + kSrcStride * b + b, kSrcStride,
395 kSrcWidth, kSrcHeight);
397 if (kSrcWidth > 8 && kSrcHeight > 8) {
401 memset(src_a, 255, kSrcPlaneSize);
403 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
404 src_b + kSrcStride * b + b, kSrcStride,
405 kSrcWidth, kSrcHeight);
407 if (kSrcWidth > 8 && kSrcHeight > 8) {
408 EXPECT_LT(err, 0.0001);
411 memset(src_a, 1, kSrcPlaneSize);
413 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
414 src_b + kSrcStride * b + b, kSrcStride,
415 kSrcWidth, kSrcHeight);
417 if (kSrcWidth > 8 && kSrcHeight > 8) {
418 EXPECT_GT(err, 0.0001);
422 for (int i = 0; i < kSrcPlaneSize; ++i) {
426 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
427 src_b + kSrcStride * b + b, kSrcStride,
428 kSrcWidth, kSrcHeight);
430 if (kSrcWidth > 8 && kSrcHeight > 8) {
432 EXPECT_LT(err, 0.01);
436 for (int i = b; i < (kSrcHeight + b); ++i) {
437 for (int j = b; j < (kSrcWidth + b); ++j) {
438 src_a[(i * kSrcStride) + j] = (random() & 0xff);
439 src_b[(i * kSrcStride) + j] = (random() & 0xff);
444 double c_err, opt_err;
446 c_err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
447 src_b + kSrcStride * b + b, kSrcStride,
448 kSrcWidth, kSrcHeight);
452 opt_err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
453 src_b + kSrcStride * b + b, kSrcStride,
454 kSrcWidth, kSrcHeight);
456 if (kSrcWidth > 8 && kSrcHeight > 8) {
457 EXPECT_EQ(opt_err, c_err);
460 free_aligned_buffer_64(src_a);
461 free_aligned_buffer_64(src_b);
464 } // namespace libyuv