History

lavc: add standalone cached bitstream reader

The cached bitstream reader was originally written by Alexandra Hájková for Libav, with significant input from Kostya Shishkov and Luca Barbato. It was then committed to FFmpeg in ca079b09549, by merging it with the implementation of the current bitstream reader. This merge makes the code of get_bits.h significantly harder to read, since it now contains two different bitstream readers interleaved with #ifdefs. Additionally, the code was committed without proper authorship attribution. This commit re-adds the cached bitstream reader as a standalone header, as it was originally developed. It will be made useful in following commits. Integration by Anton Khirnov.

Alexandra Hájková committed 10 years ago

Commit 8fe551e1 parent 4b2b9a61 file · +529 −0Browse files

Unified · Split

libavcodec/bitstream.h+529−0
@@ -0,0 +1,529 @@
1/*
2 * Copyright (c) 2016 Alexandra Hájková
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * bitstream reader API header.
24 */
25
26#ifndef AVCODEC_BITSTREAM_H
27#define AVCODEC_BITSTREAM_H
28
29#include <stdint.h>
30
31#include "config.h"
32
33#include "libavutil/avassert.h"
34#include "libavutil/common.h"
35#include "libavutil/intreadwrite.h"
36#include "libavutil/log.h"
37
38#include "mathops.h"
39#include "vlc.h"
40
41#ifndef UNCHECKED_BITSTREAM_READER
42#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER
43#endif
44
45typedef struct BitstreamContext {
46 uint64_t bits; // stores bits read from the buffer
47 const uint8_t *buffer, *buffer_end;
48 const uint8_t *ptr; // pointer to the position inside a buffer
49 unsigned bits_valid; // number of bits left in bits field
50 unsigned size_in_bits;
51} BitstreamContext;
52
53/**
54 * @return
55 * - 0 on successful refill
56 * - a negative number when bitstream end is hit
57 *
58 * Always succeeds when UNCHECKED_BITSTREAM_READER is enabled.
59 */
60static inline int bits_priv_refill_64(BitstreamContext *bc)
61{
62#if !UNCHECKED_BITSTREAM_READER
63 if (bc->ptr >= bc->buffer_end)
64 return -1;
65#endif
66
67#ifdef BITSTREAM_READER_LE
68 bc->bits = AV_RL64(bc->ptr);
69#else
70 bc->bits = AV_RB64(bc->ptr);
71#endif
72 bc->ptr += 8;
73 bc->bits_valid = 64;
74
75 return 0;
76}
77
78/**
79 * @return
80 * - 0 on successful refill
81 * - a negative number when bitstream end is hit
82 *
83 * Always succeeds when UNCHECKED_BITSTREAM_READER is enabled.
84 */
85static inline int bits_priv_refill_32(BitstreamContext *bc)
86{
87#if !UNCHECKED_BITSTREAM_READER
88 if (bc->ptr >= bc->buffer_end)
89 return -1;
90#endif
91
92#ifdef BITSTREAM_READER_LE
93 bc->bits |= (uint64_t)AV_RL32(bc->ptr) << bc->bits_valid;
94#else
95 bc->bits |= (uint64_t)AV_RB32(bc->ptr) << (32 - bc->bits_valid);
96#endif
97 bc->ptr += 4;
98 bc->bits_valid += 32;
99
100 return 0;
101}
102
103/**
104 * Initialize BitstreamContext.
105 * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
106 * larger than the actual read bits because some optimized bitstream
107 * readers read 32 or 64 bits at once and could read over the end
108 * @param bit_size the size of the buffer in bits
109 * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow.
110 */
111static inline int bits_init(BitstreamContext *bc, const uint8_t *buffer,
112 unsigned int bit_size)
113{
114 unsigned int buffer_size;
115
116 if (bit_size > INT_MAX - 7 || !buffer) {
117 bc->buffer = NULL;
118 bc->ptr = NULL;
119 bc->bits_valid = 0;
120 return AVERROR_INVALIDDATA;
121 }
122
123 buffer_size = (bit_size + 7) >> 3;
124
125 bc->buffer = buffer;
126 bc->buffer_end = buffer + buffer_size;
127 bc->ptr = bc->buffer;
128 bc->size_in_bits = bit_size;
129 bc->bits_valid = 0;
130 bc->bits = 0;
131
132 bits_priv_refill_64(bc);
133
134 return 0;
135}
136
137/**
138 * Initialize BitstreamContext.
139 * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
140 * larger than the actual read bits because some optimized bitstream
141 * readers read 32 or 64 bits at once and could read over the end
142 * @param byte_size the size of the buffer in bytes
143 * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow
144 */
145static inline int bits_init8(BitstreamContext *bc, const uint8_t *buffer,
146 unsigned int byte_size)
147{
148 if (byte_size > INT_MAX / 8)
149 return AVERROR_INVALIDDATA;
150 return bits_init(bc, buffer, byte_size * 8);
151}
152
153/**
154 * Return number of bits already read.
155 */
156static inline int bits_tell(const BitstreamContext *bc)
157{
158 return (bc->ptr - bc->buffer) * 8 - bc->bits_valid;
159}
160
161/**
162 * Return buffer size in bits.
163 */
164static inline int bits_size(const BitstreamContext *bc)
165{
166 return bc->size_in_bits;
167}
168
169/**
170 * Return the number of the bits left in a buffer.
171 */
172static inline int bits_left(const BitstreamContext *bc)
173{
174 return (bc->buffer - bc->ptr) * 8 + bc->size_in_bits + bc->bits_valid;
175}
176
177static inline uint64_t bits_priv_val_show(BitstreamContext *bc, unsigned int n)
178{
179 av_assert2(n > 0 && n <= 64);
180
181#ifdef BITSTREAM_READER_LE
182 return bc->bits & (UINT64_MAX >> (64 - n));
183#else
184 return bc->bits >> (64 - n);
185#endif
186}
187
188static inline void bits_priv_skip_remaining(BitstreamContext *bc, unsigned int n)
189{
190#ifdef BITSTREAM_READER_LE
191 bc->bits >>= n;
192#else
193 bc->bits <<= n;
194#endif
195 bc->bits_valid -= n;
196}
197
198static inline uint64_t bits_priv_val_get(BitstreamContext *bc, unsigned int n)
199{
200 uint64_t ret;
201
202 av_assert2(n > 0 && n < 64);
203
204 ret = bits_priv_val_show(bc, n);
205 bits_priv_skip_remaining(bc, n);
206
207 return ret;
208}
209
210/**
211 * Return one bit from the buffer.
212 */
213static inline unsigned int bits_read_bit(BitstreamContext *bc)
214{
215 if (!bc->bits_valid && bits_priv_refill_64(bc) < 0)
216 return 0;
217
218 return bits_priv_val_get(bc, 1);
219}
220
221/**
222 * Return n bits from the buffer, n has to be in the 1-32 range.
223 * May be faster than bits_read() when n is not a compile-time constant and is
224 * known to be non-zero;
225 */
226static inline uint32_t bits_read_nz(BitstreamContext *bc, unsigned int n)
227{
228 av_assert2(n > 0 && n <= 32);
229
230 if (n > bc->bits_valid) {
231 if (bits_priv_refill_32(bc) < 0)
232 bc->bits_valid = n;
233 }
234
235 return bits_priv_val_get(bc, n);
236}
237
238/**
239 * Return n bits from the buffer, n has to be in the 0-32 range.
240 */
241static inline uint32_t bits_read(BitstreamContext *bc, unsigned int n)
242{
243 av_assert2(n <= 32);
244
245 if (!n)
246 return 0;
247
248 return bits_read_nz(bc, n);
249}
250
251/**
252 * Return n bits from the buffer, n has to be in the 0-63 range.
253 */
254static inline uint64_t bits_read_63(BitstreamContext *bc, unsigned int n)
255{
256 uint64_t ret = 0;
257 unsigned left = 0;
258
259 av_assert2(n <= 63);
260
261 if (!n)
262 return 0;
263
264 if (n > bc->bits_valid) {
265 left = bc->bits_valid;
266 n -= left;
267
268 if (left)
269 ret = bits_priv_val_get(bc, left);
270
271 if (bits_priv_refill_64(bc) < 0)
272 bc->bits_valid = n;
273
274 }
275
276#ifdef BITSTREAM_READER_LE
277 ret = bits_priv_val_get(bc, n) << left | ret;
278#else
279 ret = bits_priv_val_get(bc, n) | ret << n;
280#endif
281
282 return ret;
283}
284
285/**
286 * Return n bits from the buffer, n has to be in the 0-64 range.
287 */
288static inline uint64_t bits_read_64(BitstreamContext *bc, unsigned int n)
289{
290 av_assert2(n <= 64);
291
292 if (n == 64) {
293 uint64_t ret = bits_read_63(bc, 63);
294#ifdef BITSTREAM_READER_LE
295 return ret | ((uint64_t)bits_read_bit(bc) << 63);
296#else
297 return (ret << 1) | (uint64_t)bits_read_bit(bc);
298#endif
299 }
300 return bits_read_63(bc, n);
301}
302
303/**
304 * Return n bits from the buffer as a signed integer.
305 * n has to be in the 0-32 range.
306 */
307static inline int32_t bits_read_signed(BitstreamContext *bc, unsigned int n)
308{
309 return sign_extend(bits_read(bc, n), n);
310}
311
312/**
313 * Return n bits from the buffer but do not change the buffer state.
314 * n has to be in the 1-32 range. May
315 */
316static inline uint32_t bits_peek_nz(BitstreamContext *bc, unsigned int n)
317{
318 av_assert2(n > 0 && n <= 32);
319
320 if (n > bc->bits_valid)
321 bits_priv_refill_32(bc);
322
323 return bits_priv_val_show(bc, n);
324}
325
326/**
327 * Return n bits from the buffer but do not change the buffer state.
328 * n has to be in the 0-32 range.
329 */
330static inline uint32_t bits_peek(BitstreamContext *bc, unsigned int n)
331{
332 av_assert2(n <= 32);
333
334 if (!n)
335 return 0;
336
337 return bits_peek_nz(bc, n);
338}
339
340/**
341 * Return n bits from the buffer as a signed integer,
342 * do not change the buffer state.
343 * n has to be in the 0-32 range.
344 */
345static inline int bits_peek_signed(BitstreamContext *bc, unsigned int n)
346{
347 return sign_extend(bits_peek(bc, n), n);
348}
349
350/**
351 * Skip n bits in the buffer.
352 */
353static inline void bits_skip(BitstreamContext *bc, unsigned int n)
354{
355 if (n < bc->bits_valid)
356 bits_priv_skip_remaining(bc, n);
357 else {
358 n -= bc->bits_valid;
359 bc->bits = 0;
360 bc->bits_valid = 0;
361
362 if (n >= 64) {
363 unsigned int skip = n / 8;
364
365 n -= skip * 8;
366 bc->ptr += skip;
367 }
368 bits_priv_refill_64(bc);
369 if (n)
370 bits_priv_skip_remaining(bc, n);
371 }
372}
373
374/**
375 * Seek to the given bit position.
376 */
377static inline void bits_seek(BitstreamContext *bc, unsigned pos)
378{
379 bc->ptr = bc->buffer;
380 bc->bits = 0;
381 bc->bits_valid = 0;
382
383 bits_skip(bc, pos);
384}
385
386/**
387 * Skip bits to a byte boundary.
388 */
389static inline const uint8_t *bits_align(BitstreamContext *bc)
390{
391 unsigned int n = -bits_tell(bc) & 7;
392 if (n)
393 bits_skip(bc, n);
394 return bc->buffer + (bits_tell(bc) >> 3);
395}
396
397/**
398 * Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB).
399 * If MSB not set it is negative.
400 * @param n length in bits
401 */
402static inline int bits_read_xbits(BitstreamContext *bc, unsigned int n)
403{
404 int32_t cache = bits_peek(bc, 32);
405 int sign = ~cache >> 31;
406 bits_priv_skip_remaining(bc, n);
407
408 return ((((uint32_t)(sign ^ cache)) >> (32 - n)) ^ sign) - sign;
409}
410
411/**
412 * Return decoded truncated unary code for the values 0, 1, 2.
413 */
414static inline int bits_decode012(BitstreamContext *bc)
415{
416 if (!bits_read_bit(bc))
417 return 0;
418 else
419 return bits_read_bit(bc) + 1;
420}
421
422/**
423 * Return decoded truncated unary code for the values 2, 1, 0.
424 */
425static inline int bits_decode210(BitstreamContext *bc)
426{
427 if (bits_read_bit(bc))
428 return 0;
429 else
430 return 2 - bits_read_bit(bc);
431}
432
433/* Read sign bit and flip the sign of the provided value accordingly. */
434static inline int bits_apply_sign(BitstreamContext *bc, int val)
435{
436 int sign = bits_read_signed(bc, 1);
437 return (val ^ sign) - sign;
438}
439
440static inline int bits_skip_1stop_8data(BitstreamContext *s)
441{
442 if (bits_left(s) <= 0)
443 return AVERROR_INVALIDDATA;
444
445 while (bits_read_bit(s)) {
446 bits_skip(s, 8);
447 if (bits_left(s) <= 0)
448 return AVERROR_INVALIDDATA;
449 }
450
451 return 0;
452}
453
454/**
455 * Return the LUT element for the given bitstream configuration.
456 */
457static inline int bits_priv_set_idx(BitstreamContext *bc, int code, int *n, int *nb_bits,
458 const VLCElem *table)
459{
460 unsigned idx;
461
462 *nb_bits = -*n;
463 idx = bits_peek(bc, *nb_bits) + code;
464 *n = table[idx].len;
465
466 return table[idx].sym;
467}
468
469/**
470 * Parse a vlc code.
471 * @param bits is the number of bits which will be read at once, must be
472 * identical to nb_bits in init_vlc()
473 * @param max_depth is the number of times bits bits must be read to completely
474 * read the longest vlc code
475 * = (max_vlc_length + bits - 1) / bits
476 * If the vlc code is invalid and max_depth=1, then no bits will be removed.
477 * If the vlc code is invalid and max_depth>1, then the number of bits removed
478 * is undefined.
479 */
480static inline int bits_read_vlc(BitstreamContext *bc, const VLCElem *table,
481 int bits, int max_depth)
482{
483 int nb_bits;
484 unsigned idx = bits_peek(bc, bits);
485 int code = table[idx].sym;
486 int n = table[idx].len;
487
488 if (max_depth > 1 && n < 0) {
489 bits_priv_skip_remaining(bc, bits);
490 code = bits_priv_set_idx(bc, code, &n, &nb_bits, table);
491 if (max_depth > 2 && n < 0) {
492 bits_priv_skip_remaining(bc, nb_bits);
493 code = bits_priv_set_idx(bc, code, &n, &nb_bits, table);
494 }
495 }
496 bits_priv_skip_remaining(bc, n);
497
498 return code;
499}
500
501#define BITS_RL_VLC(level, run, bc, table, bits, max_depth) \
502 do { \
503 int n, nb_bits; \
504 unsigned int index = bits_peek(bc, bits); \
505 level = table[index].level; \
506 n = table[index].len; \
507 \
508 if (max_depth > 1 && n < 0) { \
509 bits_skip(bc, bits); \
510 \
511 nb_bits = -n; \
512 \
513 index = bits_peek(bc, nb_bits) + level; \
514 level = table[index].level; \
515 n = table[index].len; \
516 if (max_depth > 2 && n < 0) { \
517 bits_skip(bc, nb_bits); \
518 nb_bits = -n; \
519 \
520 index = bits_peek(bc, nb_bits) + level; \
521 level = table[index].level; \
522 n = table[index].len; \
523 } \
524 } \
525 run = table[index].run; \
526 bits_skip(bc, n); \
527 } while (0)
528
529#endif /* AVCODEC_BITSTREAM_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t