-
Notifications
You must be signed in to change notification settings - Fork 41
/
bitstream.h
177 lines (165 loc) · 5.6 KB
/
bitstream.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/*****************************************************************************
* bitstream.h: bitstream writing
*****************************************************************************
* Copyright (C) 2003-2010 x264 project
*
* Authors: Loren Merritt <[email protected]>
* Jason Garrett-Glaser <[email protected]>
* Laurent Aimar <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at [email protected].
*****************************************************************************/
#ifndef LIBMPEGTS_BS_H
#define LIBMPEGTS_BS_H
#define WORD_SIZE sizeof(long)
/* Unions for type-punning.
* Mn: load or store n bits, aligned, native-endian
* CPn: copy n bits, aligned, native-endian
* we don't use memcpy for CPn because memcpy's args aren't assumed to be aligned */
typedef union { uint16_t i; uint8_t c[2]; } x264_union16_t;
typedef union { uint32_t i; uint16_t b[2]; uint8_t c[4]; } x264_union32_t;
typedef union { uint64_t i; uint32_t a[2]; uint16_t b[4]; uint8_t c[8]; } x264_union64_t;
typedef struct { uint64_t i[2]; } x264_uint128_t;
typedef union { x264_uint128_t i; uint64_t a[2]; uint32_t b[4]; uint16_t c[8]; uint8_t d[16]; } x264_union128_t;
#define M16(src) (((x264_union16_t*)(src))->i)
#define M32(src) (((x264_union32_t*)(src))->i)
#define M64(src) (((x264_union64_t*)(src))->i)
#define M128(src) (((x264_union128_t*)(src))->i)
#define M128_ZERO ((x264_uint128_t){{0,0}})
#define CP16(dst,src) M16(dst) = M16(src)
#define CP32(dst,src) M32(dst) = M32(src)
#define CP64(dst,src) M64(dst) = M64(src)
#define CP128(dst,src) M128(dst) = M128(src)
#if WORDS_BIGENDIAN
#define endian_fix(x) (x)
#define endian_fix64(x) (x)
#define endian_fix32(x) (x)
#define endian_fix16(x) (x)
#else
static inline uint32_t endian_fix32( uint32_t x )
{
return (x<<24) + ((x<<8)&0xff0000) + ((x>>8)&0xff00) + (x>>24);
}
static inline uint64_t endian_fix64( uint64_t x )
{
return endian_fix32(x>>32) + ((uint64_t)endian_fix32(x)<<32);
}
static inline intptr_t endian_fix( intptr_t x )
{
return WORD_SIZE == 8 ? endian_fix64(x) : endian_fix32(x);
}
static inline uint16_t endian_fix16( uint16_t x )
{
return (x<<8)|(x>>8);
}
#endif
typedef struct bs_s
{
uint8_t *p_start;
uint8_t *p;
uint8_t *p_end;
intptr_t cur_bits;
int i_left; /* i_count number of available bits */
} bs_t;
static inline void bs_init( bs_t *s, void *p_data, int i_data )
{
int offset = ((intptr_t)p_data & 3);
s->p = s->p_start = (uint8_t*)p_data - offset;
s->p_end = (uint8_t*)p_data + i_data;
s->i_left = (WORD_SIZE - offset)*8;
s->cur_bits = endian_fix32( M32(s->p) );
s->cur_bits >>= (4-offset)*8;
}
static inline int bs_pos( bs_t *s )
{
return( 8 * (s->p - s->p_start) + (WORD_SIZE*8) - s->i_left );
}
/* Write the rest of cur_bits to the bitstream; results in a bitstream no longer 32-bit aligned. */
static inline void bs_flush( bs_t *s )
{
M32( s->p ) = endian_fix32( s->cur_bits << (s->i_left&31) );
s->p += WORD_SIZE - (s->i_left >> 3);
s->i_left = WORD_SIZE*8;
}
/* The inverse of bs_flush: prepare the bitstream to be written to again. */
static inline void bs_realign( bs_t *s )
{
int offset = ((intptr_t)s->p & 3);
if( offset )
{
s->p = (uint8_t*)s->p - offset;
s->i_left = (WORD_SIZE - offset)*8;
s->cur_bits = endian_fix32( M32(s->p) );
s->cur_bits >>= (4-offset)*8;
}
}
static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
{
if( WORD_SIZE == 8 )
{
s->cur_bits = (s->cur_bits << i_count) | i_bits;
s->i_left -= i_count;
if( s->i_left <= 32 )
{
#if WORDS_BIGENDIAN
M32( s->p ) = s->cur_bits >> (32 - s->i_left);
#else
M32( s->p ) = endian_fix( s->cur_bits << s->i_left );
#endif
s->i_left += 32;
s->p += 4;
}
}
else
{
if( i_count < s->i_left )
{
s->cur_bits = (s->cur_bits << i_count) | i_bits;
s->i_left -= i_count;
}
else
{
i_count -= s->i_left;
s->cur_bits = (s->cur_bits << s->i_left) | (i_bits >> i_count);
M32( s->p ) = endian_fix( s->cur_bits );
s->p += 4;
s->cur_bits = i_bits;
s->i_left = 32 - i_count;
}
}
}
/* Special case to eliminate branch in normal bs_write. */
/* Golomb never writes an even-size code, so this is only used in slice headers. */
static inline void bs_write32( bs_t *s, uint32_t i_bits )
{
bs_write( s, 16, i_bits >> 16 );
bs_write( s, 16, i_bits );
}
static inline void bs_write1( bs_t *s, uint32_t i_bit )
{
s->cur_bits <<= 1;
s->cur_bits |= i_bit;
s->i_left--;
if( s->i_left == WORD_SIZE*8-32 )
{
M32( s->p ) = endian_fix32( s->cur_bits );
s->p += 4;
s->i_left = WORD_SIZE*8;
}
}
#endif