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 #ifndef PUT_BITS_H
22 #define PUT_BITS_H
23 
24 #ifdef WORDS_BIGENDIAN
25 #define be2me_32(x) (x)
26 #else
27 #define be2me_32(x) bswap_32(x)
28 #endif
29 
30 #ifndef bswap_32
bswap_32(uint32_t x)31 static inline uint32_t bswap_32(uint32_t x)
32 {
33     x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff);
34     x = (x >> 16) | (x << 16);
35     return x;
36 }
37 #endif
38 
39 typedef struct PutBitContext {
40     uint32_t    bit_buf;
41     int         bit_left;
42     uint8_t    *buf;
43     uint8_t    *buf_ptr;
44     uint8_t    *buf_end;
45     int         size_in_bits;
46 } PutBitContext;
47 
48 /**
49  * Initializes the PutBitContext s.
50  *
51  * @param buffer the buffer where to put bits
52  * @param buffer_size the size in bytes of buffer
53  */
init_put_bits(PutBitContext * s,uint8_t * buffer,int buffer_size)54 static inline void init_put_bits(PutBitContext *s, uint8_t *buffer, int buffer_size)
55 {
56     if (buffer_size < 0) {
57         buffer_size = 0;
58         buffer = NULL;
59     }
60 
61     s->size_in_bits = 8 * buffer_size;
62     s->buf          = buffer;
63     s->buf_end      = s->buf + buffer_size;
64     s->buf_ptr      = s->buf;
65     s->bit_left     = 32;
66     s->bit_buf      = 0;
67 }
68 
69 /**
70  * Returns the total number of bits written to the bitstream.
71  */
put_bits_count(PutBitContext * s)72 static inline int put_bits_count(PutBitContext *s)
73 {
74     return (s->buf_ptr - s->buf) * 8 + 32 - s->bit_left;
75 }
76 
77 /**
78  * Pads the end of the output stream with zeros.
79  */
flush_put_bits(PutBitContext * s)80 static inline void flush_put_bits(PutBitContext *s)
81 {
82     s->bit_buf <<= s->bit_left;
83     while (s->bit_left < 32) {
84         /* XXX: should test end of buffer */
85         *s->buf_ptr++ = s->bit_buf >> 24;
86         s->bit_buf  <<= 8;
87         s->bit_left  += 8;
88     }
89     s->bit_left = 32;
90     s->bit_buf  = 0;
91 }
92 
93 /**
94  * Write up to 31 bits into a bitstream.
95  * Use put_bits32 to write 32 bits.
96  */
put_bits(PutBitContext * s,int n,unsigned int value)97 static inline void put_bits(PutBitContext *s, int n, unsigned int value)
98 {
99     unsigned int bit_buf;
100     int bit_left;
101 
102     assert(n <= 31 && value < (1U << n));
103 
104     bit_buf  = s->bit_buf;
105     bit_left = s->bit_left;
106 
107     if (n < bit_left) {
108         bit_buf   = (bit_buf << n) | value;
109         bit_left -= n;
110     }
111     else {
112         bit_buf <<= bit_left;
113         bit_buf  |= value >> (n - bit_left);
114         if (3 & (uintptr_t)s->buf_ptr) {
115             s->buf_ptr[0] = bit_buf >> 24;
116             s->buf_ptr[1] = bit_buf >> 16;
117             s->buf_ptr[2] = bit_buf >> 8;
118             s->buf_ptr[3] = bit_buf;
119         }
120         else
121             *(uint32_t *)s->buf_ptr = be2me_32(bit_buf);
122         s->buf_ptr += 4;
123         bit_left   += 32 - n;
124         bit_buf     = value;
125     }
126 
127     s->bit_buf = bit_buf;
128     s->bit_left = bit_left;
129 }
130 
131 /**
132  * Pads the bitstream with zeros up to the next byte boundary.
133  */
align_put_bits(PutBitContext * s)134 static inline void align_put_bits(PutBitContext *s)
135 {
136     put_bits(s, s->bit_left & 7, 0);
137 }
138 
139 #endif /* PUT_BITS_H */
140