1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * TW5864 driver - H.264 headers generation functions |
4 | * |
5 | * Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com> |
6 | */ |
7 | |
8 | #include <linux/log2.h> |
9 | |
10 | #include "tw5864.h" |
11 | |
12 | static u8 marker[] = { 0x00, 0x00, 0x00, 0x01 }; |
13 | |
14 | /* |
15 | * Exponential-Golomb coding functions |
16 | * |
17 | * These functions are used for generation of H.264 bitstream headers. |
18 | * |
19 | * This code is derived from tw5864 reference driver by manufacturers, which |
20 | * itself apparently was derived from x264 project. |
21 | */ |
22 | |
23 | /* Bitstream writing context */ |
24 | struct bs { |
25 | u8 *buf; /* pointer to buffer beginning */ |
26 | u8 *buf_end; /* pointer to buffer end */ |
27 | u8 *ptr; /* pointer to current byte in buffer */ |
28 | unsigned int bits_left; /* number of available bits in current byte */ |
29 | }; |
30 | |
31 | static void bs_init(struct bs *s, void *buf, int size) |
32 | { |
33 | s->buf = buf; |
34 | s->ptr = buf; |
35 | s->buf_end = s->ptr + size; |
36 | s->bits_left = 8; |
37 | } |
38 | |
39 | static int bs_len(struct bs *s) |
40 | { |
41 | return s->ptr - s->buf; |
42 | } |
43 | |
44 | static void bs_write(struct bs *s, int count, u32 bits) |
45 | { |
46 | if (s->ptr >= s->buf_end - 4) |
47 | return; |
48 | while (count > 0) { |
49 | if (count < 32) |
50 | bits &= (1 << count) - 1; |
51 | if (count < s->bits_left) { |
52 | *s->ptr = (*s->ptr << count) | bits; |
53 | s->bits_left -= count; |
54 | break; |
55 | } |
56 | *s->ptr = (*s->ptr << s->bits_left) | |
57 | (bits >> (count - s->bits_left)); |
58 | count -= s->bits_left; |
59 | s->ptr++; |
60 | s->bits_left = 8; |
61 | } |
62 | } |
63 | |
64 | static void bs_write1(struct bs *s, u32 bit) |
65 | { |
66 | if (s->ptr < s->buf_end) { |
67 | *s->ptr <<= 1; |
68 | *s->ptr |= bit; |
69 | s->bits_left--; |
70 | if (s->bits_left == 0) { |
71 | s->ptr++; |
72 | s->bits_left = 8; |
73 | } |
74 | } |
75 | } |
76 | |
77 | static void bs_write_ue(struct bs *s, u32 val) |
78 | { |
79 | if (val == 0) { |
80 | bs_write1(s, bit: 1); |
81 | } else { |
82 | val++; |
83 | bs_write(s, count: 2 * fls(x: val) - 1, bits: val); |
84 | } |
85 | } |
86 | |
87 | static void bs_write_se(struct bs *s, int val) |
88 | { |
89 | bs_write_ue(s, val: val <= 0 ? -val * 2 : val * 2 - 1); |
90 | } |
91 | |
92 | static void bs_rbsp_trailing(struct bs *s) |
93 | { |
94 | bs_write1(s, bit: 1); |
95 | if (s->bits_left != 8) |
96 | bs_write(s, count: s->bits_left, bits: 0x00); |
97 | } |
98 | |
99 | /* H.264 headers generation functions */ |
100 | |
101 | static int tw5864_h264_gen_sps_rbsp(u8 *buf, size_t size, int width, int height) |
102 | { |
103 | struct bs bs, *s; |
104 | |
105 | s = &bs; |
106 | bs_init(s, buf, size); |
107 | bs_write(s, count: 8, bits: 0x42); /* profile_idc, baseline */ |
108 | bs_write(s, count: 1, bits: 1); /* constraint_set0_flag */ |
109 | bs_write(s, count: 1, bits: 1); /* constraint_set1_flag */ |
110 | bs_write(s, count: 1, bits: 0); /* constraint_set2_flag */ |
111 | bs_write(s, count: 5, bits: 0); /* reserved_zero_5bits */ |
112 | bs_write(s, count: 8, bits: 0x1e); /* level_idc */ |
113 | bs_write_ue(s, val: 0); /* seq_parameter_set_id */ |
114 | bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4); /* log2_max_frame_num_minus4 */ |
115 | bs_write_ue(s, val: 0); /* pic_order_cnt_type */ |
116 | /* log2_max_pic_order_cnt_lsb_minus4 */ |
117 | bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4); |
118 | bs_write_ue(s, val: 1); /* num_ref_frames */ |
119 | bs_write(s, count: 1, bits: 0); /* gaps_in_frame_num_value_allowed_flag */ |
120 | bs_write_ue(s, val: width / 16 - 1); /* pic_width_in_mbs_minus1 */ |
121 | bs_write_ue(s, val: height / 16 - 1); /* pic_height_in_map_units_minus1 */ |
122 | bs_write(s, count: 1, bits: 1); /* frame_mbs_only_flag */ |
123 | bs_write(s, count: 1, bits: 0); /* direct_8x8_inference_flag */ |
124 | bs_write(s, count: 1, bits: 0); /* frame_cropping_flag */ |
125 | bs_write(s, count: 1, bits: 0); /* vui_parameters_present_flag */ |
126 | bs_rbsp_trailing(s); |
127 | return bs_len(s); |
128 | } |
129 | |
130 | static int tw5864_h264_gen_pps_rbsp(u8 *buf, size_t size, int qp) |
131 | { |
132 | struct bs bs, *s; |
133 | |
134 | s = &bs; |
135 | bs_init(s, buf, size); |
136 | bs_write_ue(s, val: 0); /* pic_parameter_set_id */ |
137 | bs_write_ue(s, val: 0); /* seq_parameter_set_id */ |
138 | bs_write(s, count: 1, bits: 0); /* entropy_coding_mode_flag */ |
139 | bs_write(s, count: 1, bits: 0); /* pic_order_present_flag */ |
140 | bs_write_ue(s, val: 0); /* num_slice_groups_minus1 */ |
141 | bs_write_ue(s, val: 0); /* i_num_ref_idx_l0_active_minus1 */ |
142 | bs_write_ue(s, val: 0); /* i_num_ref_idx_l1_active_minus1 */ |
143 | bs_write(s, count: 1, bits: 0); /* weighted_pred_flag */ |
144 | bs_write(s, count: 2, bits: 0); /* weighted_bipred_idc */ |
145 | bs_write_se(s, val: qp - 26); /* pic_init_qp_minus26 */ |
146 | bs_write_se(s, val: qp - 26); /* pic_init_qs_minus26 */ |
147 | bs_write_se(s, val: 0); /* chroma_qp_index_offset */ |
148 | bs_write(s, count: 1, bits: 0); /* deblocking_filter_control_present_flag */ |
149 | bs_write(s, count: 1, bits: 0); /* constrained_intra_pred_flag */ |
150 | bs_write(s, count: 1, bits: 0); /* redundant_pic_cnt_present_flag */ |
151 | bs_rbsp_trailing(s); |
152 | return bs_len(s); |
153 | } |
154 | |
155 | static int tw5864_h264_gen_slice_head(u8 *buf, size_t size, |
156 | unsigned int idr_pic_id, |
157 | unsigned int frame_gop_seqno, |
158 | int *tail_nb_bits, u8 *tail) |
159 | { |
160 | struct bs bs, *s; |
161 | int is_i_frame = frame_gop_seqno == 0; |
162 | |
163 | s = &bs; |
164 | bs_init(s, buf, size); |
165 | bs_write_ue(s, val: 0); /* first_mb_in_slice */ |
166 | bs_write_ue(s, val: is_i_frame ? 2 : 5); /* slice_type - I or P */ |
167 | bs_write_ue(s, val: 0); /* pic_parameter_set_id */ |
168 | bs_write(s, ilog2(MAX_GOP_SIZE), bits: frame_gop_seqno); /* frame_num */ |
169 | if (is_i_frame) |
170 | bs_write_ue(s, val: idr_pic_id); |
171 | |
172 | /* pic_order_cnt_lsb */ |
173 | bs_write(s, ilog2(MAX_GOP_SIZE), bits: frame_gop_seqno); |
174 | |
175 | if (is_i_frame) { |
176 | bs_write1(s, bit: 0); /* no_output_of_prior_pics_flag */ |
177 | bs_write1(s, bit: 0); /* long_term_reference_flag */ |
178 | } else { |
179 | bs_write1(s, bit: 0); /* num_ref_idx_active_override_flag */ |
180 | bs_write1(s, bit: 0); /* ref_pic_list_reordering_flag_l0 */ |
181 | bs_write1(s, bit: 0); /* adaptive_ref_pic_marking_mode_flag */ |
182 | } |
183 | |
184 | bs_write_se(s, val: 0); /* slice_qp_delta */ |
185 | |
186 | if (s->bits_left != 8) { |
187 | *tail = ((s->ptr[0]) << s->bits_left); |
188 | *tail_nb_bits = 8 - s->bits_left; |
189 | } else { |
190 | *tail = 0; |
191 | *tail_nb_bits = 0; |
192 | } |
193 | |
194 | return bs_len(s); |
195 | } |
196 | |
197 | void (u8 **buf, size_t *space_left, int qp, |
198 | int width, int height) |
199 | { |
200 | int nal_len; |
201 | |
202 | /* SPS */ |
203 | memcpy(*buf, marker, sizeof(marker)); |
204 | *buf += 4; |
205 | *space_left -= 4; |
206 | |
207 | **buf = 0x67; /* SPS NAL header */ |
208 | *buf += 1; |
209 | *space_left -= 1; |
210 | |
211 | nal_len = tw5864_h264_gen_sps_rbsp(buf: *buf, size: *space_left, width, height); |
212 | *buf += nal_len; |
213 | *space_left -= nal_len; |
214 | |
215 | /* PPS */ |
216 | memcpy(*buf, marker, sizeof(marker)); |
217 | *buf += 4; |
218 | *space_left -= 4; |
219 | |
220 | **buf = 0x68; /* PPS NAL header */ |
221 | *buf += 1; |
222 | *space_left -= 1; |
223 | |
224 | nal_len = tw5864_h264_gen_pps_rbsp(buf: *buf, size: *space_left, qp); |
225 | *buf += nal_len; |
226 | *space_left -= nal_len; |
227 | } |
228 | |
229 | void (u8 **buf, size_t *space_left, |
230 | unsigned int idr_pic_id, |
231 | unsigned int frame_gop_seqno, |
232 | int *tail_nb_bits, u8 *tail) |
233 | { |
234 | int nal_len; |
235 | |
236 | memcpy(*buf, marker, sizeof(marker)); |
237 | *buf += 4; |
238 | *space_left -= 4; |
239 | |
240 | /* Frame NAL header */ |
241 | **buf = (frame_gop_seqno == 0) ? 0x25 : 0x21; |
242 | *buf += 1; |
243 | *space_left -= 1; |
244 | |
245 | nal_len = tw5864_h264_gen_slice_head(buf: *buf, size: *space_left, idr_pic_id, |
246 | frame_gop_seqno, tail_nb_bits, |
247 | tail); |
248 | *buf += nal_len; |
249 | *space_left -= nal_len; |
250 | } |
251 | |