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