Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder | |
3 | * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at> | |
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 | * Context Adaptive Binary Arithmetic Coder. | |
25 | */ | |
26 | ||
27 | #include <string.h> | |
28 | ||
29 | #include "libavutil/common.h" | |
30 | #include "libavutil/timer.h" | |
31 | #include "get_bits.h" | |
32 | #include "cabac.h" | |
33 | #include "cabac_functions.h" | |
34 | ||
35 | #include "cabac_tablegen.h" | |
36 | ||
37 | /** | |
38 | * | |
39 | * @param buf_size size of buf in bits | |
40 | */ | |
41 | void ff_init_cabac_encoder(CABACContext *c, uint8_t *buf, int buf_size){ | |
42 | init_put_bits(&c->pb, buf, buf_size); | |
43 | ||
44 | c->low= 0; | |
45 | c->range= 0x1FE; | |
46 | c->outstanding_count= 0; | |
47 | c->pb.bit_left++; //avoids firstBitFlag | |
48 | } | |
49 | ||
50 | /** | |
51 | * | |
52 | * @param buf_size size of buf in bits | |
53 | */ | |
54 | void ff_init_cabac_decoder(CABACContext *c, const uint8_t *buf, int buf_size){ | |
55 | c->bytestream_start= | |
56 | c->bytestream= buf; | |
57 | c->bytestream_end= buf + buf_size; | |
58 | ||
59 | #if CABAC_BITS == 16 | |
60 | c->low = (*c->bytestream++)<<18; | |
61 | c->low+= (*c->bytestream++)<<10; | |
62 | #else | |
63 | c->low = (*c->bytestream++)<<10; | |
64 | #endif | |
65 | c->low+= ((*c->bytestream++)<<2) + 2; | |
66 | c->range= 0x1FE; | |
67 | } | |
68 | ||
69 | void ff_init_cabac_states(void) | |
70 | { | |
71 | static int initialized = 0; | |
72 | ||
73 | if (initialized) | |
74 | return; | |
75 | ||
76 | cabac_tableinit(); | |
77 | ||
78 | initialized = 1; | |
79 | } | |
80 | ||
81 | #ifdef TEST | |
82 | #define SIZE 10240 | |
83 | ||
84 | #include "libavutil/lfg.h" | |
85 | #include "avcodec.h" | |
86 | ||
87 | static inline void put_cabac_bit(CABACContext *c, int b){ | |
88 | put_bits(&c->pb, 1, b); | |
89 | for(;c->outstanding_count; c->outstanding_count--){ | |
90 | put_bits(&c->pb, 1, 1-b); | |
91 | } | |
92 | } | |
93 | ||
94 | static inline void renorm_cabac_encoder(CABACContext *c){ | |
95 | while(c->range < 0x100){ | |
96 | //FIXME optimize | |
97 | if(c->low<0x100){ | |
98 | put_cabac_bit(c, 0); | |
99 | }else if(c->low<0x200){ | |
100 | c->outstanding_count++; | |
101 | c->low -= 0x100; | |
102 | }else{ | |
103 | put_cabac_bit(c, 1); | |
104 | c->low -= 0x200; | |
105 | } | |
106 | ||
107 | c->range+= c->range; | |
108 | c->low += c->low; | |
109 | } | |
110 | } | |
111 | ||
112 | static void put_cabac(CABACContext *c, uint8_t * const state, int bit){ | |
113 | int RangeLPS= ff_h264_lps_range[2*(c->range&0xC0) + *state]; | |
114 | ||
115 | if(bit == ((*state)&1)){ | |
116 | c->range -= RangeLPS; | |
117 | *state = ff_h264_mlps_state[128 + *state]; | |
118 | }else{ | |
119 | c->low += c->range - RangeLPS; | |
120 | c->range = RangeLPS; | |
121 | *state= ff_h264_mlps_state[127 - *state]; | |
122 | } | |
123 | ||
124 | renorm_cabac_encoder(c); | |
125 | } | |
126 | ||
127 | /** | |
128 | * @param bit 0 -> write zero bit, !=0 write one bit | |
129 | */ | |
130 | static void put_cabac_bypass(CABACContext *c, int bit){ | |
131 | c->low += c->low; | |
132 | ||
133 | if(bit){ | |
134 | c->low += c->range; | |
135 | } | |
136 | //FIXME optimize | |
137 | if(c->low<0x200){ | |
138 | put_cabac_bit(c, 0); | |
139 | }else if(c->low<0x400){ | |
140 | c->outstanding_count++; | |
141 | c->low -= 0x200; | |
142 | }else{ | |
143 | put_cabac_bit(c, 1); | |
144 | c->low -= 0x400; | |
145 | } | |
146 | } | |
147 | ||
148 | /** | |
149 | * | |
150 | * @return the number of bytes written | |
151 | */ | |
152 | static int put_cabac_terminate(CABACContext *c, int bit){ | |
153 | c->range -= 2; | |
154 | ||
155 | if(!bit){ | |
156 | renorm_cabac_encoder(c); | |
157 | }else{ | |
158 | c->low += c->range; | |
159 | c->range= 2; | |
160 | ||
161 | renorm_cabac_encoder(c); | |
162 | ||
163 | av_assert0(c->low <= 0x1FF); | |
164 | put_cabac_bit(c, c->low>>9); | |
165 | put_bits(&c->pb, 2, ((c->low>>7)&3)|1); | |
166 | ||
167 | flush_put_bits(&c->pb); //FIXME FIXME FIXME XXX wrong | |
168 | } | |
169 | ||
170 | return (put_bits_count(&c->pb)+7)>>3; | |
171 | } | |
172 | ||
173 | int main(void){ | |
174 | CABACContext c; | |
175 | uint8_t b[9*SIZE]; | |
176 | uint8_t r[9*SIZE]; | |
177 | int i; | |
178 | uint8_t state[10]= {0}; | |
179 | AVLFG prng; | |
180 | ||
181 | av_lfg_init(&prng, 1); | |
182 | ff_init_cabac_encoder(&c, b, SIZE); | |
183 | ff_init_cabac_states(); | |
184 | ||
185 | for(i=0; i<SIZE; i++){ | |
186 | if(2*i<SIZE) r[i] = av_lfg_get(&prng) % 7; | |
187 | else r[i] = (i>>8)&1; | |
188 | } | |
189 | ||
190 | for(i=0; i<SIZE; i++){ | |
191 | START_TIMER | |
192 | put_cabac_bypass(&c, r[i]&1); | |
193 | STOP_TIMER("put_cabac_bypass") | |
194 | } | |
195 | ||
196 | for(i=0; i<SIZE; i++){ | |
197 | START_TIMER | |
198 | put_cabac(&c, state, r[i]&1); | |
199 | STOP_TIMER("put_cabac") | |
200 | } | |
201 | ||
202 | put_cabac_terminate(&c, 1); | |
203 | ||
204 | ff_init_cabac_decoder(&c, b, SIZE); | |
205 | ||
206 | memset(state, 0, sizeof(state)); | |
207 | ||
208 | for(i=0; i<SIZE; i++){ | |
209 | START_TIMER | |
210 | if( (r[i]&1) != get_cabac_bypass(&c) ) | |
211 | av_log(NULL, AV_LOG_ERROR, "CABAC bypass failure at %d\n", i); | |
212 | STOP_TIMER("get_cabac_bypass") | |
213 | } | |
214 | ||
215 | for(i=0; i<SIZE; i++){ | |
216 | START_TIMER | |
217 | if( (r[i]&1) != get_cabac_noinline(&c, state) ) | |
218 | av_log(NULL, AV_LOG_ERROR, "CABAC failure at %d\n", i); | |
219 | STOP_TIMER("get_cabac") | |
220 | } | |
221 | if(!get_cabac_terminate(&c)) | |
222 | av_log(NULL, AV_LOG_ERROR, "where's the Terminator?\n"); | |
223 | ||
224 | return 0; | |
225 | } | |
226 | ||
227 | #endif /* TEST */ |