Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Copyright (C) 2007 Marco Gerards <marco@gnu.org> | |
3 | * Copyright (C) 2009 David Conrad | |
4 | * | |
5 | * This file is part of FFmpeg. | |
6 | * | |
7 | * FFmpeg is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * FFmpeg is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with FFmpeg; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | */ | |
21 | ||
22 | /** | |
23 | * @file | |
24 | * Arithmetic decoder for Dirac | |
25 | * @author Marco Gerards <marco@gnu.org> | |
26 | */ | |
27 | ||
28 | #ifndef AVCODEC_DIRAC_ARITH_H | |
29 | #define AVCODEC_DIRAC_ARITH_H | |
30 | ||
31 | #include "libavutil/x86/asm.h" | |
32 | #include "bytestream.h" | |
33 | #include "get_bits.h" | |
34 | ||
35 | enum dirac_arith_contexts { | |
36 | CTX_ZPZN_F1, | |
37 | CTX_ZPNN_F1, | |
38 | CTX_NPZN_F1, | |
39 | CTX_NPNN_F1, | |
40 | CTX_ZP_F2, | |
41 | CTX_ZP_F3, | |
42 | CTX_ZP_F4, | |
43 | CTX_ZP_F5, | |
44 | CTX_ZP_F6, | |
45 | CTX_NP_F2, | |
46 | CTX_NP_F3, | |
47 | CTX_NP_F4, | |
48 | CTX_NP_F5, | |
49 | CTX_NP_F6, | |
50 | CTX_COEFF_DATA, | |
51 | CTX_SIGN_NEG, | |
52 | CTX_SIGN_ZERO, | |
53 | CTX_SIGN_POS, | |
54 | CTX_ZERO_BLOCK, | |
55 | CTX_DELTA_Q_F, | |
56 | CTX_DELTA_Q_DATA, | |
57 | CTX_DELTA_Q_SIGN, | |
58 | ||
59 | DIRAC_CTX_COUNT | |
60 | }; | |
61 | ||
62 | // Dirac resets the arith decoder between decoding various types of data, | |
63 | // so many contexts are never used simultaneously. Thus, we can reduce | |
64 | // the number of contexts needed by reusing them. | |
65 | #define CTX_SB_F1 CTX_ZP_F5 | |
66 | #define CTX_SB_DATA 0 | |
67 | #define CTX_PMODE_REF1 0 | |
68 | #define CTX_PMODE_REF2 1 | |
69 | #define CTX_GLOBAL_BLOCK 2 | |
70 | #define CTX_MV_F1 CTX_ZP_F2 | |
71 | #define CTX_MV_DATA 0 | |
72 | #define CTX_DC_F1 CTX_ZP_F5 | |
73 | #define CTX_DC_DATA 0 | |
74 | ||
75 | typedef struct { | |
76 | unsigned low; | |
77 | uint16_t range; | |
78 | int16_t counter; | |
79 | ||
80 | const uint8_t *bytestream; | |
81 | const uint8_t *bytestream_end; | |
82 | ||
83 | uint16_t contexts[DIRAC_CTX_COUNT]; | |
84 | } DiracArith; | |
85 | ||
86 | extern const uint8_t ff_dirac_next_ctx[DIRAC_CTX_COUNT]; | |
87 | extern const uint16_t ff_dirac_prob[256]; | |
88 | extern int16_t ff_dirac_prob_branchless[256][2]; | |
89 | ||
90 | static inline void renorm(DiracArith *c) | |
91 | { | |
92 | #if HAVE_FAST_CLZ | |
93 | int shift = 14 - av_log2_16bit(c->range-1) + ((c->range-1)>>15); | |
94 | ||
95 | c->low <<= shift; | |
96 | c->range <<= shift; | |
97 | c->counter += shift; | |
98 | #else | |
99 | while (c->range <= 0x4000) { | |
100 | c->low <<= 1; | |
101 | c->range <<= 1; | |
102 | c->counter++; | |
103 | } | |
104 | #endif | |
105 | } | |
106 | ||
107 | static inline void refill(DiracArith *c) | |
108 | { | |
109 | int counter = c->counter; | |
110 | ||
111 | if (counter >= 0) { | |
112 | int new = bytestream_get_be16(&c->bytestream); | |
113 | ||
114 | // the spec defines overread bits to be 1, and streams rely on this | |
115 | if (c->bytestream > c->bytestream_end) { | |
116 | new |= 0xff; | |
117 | if (c->bytestream > c->bytestream_end+1) | |
118 | new |= 0xff00; | |
119 | ||
120 | c->bytestream = c->bytestream_end; | |
121 | } | |
122 | ||
123 | c->low += new << counter; | |
124 | counter -= 16; | |
125 | } | |
126 | c->counter = counter; | |
127 | } | |
128 | ||
129 | static inline int dirac_get_arith_bit(DiracArith *c, int ctx) | |
130 | { | |
131 | int prob_zero = c->contexts[ctx]; | |
132 | int range_times_prob, bit; | |
133 | unsigned low = c->low; | |
134 | int range = c->range; | |
135 | ||
136 | range_times_prob = (c->range * prob_zero) >> 16; | |
137 | ||
f6fa7814 | 138 | #if ARCH_X86 && HAVE_FAST_CMOV && HAVE_INLINE_ASM && HAVE_6REGS |
2ba45a60 DM |
139 | low -= range_times_prob << 16; |
140 | range -= range_times_prob; | |
141 | bit = 0; | |
142 | __asm__( | |
143 | "cmpl %5, %4 \n\t" | |
144 | "setae %b0 \n\t" | |
145 | "cmovb %3, %2 \n\t" | |
146 | "cmovb %5, %1 \n\t" | |
147 | : "+q"(bit), "+r"(range), "+r"(low) | |
148 | : "r"(c->low), "r"(c->low>>16), | |
149 | "r"(range_times_prob) | |
150 | ); | |
151 | #else | |
152 | bit = (low >> 16) >= range_times_prob; | |
153 | if (bit) { | |
154 | low -= range_times_prob << 16; | |
155 | range -= range_times_prob; | |
156 | } else { | |
157 | range = range_times_prob; | |
158 | } | |
159 | #endif | |
160 | ||
161 | c->contexts[ctx] += ff_dirac_prob_branchless[prob_zero>>8][bit]; | |
162 | c->low = low; | |
163 | c->range = range; | |
164 | ||
165 | renorm(c); | |
166 | refill(c); | |
167 | return bit; | |
168 | } | |
169 | ||
170 | static inline int dirac_get_arith_uint(DiracArith *c, int follow_ctx, int data_ctx) | |
171 | { | |
172 | int ret = 1; | |
173 | while (!dirac_get_arith_bit(c, follow_ctx)) { | |
174 | if (ret >= 0x40000000) { | |
175 | av_log(NULL, AV_LOG_ERROR, "dirac_get_arith_uint overflow\n"); | |
176 | return -1; | |
177 | } | |
178 | ret <<= 1; | |
179 | ret += dirac_get_arith_bit(c, data_ctx); | |
180 | follow_ctx = ff_dirac_next_ctx[follow_ctx]; | |
181 | } | |
182 | return ret-1; | |
183 | } | |
184 | ||
185 | static inline int dirac_get_arith_int(DiracArith *c, int follow_ctx, int data_ctx) | |
186 | { | |
187 | int ret = dirac_get_arith_uint(c, follow_ctx, data_ctx); | |
188 | if (ret && dirac_get_arith_bit(c, data_ctx+1)) | |
189 | ret = -ret; | |
190 | return ret; | |
191 | } | |
192 | ||
193 | void ff_dirac_init_arith_decoder(DiracArith *c, GetBitContext *gb, int length); | |
194 | ||
195 | #endif /* AVCODEC_DIRAC_ARITH_H */ |