1/*
2 * copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
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 writer API
24 */
25
26#ifndef AVCODEC_PUT_BITS_H
27#define AVCODEC_PUT_BITS_H
28
29#include <stdint.h>
30#include <stddef.h>
31#include <assert.h>
32
33#include "libavutil/intreadwrite.h"
34#include "libavutil/avassert.h"
35
36typedef struct PutBitContext {
37    uint32_t bit_buf;
38    int bit_left;
39    uint8_t *buf, *buf_ptr, *buf_end;
40    int size_in_bits;
41} PutBitContext;
42
43/**
44 * Initialize the PutBitContext s.
45 *
46 * @param buffer the buffer where to put bits
47 * @param buffer_size the size in bytes of buffer
48 */
49static inline void init_put_bits(PutBitContext *s, uint8_t *buffer,
50                                 int buffer_size)
51{
52    if (buffer_size < 0) {
53        buffer_size = 0;
54        buffer      = NULL;
55    }
56
57    s->size_in_bits = 8 * buffer_size;
58    s->buf          = buffer;
59    s->buf_end      = s->buf + buffer_size;
60    s->buf_ptr      = s->buf;
61    s->bit_left     = 32;
62    s->bit_buf      = 0;
63}
64
65/**
66 * @return the total number of bits written to the bitstream.
67 */
68static inline int put_bits_count(PutBitContext *s)
69{
70    return (s->buf_ptr - s->buf) * 8 + 32 - s->bit_left;
71}
72
73/**
74 * @return the number of bits available in the bitstream.
75 */
76static inline int put_bits_left(PutBitContext* s)
77{
78    return (s->buf_end - s->buf_ptr) * 8 - 32 + s->bit_left;
79}
80
81/**
82 * Pad the end of the output stream with zeros.
83 */
84static inline void flush_put_bits(PutBitContext *s)
85{
86#ifndef BITSTREAM_WRITER_LE
87    if (s->bit_left < 32)
88        s->bit_buf <<= s->bit_left;
89#endif
90    while (s->bit_left < 32) {
91        /* XXX: should test end of buffer */
92#ifdef BITSTREAM_WRITER_LE
93        *s->buf_ptr++ = s->bit_buf;
94        s->bit_buf  >>= 8;
95#else
96        *s->buf_ptr++ = s->bit_buf >> 24;
97        s->bit_buf  <<= 8;
98#endif
99        s->bit_left  += 8;
100    }
101    s->bit_left = 32;
102    s->bit_buf  = 0;
103}
104
105#ifdef BITSTREAM_WRITER_LE
106#define avpriv_align_put_bits align_put_bits_unsupported_here
107#define avpriv_put_string ff_put_string_unsupported_here
108#define avpriv_copy_bits avpriv_copy_bits_unsupported_here
109#else
110/**
111 * Pad the bitstream with zeros up to the next byte boundary.
112 */
113void avpriv_align_put_bits(PutBitContext *s);
114
115/**
116 * Put the string string in the bitstream.
117 *
118 * @param terminate_string 0-terminates the written string if value is 1
119 */
120void avpriv_put_string(PutBitContext *pb, const char *string,
121                       int terminate_string);
122
123/**
124 * Copy the content of src to the bitstream.
125 *
126 * @param length the number of bits of src to copy
127 */
128void avpriv_copy_bits(PutBitContext *pb, const uint8_t *src, int length);
129#endif
130
131/**
132 * Write up to 31 bits into a bitstream.
133 * Use put_bits32 to write 32 bits.
134 */
135static inline void put_bits(PutBitContext *s, int n, unsigned int value)
136{
137    unsigned int bit_buf;
138    int bit_left;
139
140    av_assert2(n <= 31 && value < (1U << n));
141
142    bit_buf  = s->bit_buf;
143    bit_left = s->bit_left;
144
145    /* XXX: optimize */
146#ifdef BITSTREAM_WRITER_LE
147    bit_buf |= value << (32 - bit_left);
148    if (n >= bit_left) {
149        av_assert2(s->buf_ptr+3<s->buf_end);
150        AV_WL32(s->buf_ptr, bit_buf);
151        s->buf_ptr += 4;
152        bit_buf     = (bit_left == 32) ? 0 : value >> bit_left;
153        bit_left   += 32;
154    }
155    bit_left -= n;
156#else
157    if (n < bit_left) {
158        bit_buf     = (bit_buf << n) | value;
159        bit_left   -= n;
160    } else {
161        bit_buf   <<= bit_left;
162        bit_buf    |= value >> (n - bit_left);
163        av_assert2(s->buf_ptr+3<s->buf_end);
164        AV_WB32(s->buf_ptr, bit_buf);
165        s->buf_ptr += 4;
166        bit_left   += 32 - n;
167        bit_buf     = value;
168    }
169#endif
170
171    s->bit_buf  = bit_buf;
172    s->bit_left = bit_left;
173}
174
175static inline void put_sbits(PutBitContext *pb, int n, int32_t value)
176{
177    av_assert2(n >= 0 && n <= 31);
178
179    put_bits(pb, n, value & ((1 << n) - 1));
180}
181
182/**
183 * Write exactly 32 bits into a bitstream.
184 */
185static void av_unused put_bits32(PutBitContext *s, uint32_t value)
186{
187    int lo = value & 0xffff;
188    int hi = value >> 16;
189#ifdef BITSTREAM_WRITER_LE
190    put_bits(s, 16, lo);
191    put_bits(s, 16, hi);
192#else
193    put_bits(s, 16, hi);
194    put_bits(s, 16, lo);
195#endif
196}
197
198/**
199 * Return the pointer to the byte where the bitstream writer will put
200 * the next bit.
201 */
202static inline uint8_t *put_bits_ptr(PutBitContext *s)
203{
204    return s->buf_ptr;
205}
206
207/**
208 * Skip the given number of bytes.
209 * PutBitContext must be flushed & aligned to a byte boundary before calling this.
210 */
211static inline void skip_put_bytes(PutBitContext *s, int n)
212{
213    av_assert2((put_bits_count(s) & 7) == 0);
214    av_assert2(s->bit_left == 32);
215    s->buf_ptr += n;
216}
217
218/**
219 * Skip the given number of bits.
220 * Must only be used if the actual values in the bitstream do not matter.
221 * If n is 0 the behavior is undefined.
222 */
223static inline void skip_put_bits(PutBitContext *s, int n)
224{
225    s->bit_left -= n;
226    s->buf_ptr  -= 4 * (s->bit_left >> 5);
227    s->bit_left &= 31;
228}
229
230/**
231 * Change the end of the buffer.
232 *
233 * @param size the new size in bytes of the buffer where to put bits
234 */
235static inline void set_put_bits_buffer_size(PutBitContext *s, int size)
236{
237    s->buf_end = s->buf + size;
238}
239
240#endif /* AVCODEC_PUT_BITS_H */
241