blob: 363161d7a428aefa9ee041e5cbc53dd289f75e88 [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
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
26namespace {
27typedef std::vector<std::pair<uint8_t, bool> > PvVec;
28
29PvVec 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
47bool 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
73bool 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
99bool 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
125bool 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
149const rans_sym rans_sym_tab[] = {
Alex Converse6bbbe312016-02-16 13:41:01 -0800150 {16, 0}, {100, 16}, {70, 116}, {70, 186},
Alex Converse9ffcb462015-12-16 11:16:32 -0800151};
152const int kDistinctSyms = sizeof(rans_sym_tab) / sizeof(rans_sym_tab[0]);
153
154std::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
171void rans_build_dec_tab(const struct rans_sym sym_tab[],
172 rans_dec_lut dec_tab) {
Alex Converse6bbbe312016-02-16 13:41:01 -0800173 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 Converse9ffcb462015-12-16 11:16:32 -0800176 }
177}
178
179bool 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
209void 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
227void 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
238struct sym_bools {
239 unsigned bits;
240 int len;
241};
242
243static 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
258void 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
267bool 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
298class 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};
307PvVec Vp10AbsTest::pv_vec_;
308
309class 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};
320std::vector<int> Vp10AnsTest::sym_vec_;
321
322TEST_F(Vp10AbsTest, Vpxbool) { EXPECT_TRUE(check_vpxbool(pv_vec_, buf_)); }
323TEST_F(Vp10AbsTest, Rabs) { EXPECT_TRUE(check_rabs(pv_vec_, buf_)); }
324TEST_F(Vp10AbsTest, RabsAsc) { EXPECT_TRUE(check_rabs_asc(pv_vec_, buf_)); }
325TEST_F(Vp10AbsTest, Uabs) { EXPECT_TRUE(check_uabs(pv_vec_, buf_)); }
326
327TEST_F(Vp10AnsTest, Rans) {
328 EXPECT_TRUE(check_rans(sym_vec_, rans_sym_tab, buf_));
329}
330TEST_F(Vp10AnsTest, Vpxtree) {
331 EXPECT_TRUE(check_vpxtree(sym_vec_, rans_sym_tab, buf_));
332}
333} // namespace