blob: 353acf1a9416d91546bd66ec9e0aff9c9409115e [file] [log] [blame]
Alex Converse7fe2ae82016-09-28 11:33:20 -07001/*
2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3 *
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.
10 */
11
12#ifndef AOM_DSP_ANSWRITER_H_
13#define AOM_DSP_ANSWRITER_H_
Alex Conversec54692b2017-01-25 16:41:05 -080014// An implementation of Asymmetric Numeral Systems
Alex Converse7fe2ae82016-09-28 11:33:20 -070015// http://arxiv.org/abs/1311.2540v2
Alex Conversec54692b2017-01-25 16:41:05 -080016// Implements encoding of:
17// * rABS (range Asymmetric Binary Systems), a boolean coder
18// * rANS (range Asymmetric Numeral Systems), a multi-symbol coder
Alex Converse7fe2ae82016-09-28 11:33:20 -070019
20#include <assert.h>
21#include "./aom_config.h"
22#include "aom/aom_integer.h"
23#include "aom_dsp/ans.h"
24#include "aom_dsp/prob.h"
25#include "aom_ports/mem_ops.h"
Alex Converse64e2f102016-06-28 13:46:19 -070026#include "av1/common/odintrin.h"
Alex Converse7fe2ae82016-09-28 11:33:20 -070027
Alex Converse64e2f102016-06-28 13:46:19 -070028#if RANS_PRECISION <= OD_DIVU_DMAX
29#define ANS_DIVREM(quotient, remainder, dividend, divisor) \
30 do { \
31 quotient = OD_DIVU_SMALL((dividend), (divisor)); \
32 remainder = (dividend) - (quotient) * (divisor); \
33 } while (0)
34#else
35#define ANS_DIVREM(quotient, remainder, dividend, divisor) \
36 do { \
37 quotient = (dividend) / (divisor); \
38 remainder = (dividend) % (divisor); \
39 } while (0)
40#endif
41
42#define ANS_DIV8(dividend, divisor) OD_DIVU_SMALL((dividend), (divisor))
Alex Converse7fe2ae82016-09-28 11:33:20 -070043
44#ifdef __cplusplus
45extern "C" {
46#endif // __cplusplus
47
48struct AnsCoder {
49 uint8_t *buf;
50 int buf_offset;
51 uint32_t state;
52};
53
54static INLINE void ans_write_init(struct AnsCoder *const ans,
55 uint8_t *const buf) {
56 ans->buf = buf;
57 ans->buf_offset = 0;
58 ans->state = L_BASE;
59}
60
61static INLINE int ans_write_end(struct AnsCoder *const ans) {
62 uint32_t state;
Alex Converseb0bbd602016-10-21 14:15:06 -070063 int ans_size;
Alex Converse7fe2ae82016-09-28 11:33:20 -070064 assert(ans->state >= L_BASE);
65 assert(ans->state < L_BASE * IO_BASE);
66 state = ans->state - L_BASE;
Alex Conversefa9c9d12016-11-04 14:06:06 -070067 if (state < (1u << 15)) {
68 mem_put_le16(ans->buf + ans->buf_offset, (0x00u << 15) + state);
Alex Converseb0bbd602016-10-21 14:15:06 -070069 ans_size = ans->buf_offset + 2;
70#if ANS_REVERSE
Alex Converse822513c2017-01-25 16:41:46 -080071#if L_BASE * IO_BASE > (1 << 23)
72 } else if (state < (1u << 22)) {
73 mem_put_le24(ans->buf + ans->buf_offset, (0x02u << 22) + state);
74 ans_size = ans->buf_offset + 3;
75 } else if (state < (1u << 30)) {
76 mem_put_le32(ans->buf + ans->buf_offset, (0x03u << 30) + state);
77 ans_size = ans->buf_offset + 4;
78#else
Alex Converseb0bbd602016-10-21 14:15:06 -070079 } else if (state < (1u << 23)) {
80 mem_put_le24(ans->buf + ans->buf_offset, (0x01u << 23) + state);
81 ans_size = ans->buf_offset + 3;
Alex Converse822513c2017-01-25 16:41:46 -080082#endif
Alex Converseb0bbd602016-10-21 14:15:06 -070083#else
Alex Conversefa9c9d12016-11-04 14:06:06 -070084 } else if (state < (1u << 22)) {
85 mem_put_le24(ans->buf + ans->buf_offset, (0x02u << 22) + state);
Alex Converseb0bbd602016-10-21 14:15:06 -070086 ans_size = ans->buf_offset + 3;
Alex Conversefa9c9d12016-11-04 14:06:06 -070087 } else if (state < (1u << 29)) {
88 mem_put_le32(ans->buf + ans->buf_offset, (0x07u << 29) + state);
Alex Converseb0bbd602016-10-21 14:15:06 -070089 ans_size = ans->buf_offset + 4;
90#endif
Alex Converse7fe2ae82016-09-28 11:33:20 -070091 } else {
92 assert(0 && "State is too large to be serialized");
93 return ans->buf_offset;
94 }
Alex Converseb0bbd602016-10-21 14:15:06 -070095#if ANS_REVERSE
96 {
97 int i;
98 uint8_t tmp;
99 for (i = 0; i < (ans_size >> 1); i++) {
100 tmp = ans->buf[i];
101 ans->buf[i] = ans->buf[ans_size - 1 - i];
102 ans->buf[ans_size - 1 - i] = tmp;
103 }
Alex Converseb0be6412016-11-30 15:51:50 -0800104 ans->buf += ans_size;
105 ans->buf_offset = 0;
106 ans->state = L_BASE;
Alex Converseb0bbd602016-10-21 14:15:06 -0700107 }
108#endif
109 return ans_size;
Alex Converse7fe2ae82016-09-28 11:33:20 -0700110}
111
Alex Conversec54692b2017-01-25 16:41:05 -0800112// Write one boolean using rABS where p0 is the probability of the value being
113// zero.
114static INLINE void rabs_write(struct AnsCoder *ans, int value, AnsP8 p0) {
115 const AnsP8 p = ANS_P8_PRECISION - p0;
116 const unsigned l_s = value ? p : p0;
117 unsigned state = ans->state;
118 while (state >= L_BASE / ANS_P8_PRECISION * IO_BASE * l_s) {
119 ans->buf[ans->buf_offset++] = state % IO_BASE;
120 state /= IO_BASE;
Alex Converse7fe2ae82016-09-28 11:33:20 -0700121 }
Alex Conversec54692b2017-01-25 16:41:05 -0800122 const unsigned quotient = ANS_DIV8(state, l_s);
123 const unsigned remainder = state - quotient * l_s;
124 ans->state = quotient * ANS_P8_PRECISION + remainder + (value ? p0 : 0);
Alex Converse7fe2ae82016-09-28 11:33:20 -0700125}
126
Alex Converse8c687d22017-02-07 15:55:24 -0800127// Encode one symbol using rANS.
128// cum_prob: The cumulative probability before this symbol (the offset of
129// the symbol in the symbol cycle)
130// prob: The probability of this symbol (l_s from the paper)
131// RANS_PRECISION takes the place of m from the paper.
132static INLINE void rans_write(struct AnsCoder *ans, aom_cdf_prob cum_prob,
133 aom_cdf_prob prob) {
134 unsigned quotient, remainder;
135 while (ans->state >= L_BASE / RANS_PRECISION * IO_BASE * prob) {
Alex Converse7fe2ae82016-09-28 11:33:20 -0700136 ans->buf[ans->buf_offset++] = ans->state % IO_BASE;
137 ans->state /= IO_BASE;
138 }
Alex Converse8c687d22017-02-07 15:55:24 -0800139 ANS_DIVREM(quotient, remainder, ans->state, prob);
140 ans->state = quotient * RANS_PRECISION + remainder + cum_prob;
Alex Converse7fe2ae82016-09-28 11:33:20 -0700141}
142
Alex Converse64e2f102016-06-28 13:46:19 -0700143#undef ANS_DIV8
144#undef ANS_DIVREM
Alex Converse7fe2ae82016-09-28 11:33:20 -0700145#ifdef __cplusplus
146} // extern "C"
147#endif // __cplusplus
148#endif // AOM_DSP_ANSWRITER_H_