blob: ddedbea9d27030ba1c11579f55136263b50db526 [file] [log] [blame]
Alex Converse9ffcb462015-12-16 11:16:32 -08001/*
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 Converse7b22c1d2016-03-22 11:11:30 -070011#define VP10_FORCE_VPXBOOL_TREEWRITER
12
Alex Converse9ffcb462015-12-16 11:16:32 -080013#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 Xuc27fc142016-08-22 16:08:15 -070023#include "av1/common/ans.h"
24#include "av1/encoder/treewriter.h"
25#include "aom_dsp/bitreader.h"
26#include "aom_dsp/bitwriter.h"
Alex Converse9ffcb462015-12-16 11:16:32 -080027
28namespace {
29typedef std::vector<std::pair<uint8_t, bool> > PvVec;
30
31PvVec abs_encode_build_vals(int iters) {
32 PvVec ret;
Yaowu Xuc27fc142016-08-22 16:08:15 -070033 libaom_test::ACMRandom gen(0x30317076);
Alex Converse9ffcb462015-12-16 11:16:32 -080034 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
49bool 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
75bool 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
101bool 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
127bool 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 Converse1f57aa32016-01-06 12:37:27 -0800151// TODO(aconverse): replace this with a more representative distribution from
152// the codec.
Alex Converse9ffcb462015-12-16 11:16:32 -0800153const rans_sym rans_sym_tab[] = {
clang-format3a826f12016-08-11 17:46:05 -0700154 { 16 * 4, 0 * 4 },
155 { 100 * 4, 16 * 4 },
156 { 70 * 4, 116 * 4 },
157 { 70 * 4, 186 * 4 },
Alex Converse9ffcb462015-12-16 11:16:32 -0800158};
159const int kDistinctSyms = sizeof(rans_sym_tab) / sizeof(rans_sym_tab[0]);
160
161std::vector<int> ans_encode_build_vals(const rans_sym *tab, int iters) {
162 std::vector<int> p_to_sym;
163 int i = 0;
Alex Converse1f57aa32016-01-06 12:37:27 -0800164 while (p_to_sym.size() < rans_precision) {
Alex Converse9ffcb462015-12-16 11:16:32 -0800165 p_to_sym.insert(p_to_sym.end(), tab[i].prob, i);
166 ++i;
167 }
Alex Converse1f57aa32016-01-06 12:37:27 -0800168 assert(p_to_sym.size() == rans_precision);
Alex Converse9ffcb462015-12-16 11:16:32 -0800169 std::vector<int> ret;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700170 libaom_test::ACMRandom gen(18543637);
Alex Converse9ffcb462015-12-16 11:16:32 -0800171 for (int i = 0; i < iters; ++i) {
Alex Converse1f57aa32016-01-06 12:37:27 -0800172 int sym = p_to_sym[gen.Rand8() * 4];
Alex Converse9ffcb462015-12-16 11:16:32 -0800173 ret.push_back(sym);
174 }
175 return ret;
176}
177
clang-format3a826f12016-08-11 17:46:05 -0700178void rans_build_dec_tab(const struct rans_sym sym_tab[], rans_dec_lut dec_tab) {
Alex Converse6bbbe312016-02-16 13:41:01 -0800179 dec_tab[0] = 0;
Alex Converse1f57aa32016-01-06 12:37:27 -0800180 for (int i = 1; dec_tab[i - 1] < rans_precision; ++i) {
Alex Converse6bbbe312016-02-16 13:41:01 -0800181 dec_tab[i] = dec_tab[i - 1] + sym_tab[i - 1].prob;
Alex Converse9ffcb462015-12-16 11:16:32 -0800182 }
183}
184
185bool 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
215void 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 Converseaf562992016-04-12 15:38:26 -0700225/* 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 Converse9ffcb462015-12-16 11:16:32 -0800235void tab2tree(const rans_sym *tab, int tab_size, vpx_prob *treep) {
Alex Converse1f57aa32016-01-06 12:37:27 -0800236 const unsigned basep = rans_precision;
Alex Converse9ffcb462015-12-16 11:16:32 -0800237 unsigned pleft = basep;
238 for (int i = 0; i < tab_size - 1; ++i) {
Alex Converse1f57aa32016-01-06 12:37:27 -0800239 unsigned prob = (tab[i].prob * basep + basep * 2) / (pleft * 4);
Alex Converse9ffcb462015-12-16 11:16:32 -0800240 assert(prob > 0 && prob < 256);
241 treep[i] = prob;
242 pleft -= tab[i].prob;
243 }
244}
245
246struct sym_bools {
247 unsigned bits;
248 int len;
249};
250
251static 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
266void 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
275bool 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
306class 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};
315PvVec Vp10AbsTest::pv_vec_;
316
317class 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};
328std::vector<int> Vp10AnsTest::sym_vec_;
329
330TEST_F(Vp10AbsTest, Vpxbool) { EXPECT_TRUE(check_vpxbool(pv_vec_, buf_)); }
331TEST_F(Vp10AbsTest, Rabs) { EXPECT_TRUE(check_rabs(pv_vec_, buf_)); }
332TEST_F(Vp10AbsTest, RabsAsc) { EXPECT_TRUE(check_rabs_asc(pv_vec_, buf_)); }
333TEST_F(Vp10AbsTest, Uabs) { EXPECT_TRUE(check_uabs(pv_vec_, buf_)); }
334
335TEST_F(Vp10AnsTest, Rans) {
336 EXPECT_TRUE(check_rans(sym_vec_, rans_sym_tab, buf_));
337}
338TEST_F(Vp10AnsTest, Vpxtree) {
339 EXPECT_TRUE(check_vpxtree(sym_vec_, rans_sym_tab, buf_));
340}
341} // namespace