1 /*
2 * Copyright 2023 Red Hat
3 * SPDX-License-Identifier: MIT
4 *
5 * This is a C rewrite of pieces of the d3d12 frontend which is:
6 * Copyright © Microsoft Corporation
7 */
8 #ifndef VL_BITSTREAM_H
9 #define VL_BITSTREAM_H
10
11 struct vl_bitstream_encoder {
12 uint8_t *bits;
13 uint32_t bits_buffer_size;
14 uint32_t offset;
15
16 uint32_t enc_buffer;
17
18 int32_t bits_to_go;
19 bool prevent_start_code;
20
21 bool internal_buffer;
22 bool overflow;
23 };
24
25 #define VL_BITSTREAM_MAX_BUFFER 256
26
27 static inline void
vl_bitstream_encoder_clear(struct vl_bitstream_encoder * enc,void * buffer_base,size_t buffer_offset,size_t buffer_limit)28 vl_bitstream_encoder_clear(struct vl_bitstream_encoder *enc,
29 void *buffer_base,
30 size_t buffer_offset,
31 size_t buffer_limit)
32 {
33 memset(enc, 0, sizeof(*enc));
34 enc->bits_to_go = 32;
35
36 if (!buffer_base) {
37 enc->bits = malloc(VL_BITSTREAM_MAX_BUFFER);
38 enc->bits_buffer_size = VL_BITSTREAM_MAX_BUFFER;
39 enc->internal_buffer = true;
40 } else {
41 enc->bits = (uint8_t *)buffer_base + buffer_offset;
42 enc->bits_buffer_size = buffer_limit;
43 }
44 }
45
46 static inline void
vl_bitstream_encoder_free(struct vl_bitstream_encoder * enc)47 vl_bitstream_encoder_free(struct vl_bitstream_encoder *enc)
48 {
49 if (enc->internal_buffer)
50 free(enc->bits);
51 }
52
53 static inline int
vl_bitstream_get_num_bits_for_byte_align(struct vl_bitstream_encoder * enc)54 vl_bitstream_get_num_bits_for_byte_align(struct vl_bitstream_encoder *enc)
55 {
56 return enc->bits_to_go & 7;
57 }
58
59 static inline int
vl_bitstream_get_byte_count(struct vl_bitstream_encoder * enc)60 vl_bitstream_get_byte_count(struct vl_bitstream_encoder *enc)
61 {
62 return enc->offset + ((32 - enc->bits_to_go) >> 3);
63 }
64
65 static inline bool
vl_bitstream_is_byte_aligned(struct vl_bitstream_encoder * enc)66 vl_bitstream_is_byte_aligned(struct vl_bitstream_encoder *enc)
67 {
68 if (enc->overflow)
69 enc->bits_to_go = 32;
70 return !(enc->bits_to_go & 7);
71 }
72
73 static inline void
vl_bitstream_write_byte_start_code(struct vl_bitstream_encoder * enc,uint8_t val)74 vl_bitstream_write_byte_start_code(struct vl_bitstream_encoder *enc, uint8_t val)
75 {
76 int offset = enc->offset;
77 uint8_t *buffer = enc->bits + enc->offset;
78 if (enc->prevent_start_code && enc->offset > 1) {
79 if (((val & 0xfc) | buffer[-2] | buffer[-1]) == 0) {
80 *buffer++ = 3;
81 offset++;
82 }
83 }
84
85 *buffer = val;
86 offset++;
87 enc->offset = offset;
88 }
89
90 static inline bool
vl_bitstream_verify_buffer(struct vl_bitstream_encoder * enc,uint32_t bytes_to_write)91 vl_bitstream_verify_buffer(struct vl_bitstream_encoder *enc, uint32_t bytes_to_write)
92 {
93 if (enc->overflow)
94 return false;
95
96 if (enc->offset + bytes_to_write > enc->bits_buffer_size) {
97 enc->overflow = true;
98 return false;
99 }
100 return true;
101 }
102
103 static inline void
vl_bitstream_flush(struct vl_bitstream_encoder * enc)104 vl_bitstream_flush(struct vl_bitstream_encoder *enc)
105 {
106 ASSERTED bool is_aligned = vl_bitstream_is_byte_aligned(enc);
107 assert (is_aligned);
108
109 uint32_t temp = (uint32_t)(32 - enc->bits_to_go);
110
111 if (!vl_bitstream_verify_buffer(enc, temp >> 3)) {
112 return;
113 }
114
115 while (temp > 0) {
116 vl_bitstream_write_byte_start_code(enc, (uint8_t)(enc->enc_buffer >> 24));
117 enc->enc_buffer <<= 8;
118 temp -= 8;
119 }
120
121 enc->bits_to_go = 32;
122 enc->enc_buffer = 0;
123 }
124
125 static inline void
vl_bitstream_put_bits(struct vl_bitstream_encoder * enc,int bits_count,uint32_t bits_val)126 vl_bitstream_put_bits(struct vl_bitstream_encoder *enc, int bits_count, uint32_t bits_val)
127 {
128 if (bits_count < enc->bits_to_go) {
129 enc->enc_buffer |= (bits_val << (enc->bits_to_go - bits_count));
130 enc->bits_to_go -= bits_count;
131 } else if (vl_bitstream_verify_buffer(enc, 4)) {
132 int left_over_bits = bits_count - enc->bits_to_go;
133 enc->enc_buffer |= (bits_val >> left_over_bits);
134
135 {
136 uint8_t *temp = (uint8_t *)&enc->enc_buffer;
137 vl_bitstream_write_byte_start_code(enc, *(temp + 3));
138 vl_bitstream_write_byte_start_code(enc, *(temp + 2));
139 vl_bitstream_write_byte_start_code(enc, *(temp + 1));
140 vl_bitstream_write_byte_start_code(enc, *temp);
141 }
142
143 enc->enc_buffer = 0;
144 enc->bits_to_go = 32 - left_over_bits;
145
146 if (left_over_bits > 0)
147 enc->enc_buffer = (bits_val << (32 - left_over_bits));
148 }
149 }
150
151 static inline int
vl_bitstream_get_exp_golomb0_code_len(uint32_t val)152 vl_bitstream_get_exp_golomb0_code_len(uint32_t val)
153 {
154 int len = 0;
155 val++;
156
157 if (val >= 0x10000) {
158 val >>= 16;
159 len += 16;
160 }
161 if (val >= 0x100) {
162 val >>= 8;
163 len += 8;
164 }
165 assert(val < 256);
166
167 return len + util_logbase2(val);
168 }
169
170 static inline void
vl_bitstream_exp_golomb_ue(struct vl_bitstream_encoder * enc,uint32_t val)171 vl_bitstream_exp_golomb_ue(struct vl_bitstream_encoder *enc, uint32_t val)
172 {
173 if (val != UINT32_MAX) {
174 int len = vl_bitstream_get_exp_golomb0_code_len(val);
175 vl_bitstream_put_bits(enc, (len << 1) + 1, val + 1);
176 } else {
177 vl_bitstream_put_bits(enc, 32, 0);
178 vl_bitstream_put_bits(enc, 1, 1);
179 vl_bitstream_put_bits(enc, 32, 1);
180 }
181 }
182
183 static inline void
vl_bitstream_exp_golomb_se(struct vl_bitstream_encoder * enc,int32_t val)184 vl_bitstream_exp_golomb_se(struct vl_bitstream_encoder *enc, int32_t val)
185 {
186 if (val > 0)
187 vl_bitstream_exp_golomb_ue(enc, (val << 1) - 1);
188 else
189 vl_bitstream_exp_golomb_ue(enc, ((-val) << 1) - (val == INT_MIN));
190 }
191
192 static inline void
vl_bitstream_rbsp_trailing(struct vl_bitstream_encoder * enc)193 vl_bitstream_rbsp_trailing(struct vl_bitstream_encoder *enc)
194 {
195 vl_bitstream_put_bits(enc, 1, 1);
196 int left = vl_bitstream_get_num_bits_for_byte_align(enc);
197
198 if (left)
199 vl_bitstream_put_bits(enc, left, 0);
200
201 ASSERTED bool is_aligned = vl_bitstream_is_byte_aligned(enc);
202 assert(is_aligned);
203 }
204 #endif
205