• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * V4L2 H264 helpers.
4  *
5  * Copyright (C) 2019 Collabora, Ltd.
6  *
7  * Author: Boris Brezillon <boris.brezillon@collabora.com>
8  */
9 
10 #include <linux/module.h>
11 #include <linux/sort.h>
12 
13 #include <media/v4l2-h264.h>
14 
15 /*
16  * Size of the tempory buffer allocated when printing reference lists. The
17  * output will be truncated if the size is too small.
18  */
19 static const int tmp_str_size = 1024;
20 
21 /**
22  * v4l2_h264_init_reflist_builder() - Initialize a P/B0/B1 reference list
23  *				      builder
24  *
25  * @b: the builder context to initialize
26  * @dec_params: decode parameters control
27  * @sps: SPS control
28  * @dpb: DPB to use when creating the reference list
29  */
30 void
v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder * b,const struct v4l2_ctrl_h264_decode_params * dec_params,const struct v4l2_ctrl_h264_sps * sps,const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES])31 v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
32 		const struct v4l2_ctrl_h264_decode_params *dec_params,
33 		const struct v4l2_ctrl_h264_sps *sps,
34 		const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES])
35 {
36 	int cur_frame_num, max_frame_num;
37 	unsigned int i;
38 
39 	max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
40 	cur_frame_num = dec_params->frame_num;
41 
42 	memset(b, 0, sizeof(*b));
43 	if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) {
44 		b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt,
45 					     dec_params->top_field_order_cnt);
46 		b->cur_pic_fields = V4L2_H264_FRAME_REF;
47 	} else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) {
48 		b->cur_pic_order_count = dec_params->bottom_field_order_cnt;
49 		b->cur_pic_fields = V4L2_H264_BOTTOM_FIELD_REF;
50 	} else {
51 		b->cur_pic_order_count = dec_params->top_field_order_cnt;
52 		b->cur_pic_fields = V4L2_H264_TOP_FIELD_REF;
53 	}
54 
55 	for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
56 		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
57 			continue;
58 
59 		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
60 			b->refs[i].longterm = true;
61 
62 		/*
63 		 * Handle frame_num wraparound as described in section
64 		 * '8.2.4.1 Decoding process for picture numbers' of the spec.
65 		 * For long term references, frame_num is set to
66 		 * long_term_frame_idx which requires no wrapping.
67 		 */
68 		if (!b->refs[i].longterm && dpb[i].frame_num > cur_frame_num)
69 			b->refs[i].frame_num = (int)dpb[i].frame_num -
70 					       max_frame_num;
71 		else
72 			b->refs[i].frame_num = dpb[i].frame_num;
73 
74 		b->refs[i].top_field_order_cnt = dpb[i].top_field_order_cnt;
75 		b->refs[i].bottom_field_order_cnt = dpb[i].bottom_field_order_cnt;
76 
77 		if (b->cur_pic_fields == V4L2_H264_FRAME_REF) {
78 			u8 fields = V4L2_H264_FRAME_REF;
79 
80 			b->unordered_reflist[b->num_valid].index = i;
81 			b->unordered_reflist[b->num_valid].fields = fields;
82 			b->num_valid++;
83 			continue;
84 		}
85 
86 		if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF) {
87 			u8 fields = V4L2_H264_TOP_FIELD_REF;
88 
89 			b->unordered_reflist[b->num_valid].index = i;
90 			b->unordered_reflist[b->num_valid].fields = fields;
91 			b->num_valid++;
92 		}
93 
94 		if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF) {
95 			u8 fields = V4L2_H264_BOTTOM_FIELD_REF;
96 
97 			b->unordered_reflist[b->num_valid].index = i;
98 			b->unordered_reflist[b->num_valid].fields = fields;
99 			b->num_valid++;
100 		}
101 	}
102 
103 	for (i = b->num_valid; i < ARRAY_SIZE(b->unordered_reflist); i++)
104 		b->unordered_reflist[i].index = i;
105 }
106 EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder);
107 
v4l2_h264_get_poc(const struct v4l2_h264_reflist_builder * b,const struct v4l2_h264_reference * ref)108 static s32 v4l2_h264_get_poc(const struct v4l2_h264_reflist_builder *b,
109 			     const struct v4l2_h264_reference *ref)
110 {
111 	switch (ref->fields) {
112 	case V4L2_H264_FRAME_REF:
113 		return min(b->refs[ref->index].top_field_order_cnt,
114 				b->refs[ref->index].bottom_field_order_cnt);
115 	case V4L2_H264_TOP_FIELD_REF:
116 		return b->refs[ref->index].top_field_order_cnt;
117 	case V4L2_H264_BOTTOM_FIELD_REF:
118 		return b->refs[ref->index].bottom_field_order_cnt;
119 	}
120 
121 	/* not reached */
122 	return 0;
123 }
124 
v4l2_h264_p_ref_list_cmp(const void * ptra,const void * ptrb,const void * data)125 static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb,
126 				    const void *data)
127 {
128 	const struct v4l2_h264_reflist_builder *builder = data;
129 	u8 idxa, idxb;
130 
131 	idxa = ((struct v4l2_h264_reference *)ptra)->index;
132 	idxb = ((struct v4l2_h264_reference *)ptrb)->index;
133 
134 	if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
135 		    idxb >= V4L2_H264_NUM_DPB_ENTRIES))
136 		return 1;
137 
138 	if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
139 		/* Short term pics first. */
140 		if (!builder->refs[idxa].longterm)
141 			return -1;
142 		else
143 			return 1;
144 	}
145 
146 	/*
147 	 * For frames, short term pics are in descending pic num order and long
148 	 * term ones in ascending order. For fields, the same direction is used
149 	 * but with frame_num (wrapped). For frames, the value of pic_num and
150 	 * frame_num are the same (see formula (8-28) and (8-29)). For this
151 	 * reason we can use frame_num only and share this function between
152 	 * frames and fields reflist.
153 	 */
154 	if (!builder->refs[idxa].longterm)
155 		return builder->refs[idxb].frame_num <
156 		       builder->refs[idxa].frame_num ?
157 		       -1 : 1;
158 
159 	return builder->refs[idxa].frame_num < builder->refs[idxb].frame_num ?
160 	       -1 : 1;
161 }
162 
v4l2_h264_b0_ref_list_cmp(const void * ptra,const void * ptrb,const void * data)163 static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb,
164 				     const void *data)
165 {
166 	const struct v4l2_h264_reflist_builder *builder = data;
167 	s32 poca, pocb;
168 	u8 idxa, idxb;
169 
170 	idxa = ((struct v4l2_h264_reference *)ptra)->index;
171 	idxb = ((struct v4l2_h264_reference *)ptrb)->index;
172 
173 	if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
174 		    idxb >= V4L2_H264_NUM_DPB_ENTRIES))
175 		return 1;
176 
177 	if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
178 		/* Short term pics first. */
179 		if (!builder->refs[idxa].longterm)
180 			return -1;
181 		else
182 			return 1;
183 	}
184 
185 	/* Long term pics in ascending frame num order. */
186 	if (builder->refs[idxa].longterm)
187 		return builder->refs[idxa].frame_num <
188 		       builder->refs[idxb].frame_num ?
189 		       -1 : 1;
190 
191 	poca = v4l2_h264_get_poc(builder, ptra);
192 	pocb = v4l2_h264_get_poc(builder, ptrb);
193 
194 	/*
195 	 * Short term pics with POC < cur POC first in POC descending order
196 	 * followed by short term pics with POC > cur POC in POC ascending
197 	 * order.
198 	 */
199 	if ((poca < builder->cur_pic_order_count) !=
200 	     (pocb < builder->cur_pic_order_count))
201 		return poca < pocb ? -1 : 1;
202 	else if (poca < builder->cur_pic_order_count)
203 		return pocb < poca ? -1 : 1;
204 
205 	return poca < pocb ? -1 : 1;
206 }
207 
v4l2_h264_b1_ref_list_cmp(const void * ptra,const void * ptrb,const void * data)208 static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb,
209 				     const void *data)
210 {
211 	const struct v4l2_h264_reflist_builder *builder = data;
212 	s32 poca, pocb;
213 	u8 idxa, idxb;
214 
215 	idxa = ((struct v4l2_h264_reference *)ptra)->index;
216 	idxb = ((struct v4l2_h264_reference *)ptrb)->index;
217 
218 	if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
219 		    idxb >= V4L2_H264_NUM_DPB_ENTRIES))
220 		return 1;
221 
222 	if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
223 		/* Short term pics first. */
224 		if (!builder->refs[idxa].longterm)
225 			return -1;
226 		else
227 			return 1;
228 	}
229 
230 	/* Long term pics in ascending frame num order. */
231 	if (builder->refs[idxa].longterm)
232 		return builder->refs[idxa].frame_num <
233 		       builder->refs[idxb].frame_num ?
234 		       -1 : 1;
235 
236 	poca = v4l2_h264_get_poc(builder, ptra);
237 	pocb = v4l2_h264_get_poc(builder, ptrb);
238 
239 	/*
240 	 * Short term pics with POC > cur POC first in POC ascending order
241 	 * followed by short term pics with POC < cur POC in POC descending
242 	 * order.
243 	 */
244 	if ((poca < builder->cur_pic_order_count) !=
245 	    (pocb < builder->cur_pic_order_count))
246 		return pocb < poca ? -1 : 1;
247 	else if (poca < builder->cur_pic_order_count)
248 		return pocb < poca ? -1 : 1;
249 
250 	return poca < pocb ? -1 : 1;
251 }
252 
253 /*
254  * The references need to be reordered so that references are alternating
255  * between top and bottom field references starting with the current picture
256  * parity. This has to be done for short term and long term references
257  * separately.
258  */
reorder_field_reflist(const struct v4l2_h264_reflist_builder * b,struct v4l2_h264_reference * reflist)259 static void reorder_field_reflist(const struct v4l2_h264_reflist_builder *b,
260 				  struct v4l2_h264_reference *reflist)
261 {
262 	struct v4l2_h264_reference tmplist[V4L2_H264_REF_LIST_LEN];
263 	u8 lt, i = 0, j = 0, k = 0;
264 
265 	memcpy(tmplist, reflist, sizeof(tmplist[0]) * b->num_valid);
266 
267 	for (lt = 0; lt <= 1; lt++) {
268 		do {
269 			for (; i < b->num_valid && b->refs[tmplist[i].index].longterm == lt; i++) {
270 				if (tmplist[i].fields == b->cur_pic_fields) {
271 					reflist[k++] = tmplist[i++];
272 					break;
273 				}
274 			}
275 
276 			for (; j < b->num_valid && b->refs[tmplist[j].index].longterm == lt; j++) {
277 				if (tmplist[j].fields != b->cur_pic_fields) {
278 					reflist[k++] = tmplist[j++];
279 					break;
280 				}
281 			}
282 		} while ((i < b->num_valid && b->refs[tmplist[i].index].longterm == lt) ||
283 			 (j < b->num_valid && b->refs[tmplist[j].index].longterm == lt));
284 	}
285 }
286 
ref_type_to_char(u8 ref_type)287 static char ref_type_to_char(u8 ref_type)
288 {
289 	switch (ref_type) {
290 	case V4L2_H264_FRAME_REF:
291 		return 'f';
292 	case V4L2_H264_TOP_FIELD_REF:
293 		return 't';
294 	case V4L2_H264_BOTTOM_FIELD_REF:
295 		return 'b';
296 	}
297 
298 	return '?';
299 }
300 
format_ref_list_p(const struct v4l2_h264_reflist_builder * builder,struct v4l2_h264_reference * reflist,char ** out_str)301 static const char *format_ref_list_p(const struct v4l2_h264_reflist_builder *builder,
302 				     struct v4l2_h264_reference *reflist,
303 				     char **out_str)
304 {
305 	int n = 0, i;
306 
307 	*out_str = kmalloc(tmp_str_size, GFP_KERNEL);
308 	if (!(*out_str))
309 		return NULL;
310 
311 	n += snprintf(*out_str + n, tmp_str_size - n, "|");
312 
313 	for (i = 0; i < builder->num_valid; i++) {
314 		/* this is pic_num for frame and frame_num (wrapped) for field,
315 		 * but for frame pic_num is equal to frame_num (wrapped).
316 		 */
317 		int frame_num = builder->refs[reflist[i].index].frame_num;
318 		bool longterm = builder->refs[reflist[i].index].longterm;
319 
320 		n += scnprintf(*out_str + n, tmp_str_size - n, "%i%c%c|",
321 			       frame_num, longterm ? 'l' : 's',
322 			       ref_type_to_char(reflist[i].fields));
323 	}
324 
325 	return *out_str;
326 }
327 
print_ref_list_p(const struct v4l2_h264_reflist_builder * builder,struct v4l2_h264_reference * reflist)328 static void print_ref_list_p(const struct v4l2_h264_reflist_builder *builder,
329 			     struct v4l2_h264_reference *reflist)
330 {
331 	char *buf = NULL;
332 
333 	pr_debug("ref_pic_list_p (cur_poc %u%c) %s\n",
334 		 builder->cur_pic_order_count,
335 		 ref_type_to_char(builder->cur_pic_fields),
336 		 format_ref_list_p(builder, reflist, &buf));
337 
338 	kfree(buf);
339 }
340 
format_ref_list_b(const struct v4l2_h264_reflist_builder * builder,struct v4l2_h264_reference * reflist,char ** out_str)341 static const char *format_ref_list_b(const struct v4l2_h264_reflist_builder *builder,
342 				     struct v4l2_h264_reference *reflist,
343 				     char **out_str)
344 {
345 	int n = 0, i;
346 
347 	*out_str = kmalloc(tmp_str_size, GFP_KERNEL);
348 	if (!(*out_str))
349 		return NULL;
350 
351 	n += snprintf(*out_str + n, tmp_str_size - n, "|");
352 
353 	for (i = 0; i < builder->num_valid; i++) {
354 		int frame_num = builder->refs[reflist[i].index].frame_num;
355 		u32 poc = v4l2_h264_get_poc(builder, reflist + i);
356 		bool longterm = builder->refs[reflist[i].index].longterm;
357 
358 		n += scnprintf(*out_str + n, tmp_str_size - n, "%i%c%c|",
359 			       longterm ? frame_num : poc,
360 			       longterm ? 'l' : 's',
361 			       ref_type_to_char(reflist[i].fields));
362 	}
363 
364 	return *out_str;
365 }
366 
print_ref_list_b(const struct v4l2_h264_reflist_builder * builder,struct v4l2_h264_reference * reflist,u8 list_num)367 static void print_ref_list_b(const struct v4l2_h264_reflist_builder *builder,
368 			     struct v4l2_h264_reference *reflist, u8 list_num)
369 {
370 	char *buf = NULL;
371 
372 	pr_debug("ref_pic_list_b%u (cur_poc %u%c) %s",
373 		 list_num, builder->cur_pic_order_count,
374 		 ref_type_to_char(builder->cur_pic_fields),
375 		 format_ref_list_b(builder, reflist, &buf));
376 
377 	kfree(buf);
378 }
379 
380 /**
381  * v4l2_h264_build_p_ref_list() - Build the P reference list
382  *
383  * @builder: reference list builder context
384  * @reflist: 32 sized array used to store the P reference list. Each entry
385  *	     is a v4l2_h264_reference structure
386  *
387  * This functions builds the P reference lists. This procedure is describe in
388  * section '8.2.4 Decoding process for reference picture lists construction'
389  * of the H264 spec. This function can be used by H264 decoder drivers that
390  * need to pass a P reference list to the hardware.
391  */
392 void
v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder * builder,struct v4l2_h264_reference * reflist)393 v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder,
394 			   struct v4l2_h264_reference *reflist)
395 {
396 	memcpy(reflist, builder->unordered_reflist,
397 	       sizeof(builder->unordered_reflist[0]) * builder->num_valid);
398 	sort_r(reflist, builder->num_valid, sizeof(*reflist),
399 	       v4l2_h264_p_ref_list_cmp, NULL, builder);
400 
401 	if (builder->cur_pic_fields != V4L2_H264_FRAME_REF)
402 		reorder_field_reflist(builder, reflist);
403 
404 	print_ref_list_p(builder, reflist);
405 }
406 EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list);
407 
408 /**
409  * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists
410  *
411  * @builder: reference list builder context
412  * @b0_reflist: 32 sized array used to store the B0 reference list. Each entry
413  *		is a v4l2_h264_reference structure
414  * @b1_reflist: 32 sized array used to store the B1 reference list. Each entry
415  *		is a v4l2_h264_reference structure
416  *
417  * This functions builds the B0/B1 reference lists. This procedure is described
418  * in section '8.2.4 Decoding process for reference picture lists construction'
419  * of the H264 spec. This function can be used by H264 decoder drivers that
420  * need to pass B0/B1 reference lists to the hardware.
421  */
422 void
v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder * builder,struct v4l2_h264_reference * b0_reflist,struct v4l2_h264_reference * b1_reflist)423 v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder,
424 			    struct v4l2_h264_reference *b0_reflist,
425 			    struct v4l2_h264_reference *b1_reflist)
426 {
427 	memcpy(b0_reflist, builder->unordered_reflist,
428 	       sizeof(builder->unordered_reflist[0]) * builder->num_valid);
429 	sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist),
430 	       v4l2_h264_b0_ref_list_cmp, NULL, builder);
431 
432 	memcpy(b1_reflist, builder->unordered_reflist,
433 	       sizeof(builder->unordered_reflist[0]) * builder->num_valid);
434 	sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist),
435 	       v4l2_h264_b1_ref_list_cmp, NULL, builder);
436 
437 	if (builder->cur_pic_fields != V4L2_H264_FRAME_REF) {
438 		reorder_field_reflist(builder, b0_reflist);
439 		reorder_field_reflist(builder, b1_reflist);
440 	}
441 
442 	if (builder->num_valid > 1 &&
443 	    !memcmp(b1_reflist, b0_reflist, builder->num_valid))
444 		swap(b1_reflist[0], b1_reflist[1]);
445 
446 	print_ref_list_b(builder, b0_reflist, 0);
447 	print_ref_list_b(builder, b1_reflist, 1);
448 }
449 EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists);
450 
451 MODULE_LICENSE("GPL");
452 MODULE_DESCRIPTION("V4L2 H264 Helpers");
453 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");
454