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 */
19static 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 */
30void
31v4l2_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}
106EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder);
107
108static 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
125static 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
163static 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
208static 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 */
259static 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
287static 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
301static 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
328static 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
341static 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
367static 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 */
392void
393v4l2_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}
406EXPORT_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 */
422void
423v4l2_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}
449EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists);
450
451MODULE_LICENSE("GPL");
452MODULE_DESCRIPTION("V4L2 H264 Helpers");
453MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");
454