1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2019 Collabora, Ltd.
7 * Author: Boris Brezillon <boris.brezillon@collabora.com>
10 #include <linux/module.h>
11 #include <linux/sort.h>
13 #include <media/v4l2-h264.h>
16 * v4l2_h264_init_reflist_builder() - Initialize a P/B0/B1 reference list
19 * @b: the builder context to initialize
20 * @dec_params: decode parameters control
21 * @slice_params: first slice parameters control
23 * @dpb: DPB to use when creating the reference list
26 v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
27 const struct v4l2_ctrl_h264_decode_params *dec_params,
28 const struct v4l2_ctrl_h264_slice_params *slice_params,
29 const struct v4l2_ctrl_h264_sps *sps,
30 const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES])
32 int cur_frame_num, max_frame_num;
35 max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
36 cur_frame_num = slice_params->frame_num;
38 memset(b, 0, sizeof(*b));
39 if (!(slice_params->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC))
40 b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt,
41 dec_params->top_field_order_cnt);
42 else if (slice_params->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)
43 b->cur_pic_order_count = dec_params->bottom_field_order_cnt;
45 b->cur_pic_order_count = dec_params->top_field_order_cnt;
47 for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
50 if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
53 b->refs[i].pic_num = dpb[i].pic_num;
54 if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
55 b->refs[i].longterm = true;
58 * Handle frame_num wraparound as described in section
59 * '8.2.4.1 Decoding process for picture numbers' of the spec.
60 * TODO: This logic will have to be adjusted when we start
61 * supporting interlaced content.
63 if (dpb[i].frame_num > cur_frame_num)
64 b->refs[i].frame_num = (int)dpb[i].frame_num -
67 b->refs[i].frame_num = dpb[i].frame_num;
69 if (dpb[i].fields == V4L2_H264_FRAME_REF)
70 pic_order_count = min(dpb[i].top_field_order_cnt,
71 dpb[i].bottom_field_order_cnt);
72 else if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)
73 pic_order_count = dpb[i].bottom_field_order_cnt;
75 pic_order_count = dpb[i].top_field_order_cnt;
77 b->refs[i].pic_order_count = pic_order_count;
78 b->unordered_reflist[b->num_valid] = i;
82 for (i = b->num_valid; i < ARRAY_SIZE(b->unordered_reflist); i++)
83 b->unordered_reflist[i] = i;
85 EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder);
87 static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb,
90 const struct v4l2_h264_reflist_builder *builder = data;
96 if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
97 idxb >= V4L2_H264_NUM_DPB_ENTRIES))
100 if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
101 /* Short term pics first. */
102 if (!builder->refs[idxa].longterm)
109 * Short term pics in descending pic num order, long term ones in
112 if (!builder->refs[idxa].longterm)
113 return builder->refs[idxb].frame_num <
114 builder->refs[idxa].frame_num ?
117 return builder->refs[idxa].pic_num < builder->refs[idxb].pic_num ?
121 static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb,
124 const struct v4l2_h264_reflist_builder *builder = data;
128 idxa = *((u8 *)ptra);
129 idxb = *((u8 *)ptrb);
131 if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
132 idxb >= V4L2_H264_NUM_DPB_ENTRIES))
135 if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
136 /* Short term pics first. */
137 if (!builder->refs[idxa].longterm)
143 /* Long term pics in ascending pic num order. */
144 if (builder->refs[idxa].longterm)
145 return builder->refs[idxa].pic_num <
146 builder->refs[idxb].pic_num ?
149 poca = builder->refs[idxa].pic_order_count;
150 pocb = builder->refs[idxb].pic_order_count;
153 * Short term pics with POC < cur POC first in POC descending order
154 * followed by short term pics with POC > cur POC in POC ascending
157 if ((poca < builder->cur_pic_order_count) !=
158 (pocb < builder->cur_pic_order_count))
159 return poca < pocb ? -1 : 1;
160 else if (poca < builder->cur_pic_order_count)
161 return pocb < poca ? -1 : 1;
163 return poca < pocb ? -1 : 1;
166 static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb,
169 const struct v4l2_h264_reflist_builder *builder = data;
173 idxa = *((u8 *)ptra);
174 idxb = *((u8 *)ptrb);
176 if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
177 idxb >= V4L2_H264_NUM_DPB_ENTRIES))
180 if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
181 /* Short term pics first. */
182 if (!builder->refs[idxa].longterm)
188 /* Long term pics in ascending pic num order. */
189 if (builder->refs[idxa].longterm)
190 return builder->refs[idxa].pic_num <
191 builder->refs[idxb].pic_num ?
194 poca = builder->refs[idxa].pic_order_count;
195 pocb = builder->refs[idxb].pic_order_count;
198 * Short term pics with POC > cur POC first in POC ascending order
199 * followed by short term pics with POC < cur POC in POC descending
202 if ((poca < builder->cur_pic_order_count) !=
203 (pocb < builder->cur_pic_order_count))
204 return pocb < poca ? -1 : 1;
205 else if (poca < builder->cur_pic_order_count)
206 return pocb < poca ? -1 : 1;
208 return poca < pocb ? -1 : 1;
212 * v4l2_h264_build_p_ref_list() - Build the P reference list
214 * @builder: reference list builder context
215 * @reflist: 16-bytes array used to store the P reference list. Each entry
216 * is an index in the DPB
218 * This functions builds the P reference lists. This procedure is describe in
219 * section '8.2.4 Decoding process for reference picture lists construction'
220 * of the H264 spec. This function can be used by H264 decoder drivers that
221 * need to pass a P reference list to the hardware.
224 v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder,
227 memcpy(reflist, builder->unordered_reflist,
228 sizeof(builder->unordered_reflist[0]) * builder->num_valid);
229 sort_r(reflist, builder->num_valid, sizeof(*reflist),
230 v4l2_h264_p_ref_list_cmp, NULL, builder);
232 EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list);
235 * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists
237 * @builder: reference list builder context
238 * @b0_reflist: 16-bytes array used to store the B0 reference list. Each entry
239 * is an index in the DPB
240 * @b1_reflist: 16-bytes array used to store the B1 reference list. Each entry
241 * is an index in the DPB
243 * This functions builds the B0/B1 reference lists. This procedure is described
244 * in section '8.2.4 Decoding process for reference picture lists construction'
245 * of the H264 spec. This function can be used by H264 decoder drivers that
246 * need to pass B0/B1 reference lists to the hardware.
249 v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder,
250 u8 *b0_reflist, u8 *b1_reflist)
252 memcpy(b0_reflist, builder->unordered_reflist,
253 sizeof(builder->unordered_reflist[0]) * builder->num_valid);
254 sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist),
255 v4l2_h264_b0_ref_list_cmp, NULL, builder);
257 memcpy(b1_reflist, builder->unordered_reflist,
258 sizeof(builder->unordered_reflist[0]) * builder->num_valid);
259 sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist),
260 v4l2_h264_b1_ref_list_cmp, NULL, builder);
262 if (builder->num_valid > 1 &&
263 !memcmp(b1_reflist, b0_reflist, builder->num_valid))
264 swap(b1_reflist[0], b1_reflist[1]);
266 EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists);
268 MODULE_LICENSE("GPL");
269 MODULE_DESCRIPTION("V4L2 H264 Helpers");
270 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");