| /* | |
| * Copyright © 2018, VideoLAN and dav1d authors | |
| * Copyright © 2018, Two Orioles, LLC | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are met: | |
| * | |
| * 1. Redistributions of source code must retain the above copyright notice, this | |
| * list of conditions and the following disclaimer. | |
| * | |
| * 2. Redistributions in binary form must reproduce the above copyright notice, | |
| * this list of conditions and the following disclaimer in the documentation | |
| * and/or other materials provided with the distribution. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #include "config.h" | |
| #include <limits.h> | |
| #include "common/intops.h" | |
| #include "src/msac.h" | |
| #define EC_PROB_SHIFT 6 | |
| #define EC_MIN_PROB 4 // must be <= (1<<EC_PROB_SHIFT)/16 | |
| #define EC_WIN_SIZE (sizeof(ec_win) << 3) | |
| static inline void ctx_refill(MsacContext *const s) { | |
| const uint8_t *buf_pos = s->buf_pos; | |
| const uint8_t *buf_end = s->buf_end; | |
| int c = EC_WIN_SIZE - s->cnt - 24; | |
| ec_win dif = s->dif; | |
| do { | |
| if (buf_pos >= buf_end) { | |
| // set remaining bits to 1; | |
| dif |= ~(~(ec_win)0xff << c); | |
| break; | |
| } | |
| dif |= (ec_win)(*buf_pos++ ^ 0xff) << c; | |
| c -= 8; | |
| } while (c >= 0); | |
| s->dif = dif; | |
| s->cnt = EC_WIN_SIZE - c - 24; | |
| s->buf_pos = buf_pos; | |
| } | |
| int dav1d_msac_decode_subexp(MsacContext *const s, const int ref, | |
| const int n, unsigned k) | |
| { | |
| assert(n >> k == 8); | |
| unsigned a = 0; | |
| if (dav1d_msac_decode_bool_equi(s)) { | |
| if (dav1d_msac_decode_bool_equi(s)) | |
| k += dav1d_msac_decode_bool_equi(s) + 1; | |
| a = 1 << k; | |
| } | |
| const unsigned v = dav1d_msac_decode_bools(s, k) + a; | |
| return ref * 2 <= n ? inv_recenter(ref, v) : | |
| n - 1 - inv_recenter(n - 1 - ref, v); | |
| } | |
| #if !(HAVE_ASM && TRIM_DSP_FUNCTIONS && ( \ | |
| ARCH_AARCH64 || \ | |
| (ARCH_ARM && (defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32))) \ | |
| )) | |
| /* Takes updated dif and range values, renormalizes them so that | |
| * 32768 <= rng < 65536 (reading more bytes from the stream into dif if | |
| * necessary), and stores them back in the decoder context. | |
| * dif: The new value of dif. | |
| * rng: The new value of the range. */ | |
| static inline void ctx_norm(MsacContext *const s, const ec_win dif, | |
| const unsigned rng) | |
| { | |
| const int d = 15 ^ (31 ^ clz(rng)); | |
| const int cnt = s->cnt; | |
| assert(rng <= 65535U); | |
| s->dif = dif << d; | |
| s->rng = rng << d; | |
| s->cnt = cnt - d; | |
| // unsigned compare avoids redundant refills at eob | |
| if ((unsigned)cnt < (unsigned)d) | |
| ctx_refill(s); | |
| } | |
| unsigned dav1d_msac_decode_bool_equi_c(MsacContext *const s) { | |
| const unsigned r = s->rng; | |
| ec_win dif = s->dif; | |
| assert((dif >> (EC_WIN_SIZE - 16)) < r); | |
| // When the probability is 1/2, f = 16384 >> EC_PROB_SHIFT = 256 and we can | |
| // replace the multiply with a simple shift. | |
| unsigned v = ((r >> 8) << 7) + EC_MIN_PROB; | |
| const ec_win vw = (ec_win)v << (EC_WIN_SIZE - 16); | |
| const unsigned ret = dif >= vw; | |
| dif -= ret * vw; | |
| v += ret * (r - 2 * v); | |
| ctx_norm(s, dif, v); | |
| return !ret; | |
| } | |
| /* Decode a single binary value. | |
| * f: The probability that the bit is one | |
| * Return: The value decoded (0 or 1). */ | |
| unsigned dav1d_msac_decode_bool_c(MsacContext *const s, const unsigned f) { | |
| const unsigned r = s->rng; | |
| ec_win dif = s->dif; | |
| assert((dif >> (EC_WIN_SIZE - 16)) < r); | |
| unsigned v = ((r >> 8) * (f >> EC_PROB_SHIFT) >> (7 - EC_PROB_SHIFT)) + EC_MIN_PROB; | |
| const ec_win vw = (ec_win)v << (EC_WIN_SIZE - 16); | |
| const unsigned ret = dif >= vw; | |
| dif -= ret * vw; | |
| v += ret * (r - 2 * v); | |
| ctx_norm(s, dif, v); | |
| return !ret; | |
| } | |
| /* Decodes a symbol given an inverse cumulative distribution function (CDF) | |
| * table in Q15. */ | |
| unsigned dav1d_msac_decode_symbol_adapt_c(MsacContext *const s, | |
| uint16_t *const cdf, | |
| const size_t n_symbols) | |
| { | |
| const unsigned c = s->dif >> (EC_WIN_SIZE - 16), r = s->rng >> 8; | |
| unsigned u, v = s->rng, val = -1; | |
| assert(n_symbols <= 15); | |
| assert(cdf[n_symbols] <= 32); | |
| do { | |
| val++; | |
| u = v; | |
| v = r * (cdf[val] >> EC_PROB_SHIFT); | |
| v >>= 7 - EC_PROB_SHIFT; | |
| v += EC_MIN_PROB * ((unsigned)n_symbols - val); | |
| } while (c < v); | |
| assert(u <= s->rng); | |
| ctx_norm(s, s->dif - ((ec_win)v << (EC_WIN_SIZE - 16)), u - v); | |
| if (s->allow_update_cdf) { | |
| const unsigned count = cdf[n_symbols]; | |
| const unsigned rate = 4 + (count >> 4) + (n_symbols > 2); | |
| unsigned i; | |
| for (i = 0; i < val; i++) | |
| cdf[i] += (32768 - cdf[i]) >> rate; | |
| for (; i < n_symbols; i++) | |
| cdf[i] -= cdf[i] >> rate; | |
| cdf[n_symbols] = count + (count < 32); | |
| } | |
| return val; | |
| } | |
| unsigned dav1d_msac_decode_bool_adapt_c(MsacContext *const s, | |
| uint16_t *const cdf) | |
| { | |
| const unsigned bit = dav1d_msac_decode_bool(s, *cdf); | |
| if (s->allow_update_cdf) { | |
| // update_cdf() specialized for boolean CDFs | |
| const unsigned count = cdf[1]; | |
| const int rate = 4 + (count >> 4); | |
| if (bit) | |
| cdf[0] += (32768 - cdf[0]) >> rate; | |
| else | |
| cdf[0] -= cdf[0] >> rate; | |
| cdf[1] = count + (count < 32); | |
| } | |
| return bit; | |
| } | |
| unsigned dav1d_msac_decode_hi_tok_c(MsacContext *const s, uint16_t *const cdf) { | |
| unsigned tok_br = dav1d_msac_decode_symbol_adapt4(s, cdf, 3); | |
| unsigned tok = 3 + tok_br; | |
| if (tok_br == 3) { | |
| tok_br = dav1d_msac_decode_symbol_adapt4(s, cdf, 3); | |
| tok = 6 + tok_br; | |
| if (tok_br == 3) { | |
| tok_br = dav1d_msac_decode_symbol_adapt4(s, cdf, 3); | |
| tok = 9 + tok_br; | |
| if (tok_br == 3) | |
| tok = 12 + dav1d_msac_decode_symbol_adapt4(s, cdf, 3); | |
| } | |
| } | |
| return tok; | |
| } | |
| #endif | |
| void dav1d_msac_init(MsacContext *const s, const uint8_t *const data, | |
| const size_t sz, const int disable_cdf_update_flag) | |
| { | |
| s->buf_pos = data; | |
| s->buf_end = data + sz; | |
| s->dif = 0; | |
| s->rng = 0x8000; | |
| s->cnt = -15; | |
| s->allow_update_cdf = !disable_cdf_update_flag; | |
| ctx_refill(s); | |
| #if ARCH_X86_64 && HAVE_ASM | |
| s->symbol_adapt16 = dav1d_msac_decode_symbol_adapt_c; | |
| msac_init_x86(s); | |
| #endif | |
| } |