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
22 * @dpb: DPB to use when creating the reference list
25 v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder
*b
,
26 const struct v4l2_ctrl_h264_decode_params
*dec_params
,
27 const struct v4l2_ctrl_h264_sps
*sps
,
28 const struct v4l2_h264_dpb_entry dpb
[V4L2_H264_NUM_DPB_ENTRIES
])
30 int cur_frame_num
, max_frame_num
;
33 max_frame_num
= 1 << (sps
->log2_max_frame_num_minus4
+ 4);
34 cur_frame_num
= dec_params
->frame_num
;
36 memset(b
, 0, sizeof(*b
));
37 if (!(dec_params
->flags
& V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC
))
38 b
->cur_pic_order_count
= min(dec_params
->bottom_field_order_cnt
,
39 dec_params
->top_field_order_cnt
);
40 else if (dec_params
->flags
& V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD
)
41 b
->cur_pic_order_count
= dec_params
->bottom_field_order_cnt
;
43 b
->cur_pic_order_count
= dec_params
->top_field_order_cnt
;
45 for (i
= 0; i
< V4L2_H264_NUM_DPB_ENTRIES
; i
++) {
48 if (!(dpb
[i
].flags
& V4L2_H264_DPB_ENTRY_FLAG_ACTIVE
))
51 b
->refs
[i
].pic_num
= dpb
[i
].pic_num
;
52 if (dpb
[i
].flags
& V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM
)
53 b
->refs
[i
].longterm
= true;
56 * Handle frame_num wraparound as described in section
57 * '8.2.4.1 Decoding process for picture numbers' of the spec.
58 * TODO: This logic will have to be adjusted when we start
59 * supporting interlaced content.
61 if (dpb
[i
].frame_num
> cur_frame_num
)
62 b
->refs
[i
].frame_num
= (int)dpb
[i
].frame_num
-
65 b
->refs
[i
].frame_num
= dpb
[i
].frame_num
;
67 if (dpb
[i
].fields
== V4L2_H264_FRAME_REF
)
68 pic_order_count
= min(dpb
[i
].top_field_order_cnt
,
69 dpb
[i
].bottom_field_order_cnt
);
70 else if (dpb
[i
].fields
& V4L2_H264_BOTTOM_FIELD_REF
)
71 pic_order_count
= dpb
[i
].bottom_field_order_cnt
;
73 pic_order_count
= dpb
[i
].top_field_order_cnt
;
75 b
->refs
[i
].pic_order_count
= pic_order_count
;
76 b
->unordered_reflist
[b
->num_valid
] = i
;
80 for (i
= b
->num_valid
; i
< ARRAY_SIZE(b
->unordered_reflist
); i
++)
81 b
->unordered_reflist
[i
] = i
;
83 EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder
);
85 static int v4l2_h264_p_ref_list_cmp(const void *ptra
, const void *ptrb
,
88 const struct v4l2_h264_reflist_builder
*builder
= data
;
94 if (WARN_ON(idxa
>= V4L2_H264_NUM_DPB_ENTRIES
||
95 idxb
>= V4L2_H264_NUM_DPB_ENTRIES
))
98 if (builder
->refs
[idxa
].longterm
!= builder
->refs
[idxb
].longterm
) {
99 /* Short term pics first. */
100 if (!builder
->refs
[idxa
].longterm
)
107 * Short term pics in descending pic num order, long term ones in
110 if (!builder
->refs
[idxa
].longterm
)
111 return builder
->refs
[idxb
].frame_num
<
112 builder
->refs
[idxa
].frame_num
?
115 return builder
->refs
[idxa
].pic_num
< builder
->refs
[idxb
].pic_num
?
119 static int v4l2_h264_b0_ref_list_cmp(const void *ptra
, const void *ptrb
,
122 const struct v4l2_h264_reflist_builder
*builder
= data
;
126 idxa
= *((u8
*)ptra
);
127 idxb
= *((u8
*)ptrb
);
129 if (WARN_ON(idxa
>= V4L2_H264_NUM_DPB_ENTRIES
||
130 idxb
>= V4L2_H264_NUM_DPB_ENTRIES
))
133 if (builder
->refs
[idxa
].longterm
!= builder
->refs
[idxb
].longterm
) {
134 /* Short term pics first. */
135 if (!builder
->refs
[idxa
].longterm
)
141 /* Long term pics in ascending pic num order. */
142 if (builder
->refs
[idxa
].longterm
)
143 return builder
->refs
[idxa
].pic_num
<
144 builder
->refs
[idxb
].pic_num
?
147 poca
= builder
->refs
[idxa
].pic_order_count
;
148 pocb
= builder
->refs
[idxb
].pic_order_count
;
151 * Short term pics with POC < cur POC first in POC descending order
152 * followed by short term pics with POC > cur POC in POC ascending
155 if ((poca
< builder
->cur_pic_order_count
) !=
156 (pocb
< builder
->cur_pic_order_count
))
157 return poca
< pocb
? -1 : 1;
158 else if (poca
< builder
->cur_pic_order_count
)
159 return pocb
< poca
? -1 : 1;
161 return poca
< pocb
? -1 : 1;
164 static int v4l2_h264_b1_ref_list_cmp(const void *ptra
, const void *ptrb
,
167 const struct v4l2_h264_reflist_builder
*builder
= data
;
171 idxa
= *((u8
*)ptra
);
172 idxb
= *((u8
*)ptrb
);
174 if (WARN_ON(idxa
>= V4L2_H264_NUM_DPB_ENTRIES
||
175 idxb
>= V4L2_H264_NUM_DPB_ENTRIES
))
178 if (builder
->refs
[idxa
].longterm
!= builder
->refs
[idxb
].longterm
) {
179 /* Short term pics first. */
180 if (!builder
->refs
[idxa
].longterm
)
186 /* Long term pics in ascending pic num order. */
187 if (builder
->refs
[idxa
].longterm
)
188 return builder
->refs
[idxa
].pic_num
<
189 builder
->refs
[idxb
].pic_num
?
192 poca
= builder
->refs
[idxa
].pic_order_count
;
193 pocb
= builder
->refs
[idxb
].pic_order_count
;
196 * Short term pics with POC > cur POC first in POC ascending order
197 * followed by short term pics with POC < cur POC in POC descending
200 if ((poca
< builder
->cur_pic_order_count
) !=
201 (pocb
< builder
->cur_pic_order_count
))
202 return pocb
< poca
? -1 : 1;
203 else if (poca
< builder
->cur_pic_order_count
)
204 return pocb
< poca
? -1 : 1;
206 return poca
< pocb
? -1 : 1;
210 * v4l2_h264_build_p_ref_list() - Build the P reference list
212 * @builder: reference list builder context
213 * @reflist: 16-bytes array used to store the P reference list. Each entry
214 * is an index in the DPB
216 * This functions builds the P reference lists. This procedure is describe in
217 * section '8.2.4 Decoding process for reference picture lists construction'
218 * of the H264 spec. This function can be used by H264 decoder drivers that
219 * need to pass a P reference list to the hardware.
222 v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder
*builder
,
225 memcpy(reflist
, builder
->unordered_reflist
,
226 sizeof(builder
->unordered_reflist
[0]) * builder
->num_valid
);
227 sort_r(reflist
, builder
->num_valid
, sizeof(*reflist
),
228 v4l2_h264_p_ref_list_cmp
, NULL
, builder
);
230 EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list
);
233 * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists
235 * @builder: reference list builder context
236 * @b0_reflist: 16-bytes array used to store the B0 reference list. Each entry
237 * is an index in the DPB
238 * @b1_reflist: 16-bytes array used to store the B1 reference list. Each entry
239 * is an index in the DPB
241 * This functions builds the B0/B1 reference lists. This procedure is described
242 * in section '8.2.4 Decoding process for reference picture lists construction'
243 * of the H264 spec. This function can be used by H264 decoder drivers that
244 * need to pass B0/B1 reference lists to the hardware.
247 v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder
*builder
,
248 u8
*b0_reflist
, u8
*b1_reflist
)
250 memcpy(b0_reflist
, builder
->unordered_reflist
,
251 sizeof(builder
->unordered_reflist
[0]) * builder
->num_valid
);
252 sort_r(b0_reflist
, builder
->num_valid
, sizeof(*b0_reflist
),
253 v4l2_h264_b0_ref_list_cmp
, NULL
, builder
);
255 memcpy(b1_reflist
, builder
->unordered_reflist
,
256 sizeof(builder
->unordered_reflist
[0]) * builder
->num_valid
);
257 sort_r(b1_reflist
, builder
->num_valid
, sizeof(*b1_reflist
),
258 v4l2_h264_b1_ref_list_cmp
, NULL
, builder
);
260 if (builder
->num_valid
> 1 &&
261 !memcmp(b1_reflist
, b0_reflist
, builder
->num_valid
))
262 swap(b1_reflist
[0], b1_reflist
[1]);
264 EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists
);
266 MODULE_LICENSE("GPL");
267 MODULE_DESCRIPTION("V4L2 H264 Helpers");
268 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");