xref: /OK3568_Linux_fs/kernel/drivers/media/v4l2-core/v4l2-h264.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * V4L2 H264 helpers.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2019 Collabora, Ltd.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Boris Brezillon <boris.brezillon@collabora.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/sort.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <media/v4l2-h264.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun /**
16*4882a593Smuzhiyun  * v4l2_h264_init_reflist_builder() - Initialize a P/B0/B1 reference list
17*4882a593Smuzhiyun  *				      builder
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * @b: the builder context to initialize
20*4882a593Smuzhiyun  * @dec_params: decode parameters control
21*4882a593Smuzhiyun  * @sps: SPS control
22*4882a593Smuzhiyun  * @dpb: DPB to use when creating the reference list
23*4882a593Smuzhiyun  */
24*4882a593Smuzhiyun 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])25*4882a593Smuzhiyun v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
26*4882a593Smuzhiyun 		const struct v4l2_ctrl_h264_decode_params *dec_params,
27*4882a593Smuzhiyun 		const struct v4l2_ctrl_h264_sps *sps,
28*4882a593Smuzhiyun 		const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES])
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun 	int cur_frame_num, max_frame_num;
31*4882a593Smuzhiyun 	unsigned int i;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
34*4882a593Smuzhiyun 	cur_frame_num = dec_params->frame_num;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	memset(b, 0, sizeof(*b));
37*4882a593Smuzhiyun 	if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC))
38*4882a593Smuzhiyun 		b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt,
39*4882a593Smuzhiyun 					     dec_params->top_field_order_cnt);
40*4882a593Smuzhiyun 	else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD)
41*4882a593Smuzhiyun 		b->cur_pic_order_count = dec_params->bottom_field_order_cnt;
42*4882a593Smuzhiyun 	else
43*4882a593Smuzhiyun 		b->cur_pic_order_count = dec_params->top_field_order_cnt;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
46*4882a593Smuzhiyun 		u32 pic_order_count;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
49*4882a593Smuzhiyun 			continue;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 		b->refs[i].pic_num = dpb[i].pic_num;
52*4882a593Smuzhiyun 		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
53*4882a593Smuzhiyun 			b->refs[i].longterm = true;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 		/*
56*4882a593Smuzhiyun 		 * Handle frame_num wraparound as described in section
57*4882a593Smuzhiyun 		 * '8.2.4.1 Decoding process for picture numbers' of the spec.
58*4882a593Smuzhiyun 		 * TODO: This logic will have to be adjusted when we start
59*4882a593Smuzhiyun 		 * supporting interlaced content.
60*4882a593Smuzhiyun 		 */
61*4882a593Smuzhiyun 		if (dpb[i].frame_num > cur_frame_num)
62*4882a593Smuzhiyun 			b->refs[i].frame_num = (int)dpb[i].frame_num -
63*4882a593Smuzhiyun 					       max_frame_num;
64*4882a593Smuzhiyun 		else
65*4882a593Smuzhiyun 			b->refs[i].frame_num = dpb[i].frame_num;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 		if (dpb[i].fields == V4L2_H264_FRAME_REF)
68*4882a593Smuzhiyun 			pic_order_count = min(dpb[i].top_field_order_cnt,
69*4882a593Smuzhiyun 					      dpb[i].bottom_field_order_cnt);
70*4882a593Smuzhiyun 		else if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)
71*4882a593Smuzhiyun 			pic_order_count = dpb[i].bottom_field_order_cnt;
72*4882a593Smuzhiyun 		else
73*4882a593Smuzhiyun 			pic_order_count = dpb[i].top_field_order_cnt;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 		b->refs[i].pic_order_count = pic_order_count;
76*4882a593Smuzhiyun 		b->unordered_reflist[b->num_valid] = i;
77*4882a593Smuzhiyun 		b->num_valid++;
78*4882a593Smuzhiyun 	}
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	for (i = b->num_valid; i < ARRAY_SIZE(b->unordered_reflist); i++)
81*4882a593Smuzhiyun 		b->unordered_reflist[i] = i;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder);
84*4882a593Smuzhiyun 
v4l2_h264_p_ref_list_cmp(const void * ptra,const void * ptrb,const void * data)85*4882a593Smuzhiyun static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb,
86*4882a593Smuzhiyun 				    const void *data)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	const struct v4l2_h264_reflist_builder *builder = data;
89*4882a593Smuzhiyun 	u8 idxa, idxb;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	idxa = *((u8 *)ptra);
92*4882a593Smuzhiyun 	idxb = *((u8 *)ptrb);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
95*4882a593Smuzhiyun 		    idxb >= V4L2_H264_NUM_DPB_ENTRIES))
96*4882a593Smuzhiyun 		return 1;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
99*4882a593Smuzhiyun 		/* Short term pics first. */
100*4882a593Smuzhiyun 		if (!builder->refs[idxa].longterm)
101*4882a593Smuzhiyun 			return -1;
102*4882a593Smuzhiyun 		else
103*4882a593Smuzhiyun 			return 1;
104*4882a593Smuzhiyun 	}
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	/*
107*4882a593Smuzhiyun 	 * Short term pics in descending pic num order, long term ones in
108*4882a593Smuzhiyun 	 * ascending order.
109*4882a593Smuzhiyun 	 */
110*4882a593Smuzhiyun 	if (!builder->refs[idxa].longterm)
111*4882a593Smuzhiyun 		return builder->refs[idxb].frame_num <
112*4882a593Smuzhiyun 		       builder->refs[idxa].frame_num ?
113*4882a593Smuzhiyun 		       -1 : 1;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	return builder->refs[idxa].pic_num < builder->refs[idxb].pic_num ?
116*4882a593Smuzhiyun 	       -1 : 1;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
v4l2_h264_b0_ref_list_cmp(const void * ptra,const void * ptrb,const void * data)119*4882a593Smuzhiyun static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb,
120*4882a593Smuzhiyun 				     const void *data)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	const struct v4l2_h264_reflist_builder *builder = data;
123*4882a593Smuzhiyun 	s32 poca, pocb;
124*4882a593Smuzhiyun 	u8 idxa, idxb;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	idxa = *((u8 *)ptra);
127*4882a593Smuzhiyun 	idxb = *((u8 *)ptrb);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
130*4882a593Smuzhiyun 		    idxb >= V4L2_H264_NUM_DPB_ENTRIES))
131*4882a593Smuzhiyun 		return 1;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
134*4882a593Smuzhiyun 		/* Short term pics first. */
135*4882a593Smuzhiyun 		if (!builder->refs[idxa].longterm)
136*4882a593Smuzhiyun 			return -1;
137*4882a593Smuzhiyun 		else
138*4882a593Smuzhiyun 			return 1;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	/* Long term pics in ascending pic num order. */
142*4882a593Smuzhiyun 	if (builder->refs[idxa].longterm)
143*4882a593Smuzhiyun 		return builder->refs[idxa].pic_num <
144*4882a593Smuzhiyun 		       builder->refs[idxb].pic_num ?
145*4882a593Smuzhiyun 		       -1 : 1;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	poca = builder->refs[idxa].pic_order_count;
148*4882a593Smuzhiyun 	pocb = builder->refs[idxb].pic_order_count;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	/*
151*4882a593Smuzhiyun 	 * Short term pics with POC < cur POC first in POC descending order
152*4882a593Smuzhiyun 	 * followed by short term pics with POC > cur POC in POC ascending
153*4882a593Smuzhiyun 	 * order.
154*4882a593Smuzhiyun 	 */
155*4882a593Smuzhiyun 	if ((poca < builder->cur_pic_order_count) !=
156*4882a593Smuzhiyun 	     (pocb < builder->cur_pic_order_count))
157*4882a593Smuzhiyun 		return poca < pocb ? -1 : 1;
158*4882a593Smuzhiyun 	else if (poca < builder->cur_pic_order_count)
159*4882a593Smuzhiyun 		return pocb < poca ? -1 : 1;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	return poca < pocb ? -1 : 1;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
v4l2_h264_b1_ref_list_cmp(const void * ptra,const void * ptrb,const void * data)164*4882a593Smuzhiyun static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb,
165*4882a593Smuzhiyun 				     const void *data)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	const struct v4l2_h264_reflist_builder *builder = data;
168*4882a593Smuzhiyun 	s32 poca, pocb;
169*4882a593Smuzhiyun 	u8 idxa, idxb;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	idxa = *((u8 *)ptra);
172*4882a593Smuzhiyun 	idxb = *((u8 *)ptrb);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
175*4882a593Smuzhiyun 		    idxb >= V4L2_H264_NUM_DPB_ENTRIES))
176*4882a593Smuzhiyun 		return 1;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
179*4882a593Smuzhiyun 		/* Short term pics first. */
180*4882a593Smuzhiyun 		if (!builder->refs[idxa].longterm)
181*4882a593Smuzhiyun 			return -1;
182*4882a593Smuzhiyun 		else
183*4882a593Smuzhiyun 			return 1;
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	/* Long term pics in ascending pic num order. */
187*4882a593Smuzhiyun 	if (builder->refs[idxa].longterm)
188*4882a593Smuzhiyun 		return builder->refs[idxa].pic_num <
189*4882a593Smuzhiyun 		       builder->refs[idxb].pic_num ?
190*4882a593Smuzhiyun 		       -1 : 1;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	poca = builder->refs[idxa].pic_order_count;
193*4882a593Smuzhiyun 	pocb = builder->refs[idxb].pic_order_count;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	/*
196*4882a593Smuzhiyun 	 * Short term pics with POC > cur POC first in POC ascending order
197*4882a593Smuzhiyun 	 * followed by short term pics with POC < cur POC in POC descending
198*4882a593Smuzhiyun 	 * order.
199*4882a593Smuzhiyun 	 */
200*4882a593Smuzhiyun 	if ((poca < builder->cur_pic_order_count) !=
201*4882a593Smuzhiyun 	    (pocb < builder->cur_pic_order_count))
202*4882a593Smuzhiyun 		return pocb < poca ? -1 : 1;
203*4882a593Smuzhiyun 	else if (poca < builder->cur_pic_order_count)
204*4882a593Smuzhiyun 		return pocb < poca ? -1 : 1;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	return poca < pocb ? -1 : 1;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun /**
210*4882a593Smuzhiyun  * v4l2_h264_build_p_ref_list() - Build the P reference list
211*4882a593Smuzhiyun  *
212*4882a593Smuzhiyun  * @builder: reference list builder context
213*4882a593Smuzhiyun  * @reflist: 16-bytes array used to store the P reference list. Each entry
214*4882a593Smuzhiyun  *	     is an index in the DPB
215*4882a593Smuzhiyun  *
216*4882a593Smuzhiyun  * This functions builds the P reference lists. This procedure is describe in
217*4882a593Smuzhiyun  * section '8.2.4 Decoding process for reference picture lists construction'
218*4882a593Smuzhiyun  * of the H264 spec. This function can be used by H264 decoder drivers that
219*4882a593Smuzhiyun  * need to pass a P reference list to the hardware.
220*4882a593Smuzhiyun  */
221*4882a593Smuzhiyun void
v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder * builder,u8 * reflist)222*4882a593Smuzhiyun v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder,
223*4882a593Smuzhiyun 			   u8 *reflist)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	memcpy(reflist, builder->unordered_reflist,
226*4882a593Smuzhiyun 	       sizeof(builder->unordered_reflist[0]) * builder->num_valid);
227*4882a593Smuzhiyun 	sort_r(reflist, builder->num_valid, sizeof(*reflist),
228*4882a593Smuzhiyun 	       v4l2_h264_p_ref_list_cmp, NULL, builder);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun /**
233*4882a593Smuzhiyun  * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists
234*4882a593Smuzhiyun  *
235*4882a593Smuzhiyun  * @builder: reference list builder context
236*4882a593Smuzhiyun  * @b0_reflist: 16-bytes array used to store the B0 reference list. Each entry
237*4882a593Smuzhiyun  *		is an index in the DPB
238*4882a593Smuzhiyun  * @b1_reflist: 16-bytes array used to store the B1 reference list. Each entry
239*4882a593Smuzhiyun  *		is an index in the DPB
240*4882a593Smuzhiyun  *
241*4882a593Smuzhiyun  * This functions builds the B0/B1 reference lists. This procedure is described
242*4882a593Smuzhiyun  * in section '8.2.4 Decoding process for reference picture lists construction'
243*4882a593Smuzhiyun  * of the H264 spec. This function can be used by H264 decoder drivers that
244*4882a593Smuzhiyun  * need to pass B0/B1 reference lists to the hardware.
245*4882a593Smuzhiyun  */
246*4882a593Smuzhiyun void
v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder * builder,u8 * b0_reflist,u8 * b1_reflist)247*4882a593Smuzhiyun v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder,
248*4882a593Smuzhiyun 			    u8 *b0_reflist, u8 *b1_reflist)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	memcpy(b0_reflist, builder->unordered_reflist,
251*4882a593Smuzhiyun 	       sizeof(builder->unordered_reflist[0]) * builder->num_valid);
252*4882a593Smuzhiyun 	sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist),
253*4882a593Smuzhiyun 	       v4l2_h264_b0_ref_list_cmp, NULL, builder);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	memcpy(b1_reflist, builder->unordered_reflist,
256*4882a593Smuzhiyun 	       sizeof(builder->unordered_reflist[0]) * builder->num_valid);
257*4882a593Smuzhiyun 	sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist),
258*4882a593Smuzhiyun 	       v4l2_h264_b1_ref_list_cmp, NULL, builder);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	if (builder->num_valid > 1 &&
261*4882a593Smuzhiyun 	    !memcmp(b1_reflist, b0_reflist, builder->num_valid))
262*4882a593Smuzhiyun 		swap(b1_reflist[0], b1_reflist[1]);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists);
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun MODULE_LICENSE("GPL");
267*4882a593Smuzhiyun MODULE_DESCRIPTION("V4L2 H264 Helpers");
268*4882a593Smuzhiyun MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");
269