Alex Converse | 9ffcb46 | 2015-12-16 11:16:32 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2015 The WebM 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 <assert.h> |
| 12 | #include <math.h> |
| 13 | #include <stdio.h> |
| 14 | #include <ctime> |
| 15 | #include <utility> |
| 16 | #include <vector> |
| 17 | |
| 18 | #include "third_party/googletest/src/include/gtest/gtest.h" |
| 19 | |
| 20 | #include "test/acm_random.h" |
| 21 | #include "vp10/common/ans.h" |
| 22 | #include "vp10/encoder/treewriter.h" |
| 23 | #include "vpx_dsp/bitreader.h" |
| 24 | #include "vpx_dsp/bitwriter.h" |
| 25 | |
| 26 | namespace { |
| 27 | typedef std::vector<std::pair<uint8_t, bool> > PvVec; |
| 28 | |
| 29 | PvVec abs_encode_build_vals(int iters) { |
| 30 | PvVec ret; |
| 31 | libvpx_test::ACMRandom gen(0x30317076); |
| 32 | double entropy = 0; |
| 33 | for (int i = 0; i < iters; ++i) { |
| 34 | uint8_t p; |
| 35 | do { |
| 36 | p = gen.Rand8(); |
| 37 | } while (p == 0); // zero is not a valid coding probability |
| 38 | bool b = gen.Rand8() < p; |
| 39 | ret.push_back(std::make_pair(static_cast<uint8_t>(p), b)); |
| 40 | double d = p / 256.; |
| 41 | entropy += -d * log2(d) - (1 - d) * log2(1 - d); |
| 42 | } |
| 43 | printf("entropy %f\n", entropy); |
| 44 | return ret; |
| 45 | } |
| 46 | |
| 47 | bool check_rabs(const PvVec &pv_vec, uint8_t *buf) { |
| 48 | AnsCoder a; |
| 49 | ans_write_init(&a, buf); |
| 50 | |
| 51 | std::clock_t start = std::clock(); |
| 52 | for (PvVec::const_reverse_iterator it = pv_vec.rbegin(); it != pv_vec.rend(); |
| 53 | ++it) { |
| 54 | rabs_write(&a, it->second, 256 - it->first); |
| 55 | } |
| 56 | std::clock_t enc_time = std::clock() - start; |
| 57 | int offset = ans_write_end(&a); |
| 58 | bool okay = true; |
| 59 | AnsDecoder d; |
| 60 | if (ans_read_init(&d, buf, offset)) return false; |
| 61 | start = std::clock(); |
| 62 | for (PvVec::const_iterator it = pv_vec.begin(); it != pv_vec.end(); ++it) { |
| 63 | okay &= rabs_read(&d, 256 - it->first) == it->second; |
| 64 | } |
| 65 | std::clock_t dec_time = std::clock() - start; |
| 66 | if (!okay) return false; |
| 67 | printf("rABS size %d enc_time %f dec_time %f\n", offset, |
| 68 | static_cast<float>(enc_time) / CLOCKS_PER_SEC, |
| 69 | static_cast<float>(dec_time) / CLOCKS_PER_SEC); |
| 70 | return ans_read_end(&d); |
| 71 | } |
| 72 | |
| 73 | bool check_rabs_asc(const PvVec &pv_vec, uint8_t *buf) { |
| 74 | AnsCoder a; |
| 75 | ans_write_init(&a, buf); |
| 76 | |
| 77 | std::clock_t start = std::clock(); |
| 78 | for (PvVec::const_reverse_iterator it = pv_vec.rbegin(); it != pv_vec.rend(); |
| 79 | ++it) { |
| 80 | rabs_asc_write(&a, it->second, 256 - it->first); |
| 81 | } |
| 82 | std::clock_t enc_time = std::clock() - start; |
| 83 | int offset = ans_write_end(&a); |
| 84 | bool okay = true; |
| 85 | AnsDecoder d; |
| 86 | if (ans_read_init(&d, buf, offset)) return false; |
| 87 | start = std::clock(); |
| 88 | for (PvVec::const_iterator it = pv_vec.begin(); it != pv_vec.end(); ++it) { |
| 89 | okay &= rabs_asc_read(&d, 256 - it->first) == it->second; |
| 90 | } |
| 91 | std::clock_t dec_time = std::clock() - start; |
| 92 | if (!okay) return false; |
| 93 | printf("rABS (asc) size %d enc_time %f dec_time %f\n", offset, |
| 94 | static_cast<float>(enc_time) / CLOCKS_PER_SEC, |
| 95 | static_cast<float>(dec_time) / CLOCKS_PER_SEC); |
| 96 | return ans_read_end(&d); |
| 97 | } |
| 98 | |
| 99 | bool check_uabs(const PvVec &pv_vec, uint8_t *buf) { |
| 100 | AnsCoder a; |
| 101 | ans_write_init(&a, buf); |
| 102 | |
| 103 | std::clock_t start = std::clock(); |
| 104 | for (PvVec::const_reverse_iterator it = pv_vec.rbegin(); it != pv_vec.rend(); |
| 105 | ++it) { |
| 106 | uabs_write(&a, it->second, 256 - it->first); |
| 107 | } |
| 108 | std::clock_t enc_time = std::clock() - start; |
| 109 | int offset = ans_write_end(&a); |
| 110 | bool okay = true; |
| 111 | AnsDecoder d; |
| 112 | if (ans_read_init(&d, buf, offset)) return false; |
| 113 | start = std::clock(); |
| 114 | for (PvVec::const_iterator it = pv_vec.begin(); it != pv_vec.end(); ++it) { |
| 115 | okay &= uabs_read(&d, 256 - it->first) == it->second; |
| 116 | } |
| 117 | std::clock_t dec_time = std::clock() - start; |
| 118 | if (!okay) return false; |
| 119 | printf("uABS size %d enc_time %f dec_time %f\n", offset, |
| 120 | static_cast<float>(enc_time) / CLOCKS_PER_SEC, |
| 121 | static_cast<float>(dec_time) / CLOCKS_PER_SEC); |
| 122 | return ans_read_end(&d); |
| 123 | } |
| 124 | |
| 125 | bool check_vpxbool(const PvVec &pv_vec, uint8_t *buf) { |
| 126 | vpx_writer w; |
| 127 | vpx_reader r; |
| 128 | vpx_start_encode(&w, buf); |
| 129 | |
| 130 | std::clock_t start = std::clock(); |
| 131 | for (PvVec::const_iterator it = pv_vec.begin(); it != pv_vec.end(); ++it) { |
| 132 | vpx_write(&w, it->second, 256 - it->first); |
| 133 | } |
| 134 | std::clock_t enc_time = std::clock() - start; |
| 135 | vpx_stop_encode(&w); |
| 136 | bool okay = true; |
| 137 | vpx_reader_init(&r, buf, w.pos, NULL, NULL); |
| 138 | start = std::clock(); |
| 139 | for (PvVec::const_iterator it = pv_vec.begin(); it != pv_vec.end(); ++it) { |
| 140 | okay &= vpx_read(&r, 256 - it->first) == it->second; |
| 141 | } |
| 142 | std::clock_t dec_time = std::clock() - start; |
| 143 | printf("VPX size %d enc_time %f dec_time %f\n", w.pos, |
| 144 | static_cast<float>(enc_time) / CLOCKS_PER_SEC, |
| 145 | static_cast<float>(dec_time) / CLOCKS_PER_SEC); |
| 146 | return okay; |
| 147 | } |
| 148 | |
| 149 | const rans_sym rans_sym_tab[] = { |
Alex Converse | 6bbbe31 | 2016-02-16 13:41:01 -0800 | [diff] [blame] | 150 | {16, 0}, {100, 16}, {70, 116}, {70, 186}, |
Alex Converse | 9ffcb46 | 2015-12-16 11:16:32 -0800 | [diff] [blame] | 151 | }; |
| 152 | const int kDistinctSyms = sizeof(rans_sym_tab) / sizeof(rans_sym_tab[0]); |
| 153 | |
| 154 | std::vector<int> ans_encode_build_vals(const rans_sym *tab, int iters) { |
| 155 | std::vector<int> p_to_sym; |
| 156 | int i = 0; |
| 157 | while (p_to_sym.size() < 256) { |
| 158 | p_to_sym.insert(p_to_sym.end(), tab[i].prob, i); |
| 159 | ++i; |
| 160 | } |
| 161 | assert(p_to_sym.size() == 256); |
| 162 | std::vector<int> ret; |
| 163 | libvpx_test::ACMRandom gen(18543637); |
| 164 | for (int i = 0; i < iters; ++i) { |
| 165 | int sym = p_to_sym[gen.Rand8()]; |
| 166 | ret.push_back(sym); |
| 167 | } |
| 168 | return ret; |
| 169 | } |
| 170 | |
| 171 | void rans_build_dec_tab(const struct rans_sym sym_tab[], |
| 172 | rans_dec_lut dec_tab) { |
Alex Converse | 6bbbe31 | 2016-02-16 13:41:01 -0800 | [diff] [blame] | 173 | dec_tab[0] = 0; |
| 174 | for (int i = 1; dec_tab[i - 1] < ans_p8_precision; ++i) { |
| 175 | dec_tab[i] = dec_tab[i - 1] + sym_tab[i - 1].prob; |
Alex Converse | 9ffcb46 | 2015-12-16 11:16:32 -0800 | [diff] [blame] | 176 | } |
| 177 | } |
| 178 | |
| 179 | bool check_rans(const std::vector<int> &sym_vec, const rans_sym *const tab, |
| 180 | uint8_t *buf) { |
| 181 | AnsCoder a; |
| 182 | ans_write_init(&a, buf); |
| 183 | rans_dec_lut dec_tab; |
| 184 | rans_build_dec_tab(tab, dec_tab); |
| 185 | |
| 186 | std::clock_t start = std::clock(); |
| 187 | for (std::vector<int>::const_reverse_iterator it = sym_vec.rbegin(); |
| 188 | it != sym_vec.rend(); ++it) { |
| 189 | rans_write(&a, &tab[*it]); |
| 190 | } |
| 191 | std::clock_t enc_time = std::clock() - start; |
| 192 | int offset = ans_write_end(&a); |
| 193 | bool okay = true; |
| 194 | AnsDecoder d; |
| 195 | if (ans_read_init(&d, buf, offset)) return false; |
| 196 | start = std::clock(); |
| 197 | for (std::vector<int>::const_iterator it = sym_vec.begin(); |
| 198 | it != sym_vec.end(); ++it) { |
| 199 | okay &= rans_read(&d, dec_tab) == *it; |
| 200 | } |
| 201 | std::clock_t dec_time = std::clock() - start; |
| 202 | if (!okay) return false; |
| 203 | printf("rANS size %d enc_time %f dec_time %f\n", offset, |
| 204 | static_cast<float>(enc_time) / CLOCKS_PER_SEC, |
| 205 | static_cast<float>(dec_time) / CLOCKS_PER_SEC); |
| 206 | return ans_read_end(&d); |
| 207 | } |
| 208 | |
| 209 | void build_tree(vpx_tree_index *tree, int num_syms) { |
| 210 | vpx_tree_index i; |
| 211 | int sym = 0; |
| 212 | for (i = 0; i < num_syms - 1; ++i) { |
| 213 | tree[2 * i] = sym--; |
| 214 | tree[2 * i + 1] = 2 * (i + 1); |
| 215 | } |
| 216 | tree[2 * i - 1] = sym; |
| 217 | } |
| 218 | |
| 219 | // treep are the probabilites of tree nodes like: |
| 220 | // * |
| 221 | // / \ |
| 222 | // -sym0 * |
| 223 | // / \ |
| 224 | // -sym1 * |
| 225 | // / \ |
| 226 | // -sym2 -sym3 |
| 227 | void tab2tree(const rans_sym *tab, int tab_size, vpx_prob *treep) { |
| 228 | const unsigned basep = 256; |
| 229 | unsigned pleft = basep; |
| 230 | for (int i = 0; i < tab_size - 1; ++i) { |
| 231 | unsigned prob = (tab[i].prob * basep + (basep / 2)) / pleft; |
| 232 | assert(prob > 0 && prob < 256); |
| 233 | treep[i] = prob; |
| 234 | pleft -= tab[i].prob; |
| 235 | } |
| 236 | } |
| 237 | |
| 238 | struct sym_bools { |
| 239 | unsigned bits; |
| 240 | int len; |
| 241 | }; |
| 242 | |
| 243 | static void make_tree_bits_tab(sym_bools *tab, int num_syms) { |
| 244 | unsigned bits = 0; |
| 245 | int len = 0; |
| 246 | int i; |
| 247 | for (i = 0; i < num_syms - 1; ++i) { |
| 248 | bits *= 2; |
| 249 | ++len; |
| 250 | tab[i].bits = bits; |
| 251 | tab[i].len = len; |
| 252 | ++bits; |
| 253 | } |
| 254 | tab[i].bits = bits; |
| 255 | tab[i].len = len; |
| 256 | } |
| 257 | |
| 258 | void build_tpb(vpx_prob probs[/*num_syms*/], |
| 259 | vpx_tree_index tree[/*2*num_syms*/], |
| 260 | sym_bools bit_len[/*num_syms*/], |
| 261 | const rans_sym sym_tab[/*num_syms*/], int num_syms) { |
| 262 | tab2tree(sym_tab, num_syms, probs); |
| 263 | build_tree(tree, num_syms); |
| 264 | make_tree_bits_tab(bit_len, num_syms); |
| 265 | } |
| 266 | |
| 267 | bool check_vpxtree(const std::vector<int> &sym_vec, const rans_sym *sym_tab, |
| 268 | uint8_t *buf) { |
| 269 | vpx_writer w; |
| 270 | vpx_reader r; |
| 271 | vpx_start_encode(&w, buf); |
| 272 | |
| 273 | vpx_prob probs[kDistinctSyms]; |
| 274 | vpx_tree_index tree[2 * kDistinctSyms]; |
| 275 | sym_bools bit_len[kDistinctSyms]; |
| 276 | build_tpb(probs, tree, bit_len, sym_tab, kDistinctSyms); |
| 277 | |
| 278 | std::clock_t start = std::clock(); |
| 279 | for (std::vector<int>::const_iterator it = sym_vec.begin(); |
| 280 | it != sym_vec.end(); ++it) { |
| 281 | vp10_write_tree(&w, tree, probs, bit_len[*it].bits, bit_len[*it].len, 0); |
| 282 | } |
| 283 | std::clock_t enc_time = std::clock() - start; |
| 284 | vpx_stop_encode(&w); |
| 285 | vpx_reader_init(&r, buf, w.pos, NULL, NULL); |
| 286 | start = std::clock(); |
| 287 | for (std::vector<int>::const_iterator it = sym_vec.begin(); |
| 288 | it != sym_vec.end(); ++it) { |
| 289 | if (vpx_read_tree(&r, tree, probs) != *it) return false; |
| 290 | } |
| 291 | std::clock_t dec_time = std::clock() - start; |
| 292 | printf("VPXtree size %u enc_time %f dec_time %f\n", w.pos, |
| 293 | static_cast<float>(enc_time) / CLOCKS_PER_SEC, |
| 294 | static_cast<float>(dec_time) / CLOCKS_PER_SEC); |
| 295 | return true; |
| 296 | } |
| 297 | |
| 298 | class Vp10AbsTest : public ::testing::Test { |
| 299 | protected: |
| 300 | static void SetUpTestCase() { pv_vec_ = abs_encode_build_vals(kNumBools); } |
| 301 | virtual void SetUp() { buf_ = new uint8_t[kNumBools / 8]; } |
| 302 | virtual void TearDown() { delete[] buf_; } |
| 303 | static const int kNumBools = 100000000; |
| 304 | static PvVec pv_vec_; |
| 305 | uint8_t *buf_; |
| 306 | }; |
| 307 | PvVec Vp10AbsTest::pv_vec_; |
| 308 | |
| 309 | class Vp10AnsTest : public ::testing::Test { |
| 310 | protected: |
| 311 | static void SetUpTestCase() { |
| 312 | sym_vec_ = ans_encode_build_vals(rans_sym_tab, kNumSyms); |
| 313 | } |
| 314 | virtual void SetUp() { buf_ = new uint8_t[kNumSyms / 2]; } |
| 315 | virtual void TearDown() { delete[] buf_; } |
| 316 | static const int kNumSyms = 25000000; |
| 317 | static std::vector<int> sym_vec_; |
| 318 | uint8_t *buf_; |
| 319 | }; |
| 320 | std::vector<int> Vp10AnsTest::sym_vec_; |
| 321 | |
| 322 | TEST_F(Vp10AbsTest, Vpxbool) { EXPECT_TRUE(check_vpxbool(pv_vec_, buf_)); } |
| 323 | TEST_F(Vp10AbsTest, Rabs) { EXPECT_TRUE(check_rabs(pv_vec_, buf_)); } |
| 324 | TEST_F(Vp10AbsTest, RabsAsc) { EXPECT_TRUE(check_rabs_asc(pv_vec_, buf_)); } |
| 325 | TEST_F(Vp10AbsTest, Uabs) { EXPECT_TRUE(check_uabs(pv_vec_, buf_)); } |
| 326 | |
| 327 | TEST_F(Vp10AnsTest, Rans) { |
| 328 | EXPECT_TRUE(check_rans(sym_vec_, rans_sym_tab, buf_)); |
| 329 | } |
| 330 | TEST_F(Vp10AnsTest, Vpxtree) { |
| 331 | EXPECT_TRUE(check_vpxtree(sym_vec_, rans_sym_tab, buf_)); |
| 332 | } |
| 333 | } // namespace |