Merge tag 'amlogic-fixes' into v5.11/dt64
[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  * @sps: SPS control
22  * @dpb: DPB to use when creating the reference list
23  */
24 void
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])
29 {
30         int cur_frame_num, max_frame_num;
31         unsigned int i;
32
33         max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
34         cur_frame_num = dec_params->frame_num;
35
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;
42         else
43                 b->cur_pic_order_count = dec_params->top_field_order_cnt;
44
45         for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
46                 u32 pic_order_count;
47
48                 if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
49                         continue;
50
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;
54
55                 /*
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.
60                  */
61                 if (dpb[i].frame_num > cur_frame_num)
62                         b->refs[i].frame_num = (int)dpb[i].frame_num -
63                                                max_frame_num;
64                 else
65                         b->refs[i].frame_num = dpb[i].frame_num;
66
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;
72                 else
73                         pic_order_count = dpb[i].top_field_order_cnt;
74
75                 b->refs[i].pic_order_count = pic_order_count;
76                 b->unordered_reflist[b->num_valid] = i;
77                 b->num_valid++;
78         }
79
80         for (i = b->num_valid; i < ARRAY_SIZE(b->unordered_reflist); i++)
81                 b->unordered_reflist[i] = i;
82 }
83 EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder);
84
85 static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb,
86                                     const void *data)
87 {
88         const struct v4l2_h264_reflist_builder *builder = data;
89         u8 idxa, idxb;
90
91         idxa = *((u8 *)ptra);
92         idxb = *((u8 *)ptrb);
93
94         if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
95                     idxb >= V4L2_H264_NUM_DPB_ENTRIES))
96                 return 1;
97
98         if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
99                 /* Short term pics first. */
100                 if (!builder->refs[idxa].longterm)
101                         return -1;
102                 else
103                         return 1;
104         }
105
106         /*
107          * Short term pics in descending pic num order, long term ones in
108          * ascending order.
109          */
110         if (!builder->refs[idxa].longterm)
111                 return builder->refs[idxb].frame_num <
112                        builder->refs[idxa].frame_num ?
113                        -1 : 1;
114
115         return builder->refs[idxa].pic_num < builder->refs[idxb].pic_num ?
116                -1 : 1;
117 }
118
119 static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb,
120                                      const void *data)
121 {
122         const struct v4l2_h264_reflist_builder *builder = data;
123         s32 poca, pocb;
124         u8 idxa, idxb;
125
126         idxa = *((u8 *)ptra);
127         idxb = *((u8 *)ptrb);
128
129         if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
130                     idxb >= V4L2_H264_NUM_DPB_ENTRIES))
131                 return 1;
132
133         if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
134                 /* Short term pics first. */
135                 if (!builder->refs[idxa].longterm)
136                         return -1;
137                 else
138                         return 1;
139         }
140
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 ?
145                        -1 : 1;
146
147         poca = builder->refs[idxa].pic_order_count;
148         pocb = builder->refs[idxb].pic_order_count;
149
150         /*
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
153          * order.
154          */
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;
160
161         return poca < pocb ? -1 : 1;
162 }
163
164 static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb,
165                                      const void *data)
166 {
167         const struct v4l2_h264_reflist_builder *builder = data;
168         s32 poca, pocb;
169         u8 idxa, idxb;
170
171         idxa = *((u8 *)ptra);
172         idxb = *((u8 *)ptrb);
173
174         if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
175                     idxb >= V4L2_H264_NUM_DPB_ENTRIES))
176                 return 1;
177
178         if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
179                 /* Short term pics first. */
180                 if (!builder->refs[idxa].longterm)
181                         return -1;
182                 else
183                         return 1;
184         }
185
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 ?
190                        -1 : 1;
191
192         poca = builder->refs[idxa].pic_order_count;
193         pocb = builder->refs[idxb].pic_order_count;
194
195         /*
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
198          * order.
199          */
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;
205
206         return poca < pocb ? -1 : 1;
207 }
208
209 /**
210  * v4l2_h264_build_p_ref_list() - Build the P reference list
211  *
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
215  *
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.
220  */
221 void
222 v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder,
223                            u8 *reflist)
224 {
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);
229 }
230 EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list);
231
232 /**
233  * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists
234  *
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
240  *
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.
245  */
246 void
247 v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder,
248                             u8 *b0_reflist, u8 *b1_reflist)
249 {
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);
254
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);
259
260         if (builder->num_valid > 1 &&
261             !memcmp(b1_reflist, b0_reflist, builder->num_valid))
262                 swap(b1_reflist[0], b1_reflist[1]);
263 }
264 EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists);
265
266 MODULE_LICENSE("GPL");
267 MODULE_DESCRIPTION("V4L2 H264 Helpers");
268 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");