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