1*c0909341SAndroid Build Coastguard Worker /*
2*c0909341SAndroid Build Coastguard Worker * Copyright © 2018, VideoLAN and dav1d authors
3*c0909341SAndroid Build Coastguard Worker * Copyright © 2018, Two Orioles, LLC
4*c0909341SAndroid Build Coastguard Worker * All rights reserved.
5*c0909341SAndroid Build Coastguard Worker *
6*c0909341SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
7*c0909341SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions are met:
8*c0909341SAndroid Build Coastguard Worker *
9*c0909341SAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright notice, this
10*c0909341SAndroid Build Coastguard Worker * list of conditions and the following disclaimer.
11*c0909341SAndroid Build Coastguard Worker *
12*c0909341SAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright notice,
13*c0909341SAndroid Build Coastguard Worker * this list of conditions and the following disclaimer in the documentation
14*c0909341SAndroid Build Coastguard Worker * and/or other materials provided with the distribution.
15*c0909341SAndroid Build Coastguard Worker *
16*c0909341SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17*c0909341SAndroid Build Coastguard Worker * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18*c0909341SAndroid Build Coastguard Worker * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19*c0909341SAndroid Build Coastguard Worker * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20*c0909341SAndroid Build Coastguard Worker * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21*c0909341SAndroid Build Coastguard Worker * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22*c0909341SAndroid Build Coastguard Worker * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23*c0909341SAndroid Build Coastguard Worker * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*c0909341SAndroid Build Coastguard Worker * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25*c0909341SAndroid Build Coastguard Worker * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*c0909341SAndroid Build Coastguard Worker */
27*c0909341SAndroid Build Coastguard Worker
28*c0909341SAndroid Build Coastguard Worker #include "config.h"
29*c0909341SAndroid Build Coastguard Worker
30*c0909341SAndroid Build Coastguard Worker #include <limits.h>
31*c0909341SAndroid Build Coastguard Worker
32*c0909341SAndroid Build Coastguard Worker #include "common/intops.h"
33*c0909341SAndroid Build Coastguard Worker
34*c0909341SAndroid Build Coastguard Worker #include "src/msac.h"
35*c0909341SAndroid Build Coastguard Worker
36*c0909341SAndroid Build Coastguard Worker #define EC_PROB_SHIFT 6
37*c0909341SAndroid Build Coastguard Worker #define EC_MIN_PROB 4 // must be <= (1<<EC_PROB_SHIFT)/16
38*c0909341SAndroid Build Coastguard Worker
39*c0909341SAndroid Build Coastguard Worker #define EC_WIN_SIZE (sizeof(ec_win) << 3)
40*c0909341SAndroid Build Coastguard Worker
ctx_refill(MsacContext * const s)41*c0909341SAndroid Build Coastguard Worker static inline void ctx_refill(MsacContext *const s) {
42*c0909341SAndroid Build Coastguard Worker const uint8_t *buf_pos = s->buf_pos;
43*c0909341SAndroid Build Coastguard Worker const uint8_t *buf_end = s->buf_end;
44*c0909341SAndroid Build Coastguard Worker int c = EC_WIN_SIZE - s->cnt - 24;
45*c0909341SAndroid Build Coastguard Worker ec_win dif = s->dif;
46*c0909341SAndroid Build Coastguard Worker do {
47*c0909341SAndroid Build Coastguard Worker if (buf_pos >= buf_end) {
48*c0909341SAndroid Build Coastguard Worker // set remaining bits to 1;
49*c0909341SAndroid Build Coastguard Worker dif |= ~(~(ec_win)0xff << c);
50*c0909341SAndroid Build Coastguard Worker break;
51*c0909341SAndroid Build Coastguard Worker }
52*c0909341SAndroid Build Coastguard Worker dif |= (ec_win)(*buf_pos++ ^ 0xff) << c;
53*c0909341SAndroid Build Coastguard Worker c -= 8;
54*c0909341SAndroid Build Coastguard Worker } while (c >= 0);
55*c0909341SAndroid Build Coastguard Worker s->dif = dif;
56*c0909341SAndroid Build Coastguard Worker s->cnt = EC_WIN_SIZE - c - 24;
57*c0909341SAndroid Build Coastguard Worker s->buf_pos = buf_pos;
58*c0909341SAndroid Build Coastguard Worker }
59*c0909341SAndroid Build Coastguard Worker
dav1d_msac_decode_subexp(MsacContext * const s,const int ref,const int n,unsigned k)60*c0909341SAndroid Build Coastguard Worker int dav1d_msac_decode_subexp(MsacContext *const s, const int ref,
61*c0909341SAndroid Build Coastguard Worker const int n, unsigned k)
62*c0909341SAndroid Build Coastguard Worker {
63*c0909341SAndroid Build Coastguard Worker assert(n >> k == 8);
64*c0909341SAndroid Build Coastguard Worker
65*c0909341SAndroid Build Coastguard Worker unsigned a = 0;
66*c0909341SAndroid Build Coastguard Worker if (dav1d_msac_decode_bool_equi(s)) {
67*c0909341SAndroid Build Coastguard Worker if (dav1d_msac_decode_bool_equi(s))
68*c0909341SAndroid Build Coastguard Worker k += dav1d_msac_decode_bool_equi(s) + 1;
69*c0909341SAndroid Build Coastguard Worker a = 1 << k;
70*c0909341SAndroid Build Coastguard Worker }
71*c0909341SAndroid Build Coastguard Worker const unsigned v = dav1d_msac_decode_bools(s, k) + a;
72*c0909341SAndroid Build Coastguard Worker return ref * 2 <= n ? inv_recenter(ref, v) :
73*c0909341SAndroid Build Coastguard Worker n - 1 - inv_recenter(n - 1 - ref, v);
74*c0909341SAndroid Build Coastguard Worker }
75*c0909341SAndroid Build Coastguard Worker
76*c0909341SAndroid Build Coastguard Worker #if !(HAVE_ASM && TRIM_DSP_FUNCTIONS && ( \
77*c0909341SAndroid Build Coastguard Worker ARCH_AARCH64 || \
78*c0909341SAndroid Build Coastguard Worker (ARCH_ARM && (defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32))) \
79*c0909341SAndroid Build Coastguard Worker ))
80*c0909341SAndroid Build Coastguard Worker /* Takes updated dif and range values, renormalizes them so that
81*c0909341SAndroid Build Coastguard Worker * 32768 <= rng < 65536 (reading more bytes from the stream into dif if
82*c0909341SAndroid Build Coastguard Worker * necessary), and stores them back in the decoder context.
83*c0909341SAndroid Build Coastguard Worker * dif: The new value of dif.
84*c0909341SAndroid Build Coastguard Worker * rng: The new value of the range. */
ctx_norm(MsacContext * const s,const ec_win dif,const unsigned rng)85*c0909341SAndroid Build Coastguard Worker static inline void ctx_norm(MsacContext *const s, const ec_win dif,
86*c0909341SAndroid Build Coastguard Worker const unsigned rng)
87*c0909341SAndroid Build Coastguard Worker {
88*c0909341SAndroid Build Coastguard Worker const int d = 15 ^ (31 ^ clz(rng));
89*c0909341SAndroid Build Coastguard Worker const int cnt = s->cnt;
90*c0909341SAndroid Build Coastguard Worker assert(rng <= 65535U);
91*c0909341SAndroid Build Coastguard Worker s->dif = dif << d;
92*c0909341SAndroid Build Coastguard Worker s->rng = rng << d;
93*c0909341SAndroid Build Coastguard Worker s->cnt = cnt - d;
94*c0909341SAndroid Build Coastguard Worker // unsigned compare avoids redundant refills at eob
95*c0909341SAndroid Build Coastguard Worker if ((unsigned)cnt < (unsigned)d)
96*c0909341SAndroid Build Coastguard Worker ctx_refill(s);
97*c0909341SAndroid Build Coastguard Worker }
98*c0909341SAndroid Build Coastguard Worker
dav1d_msac_decode_bool_equi_c(MsacContext * const s)99*c0909341SAndroid Build Coastguard Worker unsigned dav1d_msac_decode_bool_equi_c(MsacContext *const s) {
100*c0909341SAndroid Build Coastguard Worker const unsigned r = s->rng;
101*c0909341SAndroid Build Coastguard Worker ec_win dif = s->dif;
102*c0909341SAndroid Build Coastguard Worker assert((dif >> (EC_WIN_SIZE - 16)) < r);
103*c0909341SAndroid Build Coastguard Worker // When the probability is 1/2, f = 16384 >> EC_PROB_SHIFT = 256 and we can
104*c0909341SAndroid Build Coastguard Worker // replace the multiply with a simple shift.
105*c0909341SAndroid Build Coastguard Worker unsigned v = ((r >> 8) << 7) + EC_MIN_PROB;
106*c0909341SAndroid Build Coastguard Worker const ec_win vw = (ec_win)v << (EC_WIN_SIZE - 16);
107*c0909341SAndroid Build Coastguard Worker const unsigned ret = dif >= vw;
108*c0909341SAndroid Build Coastguard Worker dif -= ret * vw;
109*c0909341SAndroid Build Coastguard Worker v += ret * (r - 2 * v);
110*c0909341SAndroid Build Coastguard Worker ctx_norm(s, dif, v);
111*c0909341SAndroid Build Coastguard Worker return !ret;
112*c0909341SAndroid Build Coastguard Worker }
113*c0909341SAndroid Build Coastguard Worker
114*c0909341SAndroid Build Coastguard Worker /* Decode a single binary value.
115*c0909341SAndroid Build Coastguard Worker * f: The probability that the bit is one
116*c0909341SAndroid Build Coastguard Worker * Return: The value decoded (0 or 1). */
dav1d_msac_decode_bool_c(MsacContext * const s,const unsigned f)117*c0909341SAndroid Build Coastguard Worker unsigned dav1d_msac_decode_bool_c(MsacContext *const s, const unsigned f) {
118*c0909341SAndroid Build Coastguard Worker const unsigned r = s->rng;
119*c0909341SAndroid Build Coastguard Worker ec_win dif = s->dif;
120*c0909341SAndroid Build Coastguard Worker assert((dif >> (EC_WIN_SIZE - 16)) < r);
121*c0909341SAndroid Build Coastguard Worker unsigned v = ((r >> 8) * (f >> EC_PROB_SHIFT) >> (7 - EC_PROB_SHIFT)) + EC_MIN_PROB;
122*c0909341SAndroid Build Coastguard Worker const ec_win vw = (ec_win)v << (EC_WIN_SIZE - 16);
123*c0909341SAndroid Build Coastguard Worker const unsigned ret = dif >= vw;
124*c0909341SAndroid Build Coastguard Worker dif -= ret * vw;
125*c0909341SAndroid Build Coastguard Worker v += ret * (r - 2 * v);
126*c0909341SAndroid Build Coastguard Worker ctx_norm(s, dif, v);
127*c0909341SAndroid Build Coastguard Worker return !ret;
128*c0909341SAndroid Build Coastguard Worker }
129*c0909341SAndroid Build Coastguard Worker
130*c0909341SAndroid Build Coastguard Worker /* Decodes a symbol given an inverse cumulative distribution function (CDF)
131*c0909341SAndroid Build Coastguard Worker * table in Q15. */
dav1d_msac_decode_symbol_adapt_c(MsacContext * const s,uint16_t * const cdf,const size_t n_symbols)132*c0909341SAndroid Build Coastguard Worker unsigned dav1d_msac_decode_symbol_adapt_c(MsacContext *const s,
133*c0909341SAndroid Build Coastguard Worker uint16_t *const cdf,
134*c0909341SAndroid Build Coastguard Worker const size_t n_symbols)
135*c0909341SAndroid Build Coastguard Worker {
136*c0909341SAndroid Build Coastguard Worker const unsigned c = s->dif >> (EC_WIN_SIZE - 16), r = s->rng >> 8;
137*c0909341SAndroid Build Coastguard Worker unsigned u, v = s->rng, val = -1;
138*c0909341SAndroid Build Coastguard Worker
139*c0909341SAndroid Build Coastguard Worker assert(n_symbols <= 15);
140*c0909341SAndroid Build Coastguard Worker assert(cdf[n_symbols] <= 32);
141*c0909341SAndroid Build Coastguard Worker
142*c0909341SAndroid Build Coastguard Worker do {
143*c0909341SAndroid Build Coastguard Worker val++;
144*c0909341SAndroid Build Coastguard Worker u = v;
145*c0909341SAndroid Build Coastguard Worker v = r * (cdf[val] >> EC_PROB_SHIFT);
146*c0909341SAndroid Build Coastguard Worker v >>= 7 - EC_PROB_SHIFT;
147*c0909341SAndroid Build Coastguard Worker v += EC_MIN_PROB * ((unsigned)n_symbols - val);
148*c0909341SAndroid Build Coastguard Worker } while (c < v);
149*c0909341SAndroid Build Coastguard Worker
150*c0909341SAndroid Build Coastguard Worker assert(u <= s->rng);
151*c0909341SAndroid Build Coastguard Worker
152*c0909341SAndroid Build Coastguard Worker ctx_norm(s, s->dif - ((ec_win)v << (EC_WIN_SIZE - 16)), u - v);
153*c0909341SAndroid Build Coastguard Worker
154*c0909341SAndroid Build Coastguard Worker if (s->allow_update_cdf) {
155*c0909341SAndroid Build Coastguard Worker const unsigned count = cdf[n_symbols];
156*c0909341SAndroid Build Coastguard Worker const unsigned rate = 4 + (count >> 4) + (n_symbols > 2);
157*c0909341SAndroid Build Coastguard Worker unsigned i;
158*c0909341SAndroid Build Coastguard Worker for (i = 0; i < val; i++)
159*c0909341SAndroid Build Coastguard Worker cdf[i] += (32768 - cdf[i]) >> rate;
160*c0909341SAndroid Build Coastguard Worker for (; i < n_symbols; i++)
161*c0909341SAndroid Build Coastguard Worker cdf[i] -= cdf[i] >> rate;
162*c0909341SAndroid Build Coastguard Worker cdf[n_symbols] = count + (count < 32);
163*c0909341SAndroid Build Coastguard Worker }
164*c0909341SAndroid Build Coastguard Worker
165*c0909341SAndroid Build Coastguard Worker return val;
166*c0909341SAndroid Build Coastguard Worker }
167*c0909341SAndroid Build Coastguard Worker
dav1d_msac_decode_bool_adapt_c(MsacContext * const s,uint16_t * const cdf)168*c0909341SAndroid Build Coastguard Worker unsigned dav1d_msac_decode_bool_adapt_c(MsacContext *const s,
169*c0909341SAndroid Build Coastguard Worker uint16_t *const cdf)
170*c0909341SAndroid Build Coastguard Worker {
171*c0909341SAndroid Build Coastguard Worker const unsigned bit = dav1d_msac_decode_bool(s, *cdf);
172*c0909341SAndroid Build Coastguard Worker
173*c0909341SAndroid Build Coastguard Worker if (s->allow_update_cdf) {
174*c0909341SAndroid Build Coastguard Worker // update_cdf() specialized for boolean CDFs
175*c0909341SAndroid Build Coastguard Worker const unsigned count = cdf[1];
176*c0909341SAndroid Build Coastguard Worker const int rate = 4 + (count >> 4);
177*c0909341SAndroid Build Coastguard Worker if (bit)
178*c0909341SAndroid Build Coastguard Worker cdf[0] += (32768 - cdf[0]) >> rate;
179*c0909341SAndroid Build Coastguard Worker else
180*c0909341SAndroid Build Coastguard Worker cdf[0] -= cdf[0] >> rate;
181*c0909341SAndroid Build Coastguard Worker cdf[1] = count + (count < 32);
182*c0909341SAndroid Build Coastguard Worker }
183*c0909341SAndroid Build Coastguard Worker
184*c0909341SAndroid Build Coastguard Worker return bit;
185*c0909341SAndroid Build Coastguard Worker }
186*c0909341SAndroid Build Coastguard Worker
dav1d_msac_decode_hi_tok_c(MsacContext * const s,uint16_t * const cdf)187*c0909341SAndroid Build Coastguard Worker unsigned dav1d_msac_decode_hi_tok_c(MsacContext *const s, uint16_t *const cdf) {
188*c0909341SAndroid Build Coastguard Worker unsigned tok_br = dav1d_msac_decode_symbol_adapt4(s, cdf, 3);
189*c0909341SAndroid Build Coastguard Worker unsigned tok = 3 + tok_br;
190*c0909341SAndroid Build Coastguard Worker if (tok_br == 3) {
191*c0909341SAndroid Build Coastguard Worker tok_br = dav1d_msac_decode_symbol_adapt4(s, cdf, 3);
192*c0909341SAndroid Build Coastguard Worker tok = 6 + tok_br;
193*c0909341SAndroid Build Coastguard Worker if (tok_br == 3) {
194*c0909341SAndroid Build Coastguard Worker tok_br = dav1d_msac_decode_symbol_adapt4(s, cdf, 3);
195*c0909341SAndroid Build Coastguard Worker tok = 9 + tok_br;
196*c0909341SAndroid Build Coastguard Worker if (tok_br == 3)
197*c0909341SAndroid Build Coastguard Worker tok = 12 + dav1d_msac_decode_symbol_adapt4(s, cdf, 3);
198*c0909341SAndroid Build Coastguard Worker }
199*c0909341SAndroid Build Coastguard Worker }
200*c0909341SAndroid Build Coastguard Worker return tok;
201*c0909341SAndroid Build Coastguard Worker }
202*c0909341SAndroid Build Coastguard Worker #endif
203*c0909341SAndroid Build Coastguard Worker
dav1d_msac_init(MsacContext * const s,const uint8_t * const data,const size_t sz,const int disable_cdf_update_flag)204*c0909341SAndroid Build Coastguard Worker void dav1d_msac_init(MsacContext *const s, const uint8_t *const data,
205*c0909341SAndroid Build Coastguard Worker const size_t sz, const int disable_cdf_update_flag)
206*c0909341SAndroid Build Coastguard Worker {
207*c0909341SAndroid Build Coastguard Worker s->buf_pos = data;
208*c0909341SAndroid Build Coastguard Worker s->buf_end = data + sz;
209*c0909341SAndroid Build Coastguard Worker s->dif = 0;
210*c0909341SAndroid Build Coastguard Worker s->rng = 0x8000;
211*c0909341SAndroid Build Coastguard Worker s->cnt = -15;
212*c0909341SAndroid Build Coastguard Worker s->allow_update_cdf = !disable_cdf_update_flag;
213*c0909341SAndroid Build Coastguard Worker ctx_refill(s);
214*c0909341SAndroid Build Coastguard Worker
215*c0909341SAndroid Build Coastguard Worker #if ARCH_X86_64 && HAVE_ASM
216*c0909341SAndroid Build Coastguard Worker s->symbol_adapt16 = dav1d_msac_decode_symbol_adapt_c;
217*c0909341SAndroid Build Coastguard Worker
218*c0909341SAndroid Build Coastguard Worker msac_init_x86(s);
219*c0909341SAndroid Build Coastguard Worker #endif
220*c0909341SAndroid Build Coastguard Worker }
221