Commit c54692b5 authored by Alex Converse's avatar Alex Converse

ans: Switch from uABS to rABS

This is in preparation for expanding the state range.

No discernible compression impact

ans_multioff@2017-01-25T20:58:18.756Z -> ans_multioff_rabs@2017-01-26T01:05:12.801Z

     PSNR | PSNR Cb | PSNR Cr | PSNR HVS |    SSIM | MS SSIM | CIEDE 2000
  -0.0001 | -0.0001 | -0.0001 |  -0.0001 | -0.0001 | -0.0001 | -0.0001

https://arewecompressedyet.com/?job=ans_multioff%402017-01-25T20%3A58%3A18.756Z&job=ans_multioff_rabs%402017-01-26T01%3A05%3A12.801Z

Change-Id: Ie1817991190f1de6d9c31e0c97f77efbd5869d35
parent e2746e30
......@@ -11,8 +11,11 @@
#ifndef AOM_DSP_ANSREADER_H_
#define AOM_DSP_ANSREADER_H_
// A uABS and rANS decoder implementation of Asymmetric Numeral Systems
// An implementation of Asymmetric Numeral Systems
// http://arxiv.org/abs/1311.2540v2
// Implements decoding of:
// * rABS (range Asymmetric Binary Systems), a boolean coder
// * rANS (range Asymmetric Numeral Systems), a multi-symbol coder
#include <assert.h>
#include "./aom_config.h"
......@@ -57,43 +60,33 @@ static INLINE unsigned refill_state(struct AnsDecoder *const ans,
return state;
}
static INLINE int uabs_read(struct AnsDecoder *ans, AnsP8 p0) {
AnsP8 p = ANS_P8_PRECISION - p0;
int s;
unsigned xp, sp;
unsigned state;
// Decode one rABS encoded boolean where the probability of the value being zero
// is p0.
static INLINE int rabs_read(struct AnsDecoder *ans, AnsP8 p0) {
#if ANS_MAX_SYMBOLS
if (ans->symbols_left-- == 0) {
ans_read_reinit(ans);
ans->symbols_left--;
}
#endif
state = ans->state;
sp = state * p;
xp = sp / ANS_P8_PRECISION;
s = (sp & 0xFF) >= p0;
if (s)
state = xp;
unsigned state = ans->state;
const unsigned quotient = state / ANS_P8_PRECISION;
const unsigned remainder = state % ANS_P8_PRECISION;
const int value = remainder >= p0;
if (value)
state = quotient * (ANS_P8_PRECISION - p0) + remainder - p0;
else
state -= xp;
state = quotient * p0 + remainder;
ans->state = refill_state(ans, state);
return s;
return value;
}
static INLINE int uabs_read_bit(struct AnsDecoder *ans) {
int s;
unsigned state;
#if ANS_MAX_SYMBOLS
if (ans->symbols_left-- == 0) {
ans_read_reinit(ans);
ans->symbols_left--;
}
#endif
state = ans->state;
s = (int)(state & 1);
state >>= 1;
ans->state = refill_state(ans, state);
return s;
// Decode one rABS encoded boolean where the probability of the value being zero
// is one half.
static INLINE int rabs_read_bit(struct AnsDecoder *ans) {
// TODO(aconverse@google.com): Provide an optimized implementation of this
// routine.
return rabs_read(ans, 128);
}
struct rans_dec_sym {
......
......@@ -11,8 +11,11 @@
#ifndef AOM_DSP_ANSWRITER_H_
#define AOM_DSP_ANSWRITER_H_
// A uABS and rANS encoder implementation of Asymmetric Numeral Systems
// An implementation of Asymmetric Numeral Systems
// http://arxiv.org/abs/1311.2540v2
// Implements encoding of:
// * rABS (range Asymmetric Binary Systems), a boolean coder
// * rANS (range Asymmetric Numeral Systems), a multi-symbol coder
#include <assert.h>
#include "./aom_config.h"
......@@ -106,18 +109,19 @@ static INLINE int ans_write_end(struct AnsCoder *const ans) {
return ans_size;
}
// uABS with normalization
static INLINE void uabs_write(struct AnsCoder *ans, int val, AnsP8 p0) {
AnsP8 p = ANS_P8_PRECISION - p0;
const unsigned l_s = val ? p : p0;
while (ans->state >= L_BASE / ANS_P8_PRECISION * IO_BASE * l_s) {
ans->buf[ans->buf_offset++] = ans->state % IO_BASE;
ans->state /= IO_BASE;
// Write one boolean using rABS where p0 is the probability of the value being
// zero.
static INLINE void rabs_write(struct AnsCoder *ans, int value, AnsP8 p0) {
const AnsP8 p = ANS_P8_PRECISION - p0;
const unsigned l_s = value ? p : p0;
unsigned state = ans->state;
while (state >= L_BASE / ANS_P8_PRECISION * IO_BASE * l_s) {
ans->buf[ans->buf_offset++] = state % IO_BASE;
state /= IO_BASE;
}
if (!val)
ans->state = ANS_DIV8(ans->state * ANS_P8_PRECISION, p0);
else
ans->state = ANS_DIV8((ans->state + 1) * ANS_P8_PRECISION + p - 1, p) - 1;
const unsigned quotient = ANS_DIV8(state, l_s);
const unsigned remainder = state - quotient * l_s;
ans->state = quotient * ANS_P8_PRECISION + remainder + (value ? p0 : 0);
}
struct rans_sym {
......
......@@ -151,7 +151,7 @@ static INLINE void aom_process_accounting(const aom_reader *r ACCT_STR_PARAM) {
static INLINE int aom_read_(aom_reader *r, int prob ACCT_STR_PARAM) {
int ret;
#if CONFIG_ANS
ret = uabs_read(r, prob);
ret = rabs_read(r, prob);
#elif CONFIG_DAALA_EC
ret = aom_daala_read(r, prob);
#else
......@@ -166,7 +166,7 @@ static INLINE int aom_read_(aom_reader *r, int prob ACCT_STR_PARAM) {
static INLINE int aom_read_bit_(aom_reader *r ACCT_STR_PARAM) {
int ret;
#if CONFIG_ANS
ret = uabs_read_bit(r); // Non trivial optimization at half probability
ret = rabs_read_bit(r); // Non trivial optimization at half probability
#elif CONFIG_DAALA_EC
// Note this uses raw bits and is not the same as aom_daala_read(r, 128);
ret = aom_daala_read_bit(r);
......
......@@ -92,7 +92,7 @@ static INLINE void aom_stop_encode(aom_writer *bc) {
static INLINE void aom_write(aom_writer *br, int bit, int probability) {
#if CONFIG_ANS
buf_uabs_write(br, bit, probability);
buf_rabs_write(br, bit, probability);
#elif CONFIG_DAALA_EC
// Note this uses raw bits and is not the same as aom_daala_write(r, 128);
aom_daala_write(br, bit, probability);
......@@ -113,7 +113,7 @@ static INLINE void aom_write_record(aom_writer *br, int bit, int probability,
static INLINE void aom_write_bit(aom_writer *w, int bit) {
#if CONFIG_ANS
buf_uabs_write_bit(w, bit);
buf_rabs_write_bit(w, bit);
#elif CONFIG_DAALA_EC
aom_daala_write_bit(w, bit);
#else
......
......@@ -57,7 +57,7 @@ void aom_buf_ans_flush(struct BufAnsCoder *const c) {
sym.cum_prob = c->buf[offset].val_start;
rans_write(&c->ans, &sym);
} else {
uabs_write(&c->ans, (uint8_t)c->buf[offset].val_start,
rabs_write(&c->ans, (uint8_t)c->buf[offset].val_start,
(AnsP8)c->buf[offset].prob);
}
}
......
......@@ -25,11 +25,11 @@
extern "C" {
#endif // __cplusplus
#define ANS_METHOD_UABS 0
#define ANS_METHOD_RABS 0
#define ANS_METHOD_RANS 1
struct buffered_ans_symbol {
unsigned int method : 1; // one of ANS_METHOD_UABS or ANS_METHOD_RANS
unsigned int method : 1; // one of ANS_METHOD_RABS or ANS_METHOD_RANS
// TODO(aconverse): Should be possible to write this in terms of start for ABS
unsigned int val_start : RANS_PROB_BITS; // Boolean value for ABS
// start in symbol cycle for Rans
......@@ -71,7 +71,7 @@ static INLINE void buf_ans_write_init(struct BufAnsCoder *const c,
ans_write_init(&c->ans, output_buffer);
}
static INLINE void buf_uabs_write(struct BufAnsCoder *const c, uint8_t val,
static INLINE void buf_rabs_write(struct BufAnsCoder *const c, uint8_t val,
AnsP8 prob) {
assert(c->offset <= c->size);
#if !ANS_MAX_SYMBOLS
......@@ -79,7 +79,7 @@ static INLINE void buf_uabs_write(struct BufAnsCoder *const c, uint8_t val,
aom_buf_ans_grow(c);
}
#endif
c->buf[c->offset].method = ANS_METHOD_UABS;
c->buf[c->offset].method = ANS_METHOD_RABS;
c->buf[c->offset].val_start = val;
c->buf[c->offset].prob = prob;
++c->offset;
......@@ -105,17 +105,17 @@ static INLINE void buf_rans_write(struct BufAnsCoder *const c,
#endif
}
static INLINE void buf_uabs_write_bit(struct BufAnsCoder *c, int bit) {
buf_uabs_write(c, bit, 128);
static INLINE void buf_rabs_write_bit(struct BufAnsCoder *c, int bit) {
buf_rabs_write(c, bit, 128);
}
static INLINE void buf_uabs_write_literal(struct BufAnsCoder *c, int literal,
static INLINE void buf_rabs_write_literal(struct BufAnsCoder *c, int literal,
int bits) {
int bit;
assert(bits < 31);
for (bit = bits - 1; bit >= 0; bit--)
buf_uabs_write_bit(c, 1 & (literal >> bit));
buf_rabs_write_bit(c, 1 & (literal >> bit));
}
static INLINE int buf_ans_write_end(struct BufAnsCoder *const c) {
......
......@@ -49,14 +49,14 @@ PvVec abs_encode_build_vals(int iters) {
return ret;
}
bool check_uabs(const PvVec &pv_vec, uint8_t *buf) {
bool check_rabs(const PvVec &pv_vec, uint8_t *buf) {
BufAnsCoder a;
aom_buf_ans_alloc(&a, NULL, kBufAnsSize);
buf_ans_write_init(&a, buf);
std::clock_t start = std::clock();
for (PvVec::const_iterator it = pv_vec.begin(); it != pv_vec.end(); ++it) {
buf_uabs_write(&a, it->second, 256 - it->first);
buf_rabs_write(&a, it->second, 256 - it->first);
}
aom_buf_ans_flush(&a);
std::clock_t enc_time = std::clock() - start;
......@@ -70,7 +70,7 @@ bool check_uabs(const PvVec &pv_vec, uint8_t *buf) {
if (ans_read_init(&d, buf, offset)) return false;
start = std::clock();
for (PvVec::const_iterator it = pv_vec.begin(); it != pv_vec.end(); ++it) {
okay = okay && (uabs_read(&d, 256 - it->first) != 0) == it->second;
okay = okay && (rabs_read(&d, 256 - it->first) != 0) == it->second;
}
std::clock_t dec_time = std::clock() - start;
if (!okay) return false;
......@@ -180,7 +180,7 @@ class AnsTestFix : public ::testing::Test {
std::vector<int> AnsTestFix::sym_vec_;
rans_sym AnsTestFix::rans_sym_tab_[kRansSymbols];
TEST_F(AbsTestFix, Uabs) { EXPECT_TRUE(check_uabs(pv_vec_, buf_)); }
TEST_F(AbsTestFix, Rabs) { EXPECT_TRUE(check_rabs(pv_vec_, buf_)); }
TEST_F(AnsTestFix, Rans) {
EXPECT_TRUE(check_rans(sym_vec_, rans_sym_tab_, buf_));
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment