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 */ 19 static 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 */ 30 void 31 v4l2_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 } 106 EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder); 107 108 static 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 125 static 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 163 static 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 208 static 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 */ 259 static 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 287 static 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 301 static 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 if (!(*out_str)) 309 return NULL; 310 311 n += snprintf(*out_str + n, tmp_str_size - n, "|"); 312 313 for (i = 0; i < builder->num_valid; i++) { 314 /* this is pic_num for frame and frame_num (wrapped) for field, 315 * but for frame pic_num is equal to frame_num (wrapped). 316 */ 317 int frame_num = builder->refs[reflist[i].index].frame_num; 318 bool longterm = builder->refs[reflist[i].index].longterm; 319 320 n += scnprintf(*out_str + n, tmp_str_size - n, "%i%c%c|", 321 frame_num, longterm ? 'l' : 's', 322 ref_type_to_char(reflist[i].fields)); 323 } 324 325 return *out_str; 326 } 327 328 static void print_ref_list_p(const struct v4l2_h264_reflist_builder *builder, 329 struct v4l2_h264_reference *reflist) 330 { 331 char *buf = NULL; 332 333 pr_debug("ref_pic_list_p (cur_poc %u%c) %s\n", 334 builder->cur_pic_order_count, 335 ref_type_to_char(builder->cur_pic_fields), 336 format_ref_list_p(builder, reflist, &buf)); 337 338 kfree(buf); 339 } 340 341 static const char *format_ref_list_b(const struct v4l2_h264_reflist_builder *builder, 342 struct v4l2_h264_reference *reflist, 343 char **out_str) 344 { 345 int n = 0, i; 346 347 *out_str = kmalloc(tmp_str_size, GFP_KERNEL); 348 if (!(*out_str)) 349 return NULL; 350 351 n += snprintf(*out_str + n, tmp_str_size - n, "|"); 352 353 for (i = 0; i < builder->num_valid; i++) { 354 int frame_num = builder->refs[reflist[i].index].frame_num; 355 u32 poc = v4l2_h264_get_poc(builder, reflist + i); 356 bool longterm = builder->refs[reflist[i].index].longterm; 357 358 n += scnprintf(*out_str + n, tmp_str_size - n, "%i%c%c|", 359 longterm ? frame_num : poc, 360 longterm ? 'l' : 's', 361 ref_type_to_char(reflist[i].fields)); 362 } 363 364 return *out_str; 365 } 366 367 static void print_ref_list_b(const struct v4l2_h264_reflist_builder *builder, 368 struct v4l2_h264_reference *reflist, u8 list_num) 369 { 370 char *buf = NULL; 371 372 pr_debug("ref_pic_list_b%u (cur_poc %u%c) %s", 373 list_num, builder->cur_pic_order_count, 374 ref_type_to_char(builder->cur_pic_fields), 375 format_ref_list_b(builder, reflist, &buf)); 376 377 kfree(buf); 378 } 379 380 /** 381 * v4l2_h264_build_p_ref_list() - Build the P reference list 382 * 383 * @builder: reference list builder context 384 * @reflist: 32 sized array used to store the P reference list. Each entry 385 * is a v4l2_h264_reference structure 386 * 387 * This functions builds the P reference lists. This procedure is describe in 388 * section '8.2.4 Decoding process for reference picture lists construction' 389 * of the H264 spec. This function can be used by H264 decoder drivers that 390 * need to pass a P reference list to the hardware. 391 */ 392 void 393 v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder, 394 struct v4l2_h264_reference *reflist) 395 { 396 memcpy(reflist, builder->unordered_reflist, 397 sizeof(builder->unordered_reflist[0]) * builder->num_valid); 398 sort_r(reflist, builder->num_valid, sizeof(*reflist), 399 v4l2_h264_p_ref_list_cmp, NULL, builder); 400 401 if (builder->cur_pic_fields != V4L2_H264_FRAME_REF) 402 reorder_field_reflist(builder, reflist); 403 404 print_ref_list_p(builder, reflist); 405 } 406 EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list); 407 408 /** 409 * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists 410 * 411 * @builder: reference list builder context 412 * @b0_reflist: 32 sized array used to store the B0 reference list. Each entry 413 * is a v4l2_h264_reference structure 414 * @b1_reflist: 32 sized array used to store the B1 reference list. Each entry 415 * is a v4l2_h264_reference structure 416 * 417 * This functions builds the B0/B1 reference lists. This procedure is described 418 * in section '8.2.4 Decoding process for reference picture lists construction' 419 * of the H264 spec. This function can be used by H264 decoder drivers that 420 * need to pass B0/B1 reference lists to the hardware. 421 */ 422 void 423 v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder, 424 struct v4l2_h264_reference *b0_reflist, 425 struct v4l2_h264_reference *b1_reflist) 426 { 427 memcpy(b0_reflist, builder->unordered_reflist, 428 sizeof(builder->unordered_reflist[0]) * builder->num_valid); 429 sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist), 430 v4l2_h264_b0_ref_list_cmp, NULL, builder); 431 432 memcpy(b1_reflist, builder->unordered_reflist, 433 sizeof(builder->unordered_reflist[0]) * builder->num_valid); 434 sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist), 435 v4l2_h264_b1_ref_list_cmp, NULL, builder); 436 437 if (builder->cur_pic_fields != V4L2_H264_FRAME_REF) { 438 reorder_field_reflist(builder, b0_reflist); 439 reorder_field_reflist(builder, b1_reflist); 440 } 441 442 if (builder->num_valid > 1 && 443 !memcmp(b1_reflist, b0_reflist, builder->num_valid)) 444 swap(b1_reflist[0], b1_reflist[1]); 445 446 print_ref_list_b(builder, b0_reflist, 0); 447 print_ref_list_b(builder, b1_reflist, 1); 448 } 449 EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists); 450 451 MODULE_LICENSE("GPL"); 452 MODULE_DESCRIPTION("V4L2 H264 Helpers"); 453 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>"); 454