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/row.h" 20 21 namespace libyuv { 22 23 // hash seed of 5381 recommended. 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 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); 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] = (random() & 0xff); 48 src_b[i] = (random() & 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_64(src_a); 115 free_aligned_buffer_64(src_b); 116 } 117 118 TEST_F(libyuvTest, BenchmarkDjb2_Opt) { 119 const int kMaxTest = benchmark_width_ * benchmark_height_; 120 align_buffer_64(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_64(src_a); 132 } 133 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) { 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_64(src_a); 147 } 148 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); 155 156 memcpy(src_a, "test0123test4567", 16); 157 memcpy(src_b, "tick0123tock4567", 16); 158 uint64 h1 = ComputeSumSquareError(src_a, src_b, 16); 159 EXPECT_EQ(790u, h1); 160 161 for (int i = 0; i < kMaxWidth; ++i) { 162 src_a[i] = i; 163 src_b[i] = i; 164 } 165 memset(src_a, 0, kMaxWidth); 166 memset(src_b, 0, kMaxWidth); 167 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); 172 } 173 174 EXPECT_EQ(0, h1); 175 176 free_aligned_buffer_64(src_a); 177 free_aligned_buffer_64(src_b); 178 } 179 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); 186 187 uint64 err; 188 err = ComputeSumSquareError(src_a, src_b, kMaxWidth); 189 190 EXPECT_EQ(0, err); 191 192 memset(src_a, 1, kMaxWidth); 193 err = ComputeSumSquareError(src_a, src_b, kMaxWidth); 194 195 EXPECT_EQ(err, kMaxWidth); 196 197 memset(src_a, 190, kMaxWidth); 198 memset(src_b, 193, kMaxWidth); 199 err = ComputeSumSquareError(src_a, src_b, kMaxWidth); 200 201 EXPECT_EQ(kMaxWidth * 3 * 3, err); 202 203 srandom(time(NULL)); 204 205 for (int i = 0; i < kMaxWidth; ++i) { 206 src_a[i] = (random() & 0xff); 207 src_b[i] = (random() & 0xff); 208 } 209 210 MaskCpuFlags(0); 211 uint64 c_err = ComputeSumSquareError(src_a, src_b, kMaxWidth); 212 213 MaskCpuFlags(-1); 214 uint64 opt_err = ComputeSumSquareError(src_a, src_b, kMaxWidth); 215 216 EXPECT_EQ(c_err, opt_err); 217 218 free_aligned_buffer_64(src_a); 219 free_aligned_buffer_64(src_b); 220 } 221 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) { 226 src_a[i] = i; 227 src_b[i] = i; 228 } 229 230 MaskCpuFlags(-1); 231 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_); 237 238 opt_time = (get_time() - opt_time) / benchmark_iterations_; 239 printf("BenchmarkPsnr_Opt - %8.2f us opt\n", opt_time * 1e6); 240 241 EXPECT_EQ(0, 0); 242 243 free_aligned_buffer_64(src_a); 244 free_aligned_buffer_64(src_b); 245 } 246 247 TEST_F(libyuvTest, Psnr) { 248 const int kSrcWidth = benchmark_width_; 249 const int kSrcHeight = benchmark_height_; 250 const int b = 128; 251 const int kSrcPlaneSize = (kSrcWidth + b * 2) * (kSrcHeight + b * 2); 252 const int kSrcStride = 2 * b + kSrcWidth; 253 align_buffer_64(src_a, kSrcPlaneSize); 254 align_buffer_64(src_b, kSrcPlaneSize); 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 286 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride, 287 src_b + kSrcStride * b + b, kSrcStride, 288 kSrcWidth, kSrcHeight); 289 290 EXPECT_GT(err, 2.0); 291 if (kSrcWidth * kSrcHeight >= 256) { 292 EXPECT_LT(err, 6.0); 293 } 294 295 srandom(time(NULL)); 296 297 memset(src_a, 0, kSrcPlaneSize); 298 memset(src_b, 0, kSrcPlaneSize); 299 300 for (int i = b; i < (kSrcHeight + b); ++i) { 301 for (int j = b; j < (kSrcWidth + b); ++j) { 302 src_a[(i * kSrcStride) + j] = (random() & 0xff); 303 src_b[(i * kSrcStride) + j] = (random() & 0xff); 304 } 305 } 306 307 MaskCpuFlags(0); 308 double c_err, opt_err; 309 310 c_err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride, 311 src_b + kSrcStride * b + b, kSrcStride, 312 kSrcWidth, kSrcHeight); 313 314 MaskCpuFlags(-1); 315 316 opt_err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride, 317 src_b + kSrcStride * b + b, kSrcStride, 318 kSrcWidth, kSrcHeight); 319 320 EXPECT_EQ(opt_err, c_err); 321 322 free_aligned_buffer_64(src_a); 323 free_aligned_buffer_64(src_b); 324 } 325 326 TEST_F(libyuvTest, DISABLED_BenchmarkSsim_Opt) { 327 align_buffer_64(src_a, benchmark_width_ * benchmark_height_); 328 align_buffer_64(src_b, benchmark_width_ * benchmark_height_); 329 for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) { 330 src_a[i] = i; 331 src_b[i] = i; 332 } 333 334 MaskCpuFlags(-1); 335 336 double opt_time = get_time(); 337 for (int i = 0; i < benchmark_iterations_; ++i) 338 CalcFrameSsim(src_a, benchmark_width_, 339 src_b, benchmark_width_, 340 benchmark_width_, benchmark_height_); 341 342 opt_time = (get_time() - opt_time) / benchmark_iterations_; 343 printf("BenchmarkSsim_Opt - %8.2f us opt\n", opt_time * 1e6); 344 345 EXPECT_EQ(0, 0); // Pass if we get this far. 346 347 free_aligned_buffer_64(src_a); 348 free_aligned_buffer_64(src_b); 349 } 350 351 TEST_F(libyuvTest, Ssim) { 352 const int kSrcWidth = benchmark_width_; 353 const int kSrcHeight = benchmark_height_; 354 const int b = 128; 355 const int kSrcPlaneSize = (kSrcWidth + b * 2) * (kSrcHeight + b * 2); 356 const int kSrcStride = 2 * b + kSrcWidth; 357 align_buffer_64(src_a, kSrcPlaneSize); 358 align_buffer_64(src_b, kSrcPlaneSize); 359 memset(src_a, 0, kSrcPlaneSize); 360 memset(src_b, 0, kSrcPlaneSize); 361 362 if (kSrcWidth <=8 || kSrcHeight <= 8) { 363 printf("warning - Ssim size too small. Testing function executes.\n"); 364 } 365 366 double err; 367 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride, 368 src_b + kSrcStride * b + b, kSrcStride, 369 kSrcWidth, kSrcHeight); 370 371 if (kSrcWidth > 8 && kSrcHeight > 8) { 372 EXPECT_EQ(err, 1.0); 373 } 374 375 memset(src_a, 255, kSrcPlaneSize); 376 377 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride, 378 src_b + kSrcStride * b + b, kSrcStride, 379 kSrcWidth, kSrcHeight); 380 381 if (kSrcWidth > 8 && kSrcHeight > 8) { 382 EXPECT_LT(err, 0.0001); 383 } 384 385 memset(src_a, 1, kSrcPlaneSize); 386 387 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride, 388 src_b + kSrcStride * b + b, kSrcStride, 389 kSrcWidth, kSrcHeight); 390 391 if (kSrcWidth > 8 && kSrcHeight > 8) { 392 EXPECT_GT(err, 0.0001); 393 EXPECT_LT(err, 0.9); 394 } 395 396 for (int i = 0; i < kSrcPlaneSize; ++i) { 397 src_a[i] = i; 398 } 399 400 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride, 401 src_b + kSrcStride * b + b, kSrcStride, 402 kSrcWidth, kSrcHeight); 403 404 if (kSrcWidth > 8 && kSrcHeight > 8) { 405 EXPECT_GT(err, 0.0); 406 EXPECT_LT(err, 0.01); 407 } 408 409 srandom(time(NULL)); 410 for (int i = b; i < (kSrcHeight + b); ++i) { 411 for (int j = b; j < (kSrcWidth + b); ++j) { 412 src_a[(i * kSrcStride) + j] = (random() & 0xff); 413 src_b[(i * kSrcStride) + j] = (random() & 0xff); 414 } 415 } 416 417 MaskCpuFlags(0); 418 double c_err, opt_err; 419 420 c_err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride, 421 src_b + kSrcStride * b + b, kSrcStride, 422 kSrcWidth, kSrcHeight); 423 424 MaskCpuFlags(-1); 425 426 opt_err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride, 427 src_b + kSrcStride * b + b, kSrcStride, 428 kSrcWidth, kSrcHeight); 429 430 if (kSrcWidth > 8 && kSrcHeight > 8) { 431 EXPECT_EQ(opt_err, c_err); 432 } 433 434 free_aligned_buffer_64(src_a); 435 free_aligned_buffer_64(src_b); 436 } 437 438 } // namespace libyuv 439