v4l2-h264.c (13726B)
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 * Size of the tempory buffer allocated when printing reference lists. The 17 * output will be truncated if the size is too small. 18 */ 19static const int tmp_str_size = 1024; 20 21/** 22 * v4l2_h264_init_reflist_builder() - Initialize a P/B0/B1 reference list 23 * builder 24 * 25 * @b: the builder context to initialize 26 * @dec_params: decode parameters control 27 * @sps: SPS control 28 * @dpb: DPB to use when creating the reference list 29 */ 30void 31v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, 32 const struct v4l2_ctrl_h264_decode_params *dec_params, 33 const struct v4l2_ctrl_h264_sps *sps, 34 const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]) 35{ 36 int cur_frame_num, max_frame_num; 37 unsigned int i; 38 39 max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4); 40 cur_frame_num = dec_params->frame_num; 41 42 memset(b, 0, sizeof(*b)); 43 if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) { 44 b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt, 45 dec_params->top_field_order_cnt); 46 b->cur_pic_fields = V4L2_H264_FRAME_REF; 47 } else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) { 48 b->cur_pic_order_count = dec_params->bottom_field_order_cnt; 49 b->cur_pic_fields = V4L2_H264_BOTTOM_FIELD_REF; 50 } else { 51 b->cur_pic_order_count = dec_params->top_field_order_cnt; 52 b->cur_pic_fields = V4L2_H264_TOP_FIELD_REF; 53 } 54 55 for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) { 56 if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) 57 continue; 58 59 if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) 60 b->refs[i].longterm = true; 61 62 /* 63 * Handle frame_num wraparound as described in section 64 * '8.2.4.1 Decoding process for picture numbers' of the spec. 65 * For long term references, frame_num is set to 66 * long_term_frame_idx which requires no wrapping. 67 */ 68 if (!b->refs[i].longterm && dpb[i].frame_num > cur_frame_num) 69 b->refs[i].frame_num = (int)dpb[i].frame_num - 70 max_frame_num; 71 else 72 b->refs[i].frame_num = dpb[i].frame_num; 73 74 b->refs[i].top_field_order_cnt = dpb[i].top_field_order_cnt; 75 b->refs[i].bottom_field_order_cnt = dpb[i].bottom_field_order_cnt; 76 77 if (b->cur_pic_fields == V4L2_H264_FRAME_REF) { 78 u8 fields = V4L2_H264_FRAME_REF; 79 80 b->unordered_reflist[b->num_valid].index = i; 81 b->unordered_reflist[b->num_valid].fields = fields; 82 b->num_valid++; 83 continue; 84 } 85 86 if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF) { 87 u8 fields = V4L2_H264_TOP_FIELD_REF; 88 89 b->unordered_reflist[b->num_valid].index = i; 90 b->unordered_reflist[b->num_valid].fields = fields; 91 b->num_valid++; 92 } 93 94 if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF) { 95 u8 fields = V4L2_H264_BOTTOM_FIELD_REF; 96 97 b->unordered_reflist[b->num_valid].index = i; 98 b->unordered_reflist[b->num_valid].fields = fields; 99 b->num_valid++; 100 } 101 } 102 103 for (i = b->num_valid; i < ARRAY_SIZE(b->unordered_reflist); i++) 104 b->unordered_reflist[i].index = i; 105} 106EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder); 107 108static s32 v4l2_h264_get_poc(const struct v4l2_h264_reflist_builder *b, 109 const struct v4l2_h264_reference *ref) 110{ 111 switch (ref->fields) { 112 case V4L2_H264_FRAME_REF: 113 return min(b->refs[ref->index].top_field_order_cnt, 114 b->refs[ref->index].bottom_field_order_cnt); 115 case V4L2_H264_TOP_FIELD_REF: 116 return b->refs[ref->index].top_field_order_cnt; 117 case V4L2_H264_BOTTOM_FIELD_REF: 118 return b->refs[ref->index].bottom_field_order_cnt; 119 } 120 121 /* not reached */ 122 return 0; 123} 124 125static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb, 126 const void *data) 127{ 128 const struct v4l2_h264_reflist_builder *builder = data; 129 u8 idxa, idxb; 130 131 idxa = ((struct v4l2_h264_reference *)ptra)->index; 132 idxb = ((struct v4l2_h264_reference *)ptrb)->index; 133 134 if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || 135 idxb >= V4L2_H264_NUM_DPB_ENTRIES)) 136 return 1; 137 138 if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) { 139 /* Short term pics first. */ 140 if (!builder->refs[idxa].longterm) 141 return -1; 142 else 143 return 1; 144 } 145 146 /* 147 * For frames, short term pics are in descending pic num order and long 148 * term ones in ascending order. For fields, the same direction is used 149 * but with frame_num (wrapped). For frames, the value of pic_num and 150 * frame_num are the same (see formula (8-28) and (8-29)). For this 151 * reason we can use frame_num only and share this function between 152 * frames and fields reflist. 153 */ 154 if (!builder->refs[idxa].longterm) 155 return builder->refs[idxb].frame_num < 156 builder->refs[idxa].frame_num ? 157 -1 : 1; 158 159 return builder->refs[idxa].frame_num < builder->refs[idxb].frame_num ? 160 -1 : 1; 161} 162 163static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb, 164 const void *data) 165{ 166 const struct v4l2_h264_reflist_builder *builder = data; 167 s32 poca, pocb; 168 u8 idxa, idxb; 169 170 idxa = ((struct v4l2_h264_reference *)ptra)->index; 171 idxb = ((struct v4l2_h264_reference *)ptrb)->index; 172 173 if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || 174 idxb >= V4L2_H264_NUM_DPB_ENTRIES)) 175 return 1; 176 177 if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) { 178 /* Short term pics first. */ 179 if (!builder->refs[idxa].longterm) 180 return -1; 181 else 182 return 1; 183 } 184 185 /* Long term pics in ascending frame num order. */ 186 if (builder->refs[idxa].longterm) 187 return builder->refs[idxa].frame_num < 188 builder->refs[idxb].frame_num ? 189 -1 : 1; 190 191 poca = v4l2_h264_get_poc(builder, ptra); 192 pocb = v4l2_h264_get_poc(builder, ptrb); 193 194 /* 195 * Short term pics with POC < cur POC first in POC descending order 196 * followed by short term pics with POC > cur POC in POC ascending 197 * order. 198 */ 199 if ((poca < builder->cur_pic_order_count) != 200 (pocb < builder->cur_pic_order_count)) 201 return poca < pocb ? -1 : 1; 202 else if (poca < builder->cur_pic_order_count) 203 return pocb < poca ? -1 : 1; 204 205 return poca < pocb ? -1 : 1; 206} 207 208static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb, 209 const void *data) 210{ 211 const struct v4l2_h264_reflist_builder *builder = data; 212 s32 poca, pocb; 213 u8 idxa, idxb; 214 215 idxa = ((struct v4l2_h264_reference *)ptra)->index; 216 idxb = ((struct v4l2_h264_reference *)ptrb)->index; 217 218 if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || 219 idxb >= V4L2_H264_NUM_DPB_ENTRIES)) 220 return 1; 221 222 if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) { 223 /* Short term pics first. */ 224 if (!builder->refs[idxa].longterm) 225 return -1; 226 else 227 return 1; 228 } 229 230 /* Long term pics in ascending frame num order. */ 231 if (builder->refs[idxa].longterm) 232 return builder->refs[idxa].frame_num < 233 builder->refs[idxb].frame_num ? 234 -1 : 1; 235 236 poca = v4l2_h264_get_poc(builder, ptra); 237 pocb = v4l2_h264_get_poc(builder, ptrb); 238 239 /* 240 * Short term pics with POC > cur POC first in POC ascending order 241 * followed by short term pics with POC < cur POC in POC descending 242 * order. 243 */ 244 if ((poca < builder->cur_pic_order_count) != 245 (pocb < builder->cur_pic_order_count)) 246 return pocb < poca ? -1 : 1; 247 else if (poca < builder->cur_pic_order_count) 248 return pocb < poca ? -1 : 1; 249 250 return poca < pocb ? -1 : 1; 251} 252 253/* 254 * The references need to be reordered so that references are alternating 255 * between top and bottom field references starting with the current picture 256 * parity. This has to be done for short term and long term references 257 * separately. 258 */ 259static void reorder_field_reflist(const struct v4l2_h264_reflist_builder *b, 260 struct v4l2_h264_reference *reflist) 261{ 262 struct v4l2_h264_reference tmplist[V4L2_H264_REF_LIST_LEN]; 263 u8 lt, i = 0, j = 0, k = 0; 264 265 memcpy(tmplist, reflist, sizeof(tmplist[0]) * b->num_valid); 266 267 for (lt = 0; lt <= 1; lt++) { 268 do { 269 for (; i < b->num_valid && b->refs[tmplist[i].index].longterm == lt; i++) { 270 if (tmplist[i].fields == b->cur_pic_fields) { 271 reflist[k++] = tmplist[i++]; 272 break; 273 } 274 } 275 276 for (; j < b->num_valid && b->refs[tmplist[j].index].longterm == lt; j++) { 277 if (tmplist[j].fields != b->cur_pic_fields) { 278 reflist[k++] = tmplist[j++]; 279 break; 280 } 281 } 282 } while ((i < b->num_valid && b->refs[tmplist[i].index].longterm == lt) || 283 (j < b->num_valid && b->refs[tmplist[j].index].longterm == lt)); 284 } 285} 286 287static char ref_type_to_char(u8 ref_type) 288{ 289 switch (ref_type) { 290 case V4L2_H264_FRAME_REF: 291 return 'f'; 292 case V4L2_H264_TOP_FIELD_REF: 293 return 't'; 294 case V4L2_H264_BOTTOM_FIELD_REF: 295 return 'b'; 296 } 297 298 return '?'; 299} 300 301static const char *format_ref_list_p(const struct v4l2_h264_reflist_builder *builder, 302 struct v4l2_h264_reference *reflist, 303 char **out_str) 304{ 305 int n = 0, i; 306 307 *out_str = kmalloc(tmp_str_size, GFP_KERNEL); 308 309 n += snprintf(*out_str + n, tmp_str_size - n, "|"); 310 311 for (i = 0; i < builder->num_valid; i++) { 312 /* this is pic_num for frame and frame_num (wrapped) for field, 313 * but for frame pic_num is equal to frame_num (wrapped). 314 */ 315 int frame_num = builder->refs[reflist[i].index].frame_num; 316 bool longterm = builder->refs[reflist[i].index].longterm; 317 318 n += scnprintf(*out_str + n, tmp_str_size - n, "%i%c%c|", 319 frame_num, longterm ? 'l' : 's', 320 ref_type_to_char(reflist[i].fields)); 321 } 322 323 return *out_str; 324} 325 326static void print_ref_list_p(const struct v4l2_h264_reflist_builder *builder, 327 struct v4l2_h264_reference *reflist) 328{ 329 char *buf = NULL; 330 331 pr_debug("ref_pic_list_p (cur_poc %u%c) %s\n", 332 builder->cur_pic_order_count, 333 ref_type_to_char(builder->cur_pic_fields), 334 format_ref_list_p(builder, reflist, &buf)); 335 336 kfree(buf); 337} 338 339static const char *format_ref_list_b(const struct v4l2_h264_reflist_builder *builder, 340 struct v4l2_h264_reference *reflist, 341 char **out_str) 342{ 343 int n = 0, i; 344 345 *out_str = kmalloc(tmp_str_size, GFP_KERNEL); 346 347 n += snprintf(*out_str + n, tmp_str_size - n, "|"); 348 349 for (i = 0; i < builder->num_valid; i++) { 350 int frame_num = builder->refs[reflist[i].index].frame_num; 351 u32 poc = v4l2_h264_get_poc(builder, reflist + i); 352 bool longterm = builder->refs[reflist[i].index].longterm; 353 354 n += scnprintf(*out_str + n, tmp_str_size - n, "%i%c%c|", 355 longterm ? frame_num : poc, 356 longterm ? 'l' : 's', 357 ref_type_to_char(reflist[i].fields)); 358 } 359 360 return *out_str; 361} 362 363static void print_ref_list_b(const struct v4l2_h264_reflist_builder *builder, 364 struct v4l2_h264_reference *reflist, u8 list_num) 365{ 366 char *buf = NULL; 367 368 pr_debug("ref_pic_list_b%u (cur_poc %u%c) %s", 369 list_num, builder->cur_pic_order_count, 370 ref_type_to_char(builder->cur_pic_fields), 371 format_ref_list_b(builder, reflist, &buf)); 372 373 kfree(buf); 374} 375 376/** 377 * v4l2_h264_build_p_ref_list() - Build the P reference list 378 * 379 * @builder: reference list builder context 380 * @reflist: 32 sized array used to store the P reference list. Each entry 381 * is a v4l2_h264_reference structure 382 * 383 * This functions builds the P reference lists. This procedure is describe in 384 * section '8.2.4 Decoding process for reference picture lists construction' 385 * of the H264 spec. This function can be used by H264 decoder drivers that 386 * need to pass a P reference list to the hardware. 387 */ 388void 389v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder, 390 struct v4l2_h264_reference *reflist) 391{ 392 memcpy(reflist, builder->unordered_reflist, 393 sizeof(builder->unordered_reflist[0]) * builder->num_valid); 394 sort_r(reflist, builder->num_valid, sizeof(*reflist), 395 v4l2_h264_p_ref_list_cmp, NULL, builder); 396 397 if (builder->cur_pic_fields != V4L2_H264_FRAME_REF) 398 reorder_field_reflist(builder, reflist); 399 400 print_ref_list_p(builder, reflist); 401} 402EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list); 403 404/** 405 * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists 406 * 407 * @builder: reference list builder context 408 * @b0_reflist: 32 sized array used to store the B0 reference list. Each entry 409 * is a v4l2_h264_reference structure 410 * @b1_reflist: 32 sized array used to store the B1 reference list. Each entry 411 * is a v4l2_h264_reference structure 412 * 413 * This functions builds the B0/B1 reference lists. This procedure is described 414 * in section '8.2.4 Decoding process for reference picture lists construction' 415 * of the H264 spec. This function can be used by H264 decoder drivers that 416 * need to pass B0/B1 reference lists to the hardware. 417 */ 418void 419v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder, 420 struct v4l2_h264_reference *b0_reflist, 421 struct v4l2_h264_reference *b1_reflist) 422{ 423 memcpy(b0_reflist, builder->unordered_reflist, 424 sizeof(builder->unordered_reflist[0]) * builder->num_valid); 425 sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist), 426 v4l2_h264_b0_ref_list_cmp, NULL, builder); 427 428 memcpy(b1_reflist, builder->unordered_reflist, 429 sizeof(builder->unordered_reflist[0]) * builder->num_valid); 430 sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist), 431 v4l2_h264_b1_ref_list_cmp, NULL, builder); 432 433 if (builder->cur_pic_fields != V4L2_H264_FRAME_REF) { 434 reorder_field_reflist(builder, b0_reflist); 435 reorder_field_reflist(builder, b1_reflist); 436 } 437 438 if (builder->num_valid > 1 && 439 !memcmp(b1_reflist, b0_reflist, builder->num_valid)) 440 swap(b1_reflist[0], b1_reflist[1]); 441 442 print_ref_list_b(builder, b0_reflist, 0); 443 print_ref_list_b(builder, b1_reflist, 1); 444} 445EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists); 446 447MODULE_LICENSE("GPL"); 448MODULE_DESCRIPTION("V4L2 H264 Helpers"); 449MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");