Home | History | Annotate | Download | only in unit_test
      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 
     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(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 
    119 TEST_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 
    135 TEST_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 
    150 TEST_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 
    178 TEST_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 }
    205 TEST_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 
    237 TEST_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 
    277 TEST_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 
    301 TEST_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 
    325 TEST_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 
    402 TEST_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 
    426 TEST_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