blob: e0a806755514ce031fca3846acf8570bbf2f56a7 [file] [log] [blame] [edit]
/*
* Copyright (c) 2021, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 3-Clause Clear License
* and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
* License was not distributed with this source code in the LICENSE file, you
* can obtain it at aomedia.org/license/software-license/bsd-3-c-c/. If the
* Alliance for Open Media Patent License 1.0 was not distributed with this
* source code in the PATENTS file, you can obtain it at
* aomedia.org/license/patent-license/.
*/
#ifndef AOM_AOM_DSP_ENTDEC_H_
#define AOM_AOM_DSP_ENTDEC_H_
#include <limits.h>
#include "aom_dsp/entcode.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Minimum # of preloaded bits to maintain in od_ec_window. */
#define OD_EC_MIN_BITS 8
typedef struct od_ec_dec od_ec_dec;
#if defined(OD_ACCOUNTING) && OD_ACCOUNTING
#define OD_ACC_STR , char *acc_str
#define od_ec_dec_bits(dec, ftb, str) od_ec_dec_bits_(dec, ftb, str)
#else
#define OD_ACC_STR
#define od_ec_dec_bits(dec, ftb, str) od_ec_dec_bits_(dec, ftb)
#endif
/*The entropy decoder context.*/
struct od_ec_dec {
/*The start of the current input buffer.*/
const unsigned char *buf;
/*An offset used to keep track of tell after reaching the end of the stream.
This is constant throughout most of the decoding process, but becomes
important once we hit the end of the buffer and stop incrementing bptr
(and instead pretend cnt has lots of bits).*/
int32_t tell_offs;
/*The end of the current input buffer.*/
const unsigned char *end;
/*The read pointer for the entropy-coded bits.*/
const unsigned char *bptr;
/*The difference between the high end of the current range, (low + rng), and
the coded value, minus 1.
This stores up to OD_EC_WINDOW_SIZE bits of that difference, but the
decoder only uses the top 16 bits of the window to decode the next symbol.
As we shift up during renormalization, if we don't have enough bits left in
the window to fill the top 16, we'll read in more bits of the coded
value.*/
od_ec_window dif;
/*The number of values in the current range.*/
uint16_t rng;
/*The number of bits of data in the current value.*/
int16_t cnt;
};
/*See entdec.c for further documentation.*/
void od_ec_dec_init(od_ec_dec *dec, const unsigned char *buf, uint32_t storage)
OD_ARG_NONNULL(1) OD_ARG_NONNULL(2);
OD_WARN_UNUSED_RESULT int od_ec_decode_bool_bypass(od_ec_dec *dec)
OD_ARG_NONNULL(1);
OD_WARN_UNUSED_RESULT int od_ec_decode_literal_bypass(od_ec_dec *dec,
int n_bits)
OD_ARG_NONNULL(1);
OD_WARN_UNUSED_RESULT int od_ec_decode_unary_bypass(od_ec_dec *dec,
int max_bits)
OD_ARG_NONNULL(1);
OD_WARN_UNUSED_RESULT int od_ec_decode_bool_q15(od_ec_dec *dec, unsigned f)
OD_ARG_NONNULL(1);
OD_WARN_UNUSED_RESULT uint32_t od_ec_dec_bits_(od_ec_dec *dec, unsigned ftb)
OD_ARG_NONNULL(1);
OD_WARN_UNUSED_RESULT int od_ec_dec_tell(const od_ec_dec *dec)
OD_ARG_NONNULL(1);
OD_WARN_UNUSED_RESULT uint64_t od_ec_dec_tell_frac(const od_ec_dec *dec)
OD_ARG_NONNULL(1);
/*This is meant to be a large, positive constant that can still be efficiently
loaded as an immediate (on platforms like ARM, for example).
Even relatively modest values like 100 would work fine.*/
#define OD_EC_LOTS_OF_BITS (0x4000)
/*The return value of od_ec_dec_tell does not change across an od_ec_dec_refill
call.*/
static void od_ec_dec_refill(od_ec_dec *dec) {
int s;
od_ec_window dif;
int16_t cnt;
const unsigned char *bptr;
const unsigned char *end;
dif = dec->dif;
cnt = dec->cnt;
bptr = dec->bptr;
end = dec->end;
s = OD_EC_WINDOW_SIZE - 9 - (cnt + 15);
for (; s >= 0 && bptr < end; s -= 8, bptr++) {
/*Each time a byte is inserted into the window (dif), bptr advances and cnt
is incremented by 8, so the total number of consumed bits (the return
value of od_ec_dec_tell) does not change.*/
assert(s <= OD_EC_WINDOW_SIZE - 8);
dif ^= (od_ec_window)bptr[0] << s;
cnt += 8;
}
if (bptr >= end) {
/*We've reached the end of the buffer. It is perfectly valid for us to need
to fill the window with additional bits past the end of the buffer (and
this happens in normal operation). These bits should all just be taken
as zero. But we cannot increment bptr past 'end' (this is undefined
behavior), so we start to increment dec->tell_offs. We also don't want
to keep testing bptr against 'end', so we set cnt to OD_EC_LOTS_OF_BITS
and adjust dec->tell_offs so that the total number of unconsumed bits in
the window (dec->cnt - dec->tell_offs) does not change. This effectively
puts lots of zero bits into the window, and means we won't try to refill
it from the buffer for a very long time (at which point we'll put lots
of zero bits into the window again).*/
dec->tell_offs += OD_EC_LOTS_OF_BITS - cnt;
cnt = OD_EC_LOTS_OF_BITS;
}
dec->dif = dif;
dec->cnt = cnt;
dec->bptr = bptr;
}
/*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.
ret: The value to return.
Return: ret.
This allows the compiler to jump to this function via a tail-call.*/
static INLINE int od_ec_dec_normalize(od_ec_dec *dec, od_ec_window dif,
unsigned rng, int ret) {
int d;
assert(rng <= 65535U);
/*The number of leading zeros in the 16-bit binary representation of rng.*/
d = 16 - OD_ILOG_NZ(rng);
/*d bits in dec->dif are consumed.*/
dec->cnt -= d;
/*This is equivalent to shifting in 1's instead of 0's.*/
dec->dif = ((dif + 1) << d) - 1;
dec->rng = rng << d;
if (dec->cnt < OD_EC_MIN_BITS) od_ec_dec_refill(dec);
return ret;
}
/* This function performs renormalization after decoding bypass symbols.
This is a simplified version of od_ec_dec_normalize(), as bypass
symbol decoding only requires shifting in new bits, and the range
value remains unchanged. */
static INLINE int od_ec_dec_bypass_normalize(od_ec_dec *dec, od_ec_window dif,
int n_bypass, int ret) {
/*n_bypass bits in dec->dif are consumed.*/
dec->cnt -= n_bypass;
/*This is equivalent to shifting in 1's instead of 0's.*/
dec->dif = ((dif + 1) << n_bypass) - 1;
if (dec->cnt < OD_EC_MIN_BITS) od_ec_dec_refill(dec);
return ret;
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // AOM_AOM_DSP_ENTDEC_H_