]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
4f4ee9ee PZ |
2 | /* |
3 | * Coda multi-standard codec IP - H.264 helper functions | |
4 | * | |
5 | * Copyright (C) 2012 Vista Silicon S.L. | |
6 | * Javier Martin, <javier.martin@vista-silicon.com> | |
7 | * Xavier Duret | |
4f4ee9ee PZ |
8 | */ |
9 | ||
10 | #include <linux/kernel.h> | |
2c3759d4 | 11 | #include <linux/string.h> |
69122271 | 12 | #include <linux/videodev2.h> |
06c24f67 | 13 | #include <coda.h> |
4f4ee9ee | 14 | |
4f4ee9ee PZ |
15 | static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; |
16 | ||
69122271 PZ |
17 | static const u8 *coda_find_nal_header(const u8 *buf, const u8 *end) |
18 | { | |
19 | u32 val = 0xffffffff; | |
20 | ||
21 | do { | |
22 | val = val << 8 | *buf++; | |
23 | if (buf >= end) | |
24 | return NULL; | |
25 | } while (val != 0x00000001); | |
26 | ||
27 | return buf; | |
28 | } | |
29 | ||
30 | int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb) | |
31 | { | |
32 | const u8 *buf = vb2_plane_vaddr(vb, 0); | |
33 | const u8 *end = buf + vb2_get_plane_payload(vb, 0); | |
34 | ||
35 | /* Find SPS header */ | |
36 | do { | |
37 | buf = coda_find_nal_header(buf, end); | |
38 | if (!buf) | |
39 | return -EINVAL; | |
40 | } while ((*buf++ & 0x1f) != 0x7); | |
41 | ||
42 | ctx->params.h264_profile_idc = buf[0]; | |
43 | ctx->params.h264_level_idc = buf[2]; | |
44 | ||
45 | return 0; | |
46 | } | |
47 | ||
0eef8940 PZ |
48 | int coda_h264_filler_nal(int size, char *p) |
49 | { | |
50 | if (size < 6) | |
51 | return -EINVAL; | |
52 | ||
53 | p[0] = 0x00; | |
54 | p[1] = 0x00; | |
55 | p[2] = 0x00; | |
56 | p[3] = 0x01; | |
57 | p[4] = 0x0c; | |
58 | memset(p + 5, 0xff, size - 6); | |
59 | /* Add rbsp stop bit and trailing at the end */ | |
60 | p[size - 1] = 0x80; | |
61 | ||
62 | return 0; | |
63 | } | |
64 | ||
4f4ee9ee PZ |
65 | int coda_h264_padding(int size, char *p) |
66 | { | |
67 | int nal_size; | |
68 | int diff; | |
69 | ||
70 | diff = size - (size & ~0x7); | |
71 | if (diff == 0) | |
72 | return 0; | |
73 | ||
74 | nal_size = coda_filler_size[diff]; | |
0eef8940 | 75 | coda_h264_filler_nal(nal_size, p); |
4f4ee9ee PZ |
76 | |
77 | return nal_size; | |
78 | } | |
69122271 PZ |
79 | |
80 | int coda_h264_profile(int profile_idc) | |
81 | { | |
82 | switch (profile_idc) { | |
83 | case 66: return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; | |
84 | case 77: return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; | |
85 | case 88: return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED; | |
86 | case 100: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; | |
87 | default: return -EINVAL; | |
88 | } | |
89 | } | |
90 | ||
91 | int coda_h264_level(int level_idc) | |
92 | { | |
93 | switch (level_idc) { | |
94 | case 10: return V4L2_MPEG_VIDEO_H264_LEVEL_1_0; | |
95 | case 9: return V4L2_MPEG_VIDEO_H264_LEVEL_1B; | |
96 | case 11: return V4L2_MPEG_VIDEO_H264_LEVEL_1_1; | |
97 | case 12: return V4L2_MPEG_VIDEO_H264_LEVEL_1_2; | |
98 | case 13: return V4L2_MPEG_VIDEO_H264_LEVEL_1_3; | |
99 | case 20: return V4L2_MPEG_VIDEO_H264_LEVEL_2_0; | |
100 | case 21: return V4L2_MPEG_VIDEO_H264_LEVEL_2_1; | |
101 | case 22: return V4L2_MPEG_VIDEO_H264_LEVEL_2_2; | |
102 | case 30: return V4L2_MPEG_VIDEO_H264_LEVEL_3_0; | |
103 | case 31: return V4L2_MPEG_VIDEO_H264_LEVEL_3_1; | |
104 | case 32: return V4L2_MPEG_VIDEO_H264_LEVEL_3_2; | |
105 | case 40: return V4L2_MPEG_VIDEO_H264_LEVEL_4_0; | |
106 | case 41: return V4L2_MPEG_VIDEO_H264_LEVEL_4_1; | |
22fb5f0f PZ |
107 | case 42: return V4L2_MPEG_VIDEO_H264_LEVEL_4_2; |
108 | case 50: return V4L2_MPEG_VIDEO_H264_LEVEL_5_0; | |
109 | case 51: return V4L2_MPEG_VIDEO_H264_LEVEL_5_1; | |
69122271 PZ |
110 | default: return -EINVAL; |
111 | } | |
112 | } | |
0dff710d PZ |
113 | |
114 | struct rbsp { | |
115 | char *buf; | |
116 | int size; | |
117 | int pos; | |
118 | }; | |
119 | ||
120 | static inline int rbsp_read_bit(struct rbsp *rbsp) | |
121 | { | |
122 | int shift = 7 - (rbsp->pos % 8); | |
123 | int ofs = rbsp->pos++ / 8; | |
124 | ||
125 | if (ofs >= rbsp->size) | |
126 | return -EINVAL; | |
127 | ||
128 | return (rbsp->buf[ofs] >> shift) & 1; | |
129 | } | |
130 | ||
131 | static inline int rbsp_write_bit(struct rbsp *rbsp, int bit) | |
132 | { | |
133 | int shift = 7 - (rbsp->pos % 8); | |
134 | int ofs = rbsp->pos++ / 8; | |
135 | ||
136 | if (ofs >= rbsp->size) | |
137 | return -EINVAL; | |
138 | ||
139 | rbsp->buf[ofs] &= ~(1 << shift); | |
140 | rbsp->buf[ofs] |= bit << shift; | |
141 | ||
142 | return 0; | |
143 | } | |
144 | ||
145 | static inline int rbsp_read_bits(struct rbsp *rbsp, int num, int *val) | |
146 | { | |
147 | int i, ret; | |
148 | int tmp = 0; | |
149 | ||
150 | if (num > 32) | |
151 | return -EINVAL; | |
152 | ||
153 | for (i = 0; i < num; i++) { | |
154 | ret = rbsp_read_bit(rbsp); | |
155 | if (ret < 0) | |
156 | return ret; | |
157 | tmp |= ret << (num - i - 1); | |
158 | } | |
159 | ||
160 | if (val) | |
161 | *val = tmp; | |
162 | ||
163 | return 0; | |
164 | } | |
165 | ||
166 | static int rbsp_write_bits(struct rbsp *rbsp, int num, int value) | |
167 | { | |
168 | int ret; | |
169 | ||
170 | while (num--) { | |
171 | ret = rbsp_write_bit(rbsp, (value >> num) & 1); | |
172 | if (ret) | |
173 | return ret; | |
174 | } | |
175 | ||
176 | return 0; | |
177 | } | |
178 | ||
179 | static int rbsp_read_uev(struct rbsp *rbsp, unsigned int *val) | |
180 | { | |
181 | int leading_zero_bits = 0; | |
182 | unsigned int tmp = 0; | |
183 | int ret; | |
184 | ||
185 | while ((ret = rbsp_read_bit(rbsp)) == 0) | |
186 | leading_zero_bits++; | |
187 | if (ret < 0) | |
188 | return ret; | |
189 | ||
190 | if (leading_zero_bits > 0) { | |
191 | ret = rbsp_read_bits(rbsp, leading_zero_bits, &tmp); | |
192 | if (ret) | |
193 | return ret; | |
194 | } | |
195 | ||
196 | if (val) | |
197 | *val = (1 << leading_zero_bits) - 1 + tmp; | |
198 | ||
199 | return 0; | |
200 | } | |
201 | ||
202 | static int rbsp_write_uev(struct rbsp *rbsp, unsigned int value) | |
203 | { | |
204 | int i; | |
205 | int ret; | |
206 | int tmp = value + 1; | |
207 | int leading_zero_bits = fls(tmp) - 1; | |
208 | ||
209 | for (i = 0; i < leading_zero_bits; i++) { | |
210 | ret = rbsp_write_bit(rbsp, 0); | |
211 | if (ret) | |
212 | return ret; | |
213 | } | |
214 | ||
215 | return rbsp_write_bits(rbsp, leading_zero_bits + 1, tmp); | |
216 | } | |
217 | ||
218 | static int rbsp_read_sev(struct rbsp *rbsp, int *val) | |
219 | { | |
220 | unsigned int tmp; | |
221 | int ret; | |
222 | ||
223 | ret = rbsp_read_uev(rbsp, &tmp); | |
224 | if (ret) | |
225 | return ret; | |
226 | ||
227 | if (val) { | |
228 | if (tmp & 1) | |
229 | *val = (tmp + 1) / 2; | |
230 | else | |
231 | *val = -(tmp / 2); | |
232 | } | |
233 | ||
234 | return 0; | |
235 | } | |
236 | ||
237 | /** | |
238 | * coda_h264_sps_fixup - fixes frame cropping values in h.264 SPS | |
239 | * @ctx: encoder context | |
240 | * @width: visible width | |
241 | * @height: visible height | |
242 | * @buf: buffer containing h.264 SPS RBSP, starting with NAL header | |
243 | * @size: modified RBSP size return value | |
244 | * @max_size: available size in buf | |
245 | * | |
246 | * Rewrites the frame cropping values in an h.264 SPS RBSP correctly for the | |
247 | * given visible width and height. | |
248 | */ | |
249 | int coda_h264_sps_fixup(struct coda_ctx *ctx, int width, int height, char *buf, | |
250 | int *size, int max_size) | |
251 | { | |
252 | int profile_idc; | |
253 | unsigned int pic_order_cnt_type; | |
254 | int pic_width_in_mbs_minus1, pic_height_in_map_units_minus1; | |
255 | int frame_mbs_only_flag, frame_cropping_flag; | |
256 | int vui_parameters_present_flag; | |
257 | unsigned int crop_right, crop_bottom; | |
258 | struct rbsp sps; | |
259 | int pos; | |
260 | int ret; | |
261 | ||
262 | if (*size < 8 || *size >= max_size) | |
263 | return -EINVAL; | |
264 | ||
265 | sps.buf = buf + 5; /* Skip NAL header */ | |
266 | sps.size = *size - 5; | |
267 | ||
268 | profile_idc = sps.buf[0]; | |
269 | /* Skip constraint_set[0-5]_flag, reserved_zero_2bits */ | |
270 | /* Skip level_idc */ | |
271 | sps.pos = 24; | |
272 | ||
273 | /* seq_parameter_set_id */ | |
274 | ret = rbsp_read_uev(&sps, NULL); | |
275 | if (ret) | |
276 | return ret; | |
277 | ||
278 | if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || | |
279 | profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || | |
280 | profile_idc == 86 || profile_idc == 118 || profile_idc == 128 || | |
281 | profile_idc == 138 || profile_idc == 139 || profile_idc == 134 || | |
282 | profile_idc == 135) { | |
283 | dev_err(ctx->fh.vdev->dev_parent, | |
284 | "%s: Handling profile_idc %d not implemented\n", | |
285 | __func__, profile_idc); | |
286 | return -EINVAL; | |
287 | } | |
288 | ||
289 | /* log2_max_frame_num_minus4 */ | |
290 | ret = rbsp_read_uev(&sps, NULL); | |
291 | if (ret) | |
292 | return ret; | |
293 | ||
294 | ret = rbsp_read_uev(&sps, &pic_order_cnt_type); | |
295 | if (ret) | |
296 | return ret; | |
297 | ||
298 | if (pic_order_cnt_type == 0) { | |
299 | /* log2_max_pic_order_cnt_lsb_minus4 */ | |
300 | ret = rbsp_read_uev(&sps, NULL); | |
301 | if (ret) | |
302 | return ret; | |
303 | } else if (pic_order_cnt_type == 1) { | |
304 | unsigned int i, num_ref_frames_in_pic_order_cnt_cycle; | |
305 | ||
306 | /* delta_pic_order_always_zero_flag */ | |
307 | ret = rbsp_read_bit(&sps); | |
308 | if (ret < 0) | |
309 | return ret; | |
310 | /* offset_for_non_ref_pic */ | |
311 | ret = rbsp_read_sev(&sps, NULL); | |
312 | if (ret) | |
313 | return ret; | |
314 | /* offset_for_top_to_bottom_field */ | |
315 | ret = rbsp_read_sev(&sps, NULL); | |
316 | if (ret) | |
317 | return ret; | |
318 | ||
319 | ret = rbsp_read_uev(&sps, | |
320 | &num_ref_frames_in_pic_order_cnt_cycle); | |
321 | if (ret) | |
322 | return ret; | |
323 | for (i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) { | |
324 | /* offset_for_ref_frame */ | |
325 | ret = rbsp_read_sev(&sps, NULL); | |
326 | if (ret) | |
327 | return ret; | |
328 | } | |
329 | } | |
330 | ||
331 | /* max_num_ref_frames */ | |
332 | ret = rbsp_read_uev(&sps, NULL); | |
333 | if (ret) | |
334 | return ret; | |
335 | ||
336 | /* gaps_in_frame_num_value_allowed_flag */ | |
337 | ret = rbsp_read_bit(&sps); | |
338 | if (ret < 0) | |
339 | return ret; | |
340 | ret = rbsp_read_uev(&sps, &pic_width_in_mbs_minus1); | |
341 | if (ret) | |
342 | return ret; | |
343 | ret = rbsp_read_uev(&sps, &pic_height_in_map_units_minus1); | |
344 | if (ret) | |
345 | return ret; | |
346 | frame_mbs_only_flag = ret = rbsp_read_bit(&sps); | |
347 | if (ret < 0) | |
348 | return ret; | |
349 | if (!frame_mbs_only_flag) { | |
350 | /* mb_adaptive_frame_field_flag */ | |
351 | ret = rbsp_read_bit(&sps); | |
352 | if (ret < 0) | |
353 | return ret; | |
354 | } | |
355 | /* direct_8x8_inference_flag */ | |
356 | ret = rbsp_read_bit(&sps); | |
357 | if (ret < 0) | |
358 | return ret; | |
359 | ||
360 | /* Mark position of the frame cropping flag */ | |
361 | pos = sps.pos; | |
362 | frame_cropping_flag = ret = rbsp_read_bit(&sps); | |
363 | if (ret < 0) | |
364 | return ret; | |
365 | if (frame_cropping_flag) { | |
366 | unsigned int crop_left, crop_top; | |
367 | ||
368 | ret = rbsp_read_uev(&sps, &crop_left); | |
369 | if (ret) | |
370 | return ret; | |
371 | ret = rbsp_read_uev(&sps, &crop_right); | |
372 | if (ret) | |
373 | return ret; | |
374 | ret = rbsp_read_uev(&sps, &crop_top); | |
375 | if (ret) | |
376 | return ret; | |
377 | ret = rbsp_read_uev(&sps, &crop_bottom); | |
378 | if (ret) | |
379 | return ret; | |
380 | } | |
381 | vui_parameters_present_flag = ret = rbsp_read_bit(&sps); | |
382 | if (ret < 0) | |
383 | return ret; | |
384 | if (vui_parameters_present_flag) { | |
385 | dev_err(ctx->fh.vdev->dev_parent, | |
386 | "%s: Handling vui_parameters not implemented\n", | |
387 | __func__); | |
388 | return -EINVAL; | |
389 | } | |
390 | ||
391 | crop_right = round_up(width, 16) - width; | |
392 | crop_bottom = round_up(height, 16) - height; | |
393 | crop_right /= 2; | |
394 | if (frame_mbs_only_flag) | |
395 | crop_bottom /= 2; | |
396 | else | |
397 | crop_bottom /= 4; | |
398 | ||
399 | ||
400 | sps.size = max_size - 5; | |
401 | sps.pos = pos; | |
402 | frame_cropping_flag = 1; | |
403 | ret = rbsp_write_bit(&sps, frame_cropping_flag); | |
404 | if (ret) | |
405 | return ret; | |
406 | ret = rbsp_write_uev(&sps, 0); /* crop_left */ | |
407 | if (ret) | |
408 | return ret; | |
409 | ret = rbsp_write_uev(&sps, crop_right); | |
410 | if (ret) | |
411 | return ret; | |
412 | ret = rbsp_write_uev(&sps, 0); /* crop_top */ | |
413 | if (ret) | |
414 | return ret; | |
415 | ret = rbsp_write_uev(&sps, crop_bottom); | |
416 | if (ret) | |
417 | return ret; | |
418 | ret = rbsp_write_bit(&sps, 0); /* vui_parameters_present_flag */ | |
419 | if (ret) | |
420 | return ret; | |
421 | ret = rbsp_write_bit(&sps, 1); | |
422 | if (ret) | |
423 | return ret; | |
424 | ||
425 | *size = 5 + DIV_ROUND_UP(sps.pos, 8); | |
426 | ||
427 | return 0; | |
428 | } |