2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
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.
19 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
21 #include "test/acm_random.h"
22 #include "aom_dsp/ansreader.h"
23 #include "aom_dsp/buf_ans.h"
26 typedef std::vector
<std::pair
<uint8_t, bool> > PvVec
;
28 const int kPrintStats
= 0;
29 // Use a small buffer size to exercise ANS window spills or buffer growth
30 const int kBufAnsSize
= 1 << 8;
32 PvVec
abs_encode_build_vals(int iters
) {
34 libaom_test::ACMRandom
gen(0x30317076);
36 for (int i
= 0; i
< iters
; ++i
) {
40 } while (p
== 0); // zero is not a valid coding probability
41 bool b
= gen
.Rand8() < p
;
42 ret
.push_back(std::make_pair(static_cast<uint8_t>(p
), b
));
45 entropy
+= -d
* log2(d
) - (1 - d
) * log2(1 - d
);
48 if (kPrintStats
) printf("entropy %f\n", entropy
);
52 bool check_rabs(const PvVec
&pv_vec
, uint8_t *buf
) {
55 aom_buf_ans_alloc(&a
, NULL
);
56 buf_ans_write_init(&a
, buf
);
58 std::clock_t start
= std::clock();
59 for (PvVec::const_iterator it
= pv_vec
.begin(); it
!= pv_vec
.end(); ++it
) {
60 buf_rabs_write(&a
, it
->second
, 256 - it
->first
);
62 aom_buf_ans_flush(&a
);
63 std::clock_t enc_time
= std::clock() - start
;
64 int offset
= buf_ans_write_end(&a
);
69 d
.window_size
= kBufAnsSize
;
71 if (ans_read_init(&d
, buf
, offset
)) return false;
73 for (PvVec::const_iterator it
= pv_vec
.begin(); it
!= pv_vec
.end(); ++it
) {
74 okay
= okay
&& (rabs_read(&d
, 256 - it
->first
) != 0) == it
->second
;
76 std::clock_t dec_time
= std::clock() - start
;
77 if (!okay
) return false;
79 printf("uABS size %d enc_time %f dec_time %f\n", offset
,
80 static_cast<float>(enc_time
) / CLOCKS_PER_SEC
,
81 static_cast<float>(dec_time
) / CLOCKS_PER_SEC
);
82 return ans_read_end(&d
) != 0;
85 const aom_cdf_prob spareto65
[] = { 8320, 6018, 4402, 3254, 4259,
86 3919, 2057, 492, 45, 2 };
88 const int kRansSymbols
=
89 static_cast<int>(sizeof(spareto65
) / sizeof(spareto65
[0]));
93 aom_cdf_prob cum_prob
; // not-inclusive
96 std::vector
<int> ans_encode_build_vals(rans_sym
*const tab
, int iters
) {
98 for (int i
= 0; i
< kRansSymbols
; ++i
) {
99 tab
[i
].cum_prob
= sum
;
100 tab
[i
].prob
= spareto65
[i
];
103 std::vector
<int> p_to_sym
;
104 for (int i
= 0; i
< kRansSymbols
; ++i
) {
105 p_to_sym
.insert(p_to_sym
.end(), tab
[i
].prob
, i
);
107 assert(p_to_sym
.size() == RANS_PRECISION
);
108 std::vector
<int> ret
;
109 libaom_test::ACMRandom
gen(18543637);
110 for (int i
= 0; i
< iters
; ++i
) {
112 p_to_sym
[((gen
.Rand8() << 8) + gen
.Rand8()) & (RANS_PRECISION
- 1)];
118 void rans_build_dec_tab(const struct rans_sym sym_tab
[],
119 aom_cdf_prob
*dec_tab
) {
120 unsigned int sum
= 0;
121 for (int i
= 0; sum
< RANS_PRECISION
; ++i
) {
122 dec_tab
[i
] = sum
+= sym_tab
[i
].prob
;
126 bool check_rans(const std::vector
<int> &sym_vec
, const rans_sym
*const tab
,
129 a
.size
= kBufAnsSize
;
130 aom_buf_ans_alloc(&a
, NULL
);
131 buf_ans_write_init(&a
, buf
);
132 aom_cdf_prob dec_tab
[kRansSymbols
];
133 rans_build_dec_tab(tab
, dec_tab
);
135 std::clock_t start
= std::clock();
136 for (std::vector
<int>::const_iterator it
= sym_vec
.begin();
137 it
!= sym_vec
.end(); ++it
) {
138 buf_rans_write(&a
, tab
[*it
].cum_prob
, tab
[*it
].prob
);
140 aom_buf_ans_flush(&a
);
141 std::clock_t enc_time
= std::clock() - start
;
142 int offset
= buf_ans_write_end(&a
);
143 aom_buf_ans_free(&a
);
147 d
.window_size
= kBufAnsSize
;
149 if (ans_read_init(&d
, buf
, offset
)) return false;
150 start
= std::clock();
151 for (std::vector
<int>::const_iterator it
= sym_vec
.begin();
152 it
!= sym_vec
.end(); ++it
) {
153 okay
&= rans_read(&d
, dec_tab
) == *it
;
155 std::clock_t dec_time
= std::clock() - start
;
156 if (!okay
) return false;
158 printf("rANS size %d enc_time %f dec_time %f\n", offset
,
159 static_cast<float>(enc_time
) / CLOCKS_PER_SEC
,
160 static_cast<float>(dec_time
) / CLOCKS_PER_SEC
);
161 return ans_read_end(&d
) != 0;
164 class AbsTestFix
: public ::testing::Test
{
166 static void SetUpTestCase() { pv_vec_
= abs_encode_build_vals(kNumBools
); }
167 virtual void SetUp() { buf_
= new uint8_t[kNumBools
/ 8]; }
168 virtual void TearDown() { delete[] buf_
; }
169 static const int kNumBools
= 100000000;
170 static PvVec pv_vec_
;
173 PvVec
AbsTestFix::pv_vec_
;
175 class AnsTestFix
: public ::testing::Test
{
177 static void SetUpTestCase() {
178 sym_vec_
= ans_encode_build_vals(rans_sym_tab_
, kNumSyms
);
180 virtual void SetUp() { buf_
= new uint8_t[kNumSyms
/ 2]; }
181 virtual void TearDown() { delete[] buf_
; }
182 static const int kNumSyms
= 25000000;
183 static std::vector
<int> sym_vec_
;
184 static rans_sym rans_sym_tab_
[kRansSymbols
];
187 std::vector
<int> AnsTestFix::sym_vec_
;
188 rans_sym
AnsTestFix::rans_sym_tab_
[kRansSymbols
];
190 TEST_F(AbsTestFix
, Rabs
) { EXPECT_TRUE(check_rabs(pv_vec_
, buf_
)); }
191 TEST_F(AnsTestFix
, Rans
) {
192 EXPECT_TRUE(check_rans(sym_vec_
, rans_sym_tab_
, buf_
));
194 TEST(AnsTest
, FinalStateSerialization
) {
195 for (unsigned i
= L_BASE
; i
< L_BASE
* IO_BASE
; ++i
) {
198 ans_write_init(&c
, buf
);
200 const int written_size
= ans_write_end(&c
);
201 ASSERT_LT(static_cast<size_t>(written_size
), sizeof(buf
));
204 // There is no real data window here because no symbols are sent through
205 // ans (only synthetic states), so use a dummy value
206 d
.window_size
= 1024;
208 const int read_init_status
= ans_read_init(&d
, buf
, written_size
);
209 EXPECT_EQ(read_init_status
, 0);
210 EXPECT_EQ(d
.state
, i
);