1 /* 2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved 3 * 4 * This source code is subject to the terms of the BSD 2 Clause License and 5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License 6 * was not distributed with this source code in the LICENSE file, you can 7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open 8 * Media Patent License 1.0 was not distributed with this source code in the 9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent. 10 */ 11 12 #include <math.h> 13 #include <stdlib.h> 14 #include <new> 15 16 #include "third_party/googletest/src/googletest/include/gtest/gtest.h" 17 #include "test/acm_random.h" 18 #include "test/util.h" 19 20 #include "config/aom_config.h" 21 22 #include "aom_dsp/psnr.h" 23 #include "aom_dsp/ssim.h" 24 #include "aom_ports/mem.h" 25 #include "aom_ports/msvc.h" 26 #include "aom_scale/yv12config.h" 27 28 using libaom_test::ACMRandom; 29 30 namespace { 31 32 typedef double (*LBDMetricFunc)(const YV12_BUFFER_CONFIG *source, 33 const YV12_BUFFER_CONFIG *dest); 34 typedef double (*HBDMetricFunc)(const YV12_BUFFER_CONFIG *source, 35 const YV12_BUFFER_CONFIG *dest, uint32_t in_bd, 36 uint32_t bd); 37 38 double compute_hbd_psnr(const YV12_BUFFER_CONFIG *source, 39 const YV12_BUFFER_CONFIG *dest, uint32_t in_bd, 40 uint32_t bd) { 41 PSNR_STATS psnr; 42 aom_calc_highbd_psnr(source, dest, &psnr, bd, in_bd); 43 return psnr.psnr[0]; 44 } 45 46 double compute_psnr(const YV12_BUFFER_CONFIG *source, 47 const YV12_BUFFER_CONFIG *dest) { 48 PSNR_STATS psnr; 49 aom_calc_psnr(source, dest, &psnr); 50 return psnr.psnr[0]; 51 } 52 53 double compute_hbd_psnrhvs(const YV12_BUFFER_CONFIG *source, 54 const YV12_BUFFER_CONFIG *dest, uint32_t in_bd, 55 uint32_t bd) { 56 double tempy, tempu, tempv; 57 return aom_psnrhvs(source, dest, &tempy, &tempu, &tempv, bd, in_bd); 58 } 59 60 double compute_psnrhvs(const YV12_BUFFER_CONFIG *source, 61 const YV12_BUFFER_CONFIG *dest) { 62 double tempy, tempu, tempv; 63 return aom_psnrhvs(source, dest, &tempy, &tempu, &tempv, 8, 8); 64 } 65 66 double compute_hbd_fastssim(const YV12_BUFFER_CONFIG *source, 67 const YV12_BUFFER_CONFIG *dest, uint32_t in_bd, 68 uint32_t bd) { 69 double tempy, tempu, tempv; 70 return aom_calc_fastssim(source, dest, &tempy, &tempu, &tempv, bd, in_bd); 71 } 72 73 double compute_fastssim(const YV12_BUFFER_CONFIG *source, 74 const YV12_BUFFER_CONFIG *dest) { 75 double tempy, tempu, tempv; 76 return aom_calc_fastssim(source, dest, &tempy, &tempu, &tempv, 8, 8); 77 } 78 79 double compute_hbd_aomssim(const YV12_BUFFER_CONFIG *source, 80 const YV12_BUFFER_CONFIG *dest, uint32_t in_bd, 81 uint32_t bd) { 82 double ssim, weight; 83 ssim = aom_highbd_calc_ssim(source, dest, &weight, bd, in_bd); 84 return 100 * pow(ssim / weight, 8.0); 85 } 86 87 double compute_aomssim(const YV12_BUFFER_CONFIG *source, 88 const YV12_BUFFER_CONFIG *dest) { 89 double ssim, weight; 90 ssim = aom_calc_ssim(source, dest, &weight); 91 return 100 * pow(ssim / weight, 8.0); 92 } 93 94 class HBDMetricsTestBase { 95 public: 96 virtual ~HBDMetricsTestBase() {} 97 98 protected: 99 void RunAccuracyCheck() { 100 const int width = 1920; 101 const int height = 1080; 102 size_t i = 0; 103 const uint8_t kPixFiller = 128; 104 YV12_BUFFER_CONFIG lbd_src, lbd_dst; 105 YV12_BUFFER_CONFIG hbd_src, hbd_dst; 106 ACMRandom rnd(ACMRandom::DeterministicSeed()); 107 double lbd_db, hbd_db; 108 109 memset(&lbd_src, 0, sizeof(lbd_src)); 110 memset(&lbd_dst, 0, sizeof(lbd_dst)); 111 memset(&hbd_src, 0, sizeof(hbd_src)); 112 memset(&hbd_dst, 0, sizeof(hbd_dst)); 113 114 aom_alloc_frame_buffer(&lbd_src, width, height, 1, 1, 0, 32, 16); 115 aom_alloc_frame_buffer(&lbd_dst, width, height, 1, 1, 0, 32, 16); 116 aom_alloc_frame_buffer(&hbd_src, width, height, 1, 1, 1, 32, 16); 117 aom_alloc_frame_buffer(&hbd_dst, width, height, 1, 1, 1, 32, 16); 118 119 memset(lbd_src.buffer_alloc, kPixFiller, lbd_src.buffer_alloc_sz); 120 while (i < lbd_src.buffer_alloc_sz) { 121 uint16_t spel, dpel; 122 spel = lbd_src.buffer_alloc[i]; 123 // Create some distortion for dst buffer. 124 dpel = rnd.Rand8(); 125 lbd_dst.buffer_alloc[i] = (uint8_t)dpel; 126 ((uint16_t *)(hbd_src.buffer_alloc))[i] = spel << (bit_depth_ - 8); 127 ((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8); 128 i++; 129 } 130 131 lbd_db = lbd_metric_(&lbd_src, &lbd_dst); 132 hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_); 133 EXPECT_LE(fabs(lbd_db - hbd_db), threshold_); 134 135 i = 0; 136 while (i < lbd_src.buffer_alloc_sz) { 137 uint16_t dpel; 138 // Create some small distortion for dst buffer. 139 dpel = 120 + (rnd.Rand8() >> 4); 140 lbd_dst.buffer_alloc[i] = (uint8_t)dpel; 141 ((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8); 142 i++; 143 } 144 145 lbd_db = lbd_metric_(&lbd_src, &lbd_dst); 146 hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_); 147 EXPECT_LE(fabs(lbd_db - hbd_db), threshold_); 148 149 i = 0; 150 while (i < lbd_src.buffer_alloc_sz) { 151 uint16_t dpel; 152 // Create some small distortion for dst buffer. 153 dpel = 126 + (rnd.Rand8() >> 6); 154 lbd_dst.buffer_alloc[i] = (uint8_t)dpel; 155 ((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8); 156 i++; 157 } 158 159 lbd_db = lbd_metric_(&lbd_src, &lbd_dst); 160 hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_); 161 EXPECT_LE(fabs(lbd_db - hbd_db), threshold_); 162 163 aom_free_frame_buffer(&lbd_src); 164 aom_free_frame_buffer(&lbd_dst); 165 aom_free_frame_buffer(&hbd_src); 166 aom_free_frame_buffer(&hbd_dst); 167 } 168 169 int input_bit_depth_; 170 int bit_depth_; 171 double threshold_; 172 LBDMetricFunc lbd_metric_; 173 HBDMetricFunc hbd_metric_; 174 }; 175 176 typedef ::testing::tuple<LBDMetricFunc, HBDMetricFunc, int, int, double> 177 MetricTestTParam; 178 class HBDMetricsTest : public HBDMetricsTestBase, 179 public ::testing::TestWithParam<MetricTestTParam> { 180 public: 181 virtual void SetUp() { 182 lbd_metric_ = GET_PARAM(0); 183 hbd_metric_ = GET_PARAM(1); 184 input_bit_depth_ = GET_PARAM(2); 185 bit_depth_ = GET_PARAM(3); 186 threshold_ = GET_PARAM(4); 187 } 188 virtual void TearDown() {} 189 }; 190 191 TEST_P(HBDMetricsTest, RunAccuracyCheck) { RunAccuracyCheck(); } 192 193 // Allow small variation due to floating point operations. 194 static const double kSsim_thresh = 0.001; 195 // Allow some additional errors accumulated in floating point operations. 196 static const double kFSsim_thresh = 0.03; 197 // Allow some extra variation due to rounding error accumulated in dct. 198 static const double kPhvs_thresh = 0.3; 199 200 INSTANTIATE_TEST_CASE_P( 201 AOMSSIM, HBDMetricsTest, 202 ::testing::Values(MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim, 203 8, 10, kSsim_thresh), 204 MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim, 205 10, 10, kPhvs_thresh), 206 MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim, 207 8, 12, kSsim_thresh), 208 MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim, 209 12, 12, kPhvs_thresh))); 210 INSTANTIATE_TEST_CASE_P( 211 FASTSSIM, HBDMetricsTest, 212 ::testing::Values(MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 213 8, 10, kFSsim_thresh), 214 MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 215 10, 10, kFSsim_thresh), 216 MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 217 8, 12, kFSsim_thresh), 218 MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 219 12, 12, kFSsim_thresh))); 220 INSTANTIATE_TEST_CASE_P( 221 PSNRHVS, HBDMetricsTest, 222 ::testing::Values(MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs, 223 8, 10, kPhvs_thresh), 224 MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs, 225 10, 10, kPhvs_thresh), 226 MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs, 227 8, 12, kPhvs_thresh), 228 MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs, 229 12, 12, kPhvs_thresh))); 230 INSTANTIATE_TEST_CASE_P( 231 PSNR, HBDMetricsTest, 232 ::testing::Values( 233 MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 8, 10, kPhvs_thresh), 234 MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 10, 10, 235 kPhvs_thresh), 236 MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 8, 12, kPhvs_thresh), 237 MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 12, 12, 238 kPhvs_thresh))); 239 } // namespace 240