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/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