media: uapi: h264: Clean DPB entry interface
[linux-2.6-microblaze.git] / drivers / media / v4l2-core / v4l2-h264.c
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  * v4l2_h264_init_reflist_builder() - Initialize a P/B0/B1 reference list
17  *                                    builder
18  *
19  * @b: the builder context to initialize
20  * @dec_params: decode parameters control
21  * @slice_params: first slice parameters control
22  * @sps: SPS control
23  * @dpb: DPB to use when creating the reference list
24  */
25 void
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])
31 {
32         int cur_frame_num, max_frame_num;
33         unsigned int i;
34
35         max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
36         cur_frame_num = slice_params->frame_num;
37
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;
44         else
45                 b->cur_pic_order_count = dec_params->top_field_order_cnt;
46
47         for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
48                 u32 pic_order_count;
49
50                 if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
51                         continue;
52
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;
56
57                 /*
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.
62                  */
63                 if (dpb[i].frame_num > cur_frame_num)
64                         b->refs[i].frame_num = (int)dpb[i].frame_num -
65                                                max_frame_num;
66                 else
67                         b->refs[i].frame_num = dpb[i].frame_num;
68
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;
74                 else
75                         pic_order_count = dpb[i].top_field_order_cnt;
76
77                 b->refs[i].pic_order_count = pic_order_count;
78                 b->unordered_reflist[b->num_valid] = i;
79                 b->num_valid++;
80         }
81
82         for (i = b->num_valid; i < ARRAY_SIZE(b->unordered_reflist); i++)
83                 b->unordered_reflist[i] = i;
84 }
85 EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder);
86
87 static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb,
88                                     const void *data)
89 {
90         const struct v4l2_h264_reflist_builder *builder = data;
91         u8 idxa, idxb;
92
93         idxa = *((u8 *)ptra);
94         idxb = *((u8 *)ptrb);
95
96         if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
97                     idxb >= V4L2_H264_NUM_DPB_ENTRIES))
98                 return 1;
99
100         if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
101                 /* Short term pics first. */
102                 if (!builder->refs[idxa].longterm)
103                         return -1;
104                 else
105                         return 1;
106         }
107
108         /*
109          * Short term pics in descending pic num order, long term ones in
110          * ascending order.
111          */
112         if (!builder->refs[idxa].longterm)
113                 return builder->refs[idxb].frame_num <
114                        builder->refs[idxa].frame_num ?
115                        -1 : 1;
116
117         return builder->refs[idxa].pic_num < builder->refs[idxb].pic_num ?
118                -1 : 1;
119 }
120
121 static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb,
122                                      const void *data)
123 {
124         const struct v4l2_h264_reflist_builder *builder = data;
125         s32 poca, pocb;
126         u8 idxa, idxb;
127
128         idxa = *((u8 *)ptra);
129         idxb = *((u8 *)ptrb);
130
131         if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
132                     idxb >= V4L2_H264_NUM_DPB_ENTRIES))
133                 return 1;
134
135         if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
136                 /* Short term pics first. */
137                 if (!builder->refs[idxa].longterm)
138                         return -1;
139                 else
140                         return 1;
141         }
142
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 ?
147                        -1 : 1;
148
149         poca = builder->refs[idxa].pic_order_count;
150         pocb = builder->refs[idxb].pic_order_count;
151
152         /*
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
155          * order.
156          */
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;
162
163         return poca < pocb ? -1 : 1;
164 }
165
166 static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb,
167                                      const void *data)
168 {
169         const struct v4l2_h264_reflist_builder *builder = data;
170         s32 poca, pocb;
171         u8 idxa, idxb;
172
173         idxa = *((u8 *)ptra);
174         idxb = *((u8 *)ptrb);
175
176         if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
177                     idxb >= V4L2_H264_NUM_DPB_ENTRIES))
178                 return 1;
179
180         if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
181                 /* Short term pics first. */
182                 if (!builder->refs[idxa].longterm)
183                         return -1;
184                 else
185                         return 1;
186         }
187
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 ?
192                        -1 : 1;
193
194         poca = builder->refs[idxa].pic_order_count;
195         pocb = builder->refs[idxb].pic_order_count;
196
197         /*
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
200          * order.
201          */
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;
207
208         return poca < pocb ? -1 : 1;
209 }
210
211 /**
212  * v4l2_h264_build_p_ref_list() - Build the P reference list
213  *
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
217  *
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.
222  */
223 void
224 v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder,
225                            u8 *reflist)
226 {
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);
231 }
232 EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list);
233
234 /**
235  * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists
236  *
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
242  *
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.
247  */
248 void
249 v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder,
250                             u8 *b0_reflist, u8 *b1_reflist)
251 {
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);
256
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);
261
262         if (builder->num_valid > 1 &&
263             !memcmp(b1_reflist, b0_reflist, builder->num_valid))
264                 swap(b1_reflist[0], b1_reflist[1]);
265 }
266 EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists);
267
268 MODULE_LICENSE("GPL");
269 MODULE_DESCRIPTION("V4L2 H264 Helpers");
270 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");