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