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