Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * V4L2 H264 helpers.
0004  *
0005  * Copyright (C) 2019 Collabora, Ltd.
0006  *
0007  * Author: Boris Brezillon <boris.brezillon@collabora.com>
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/sort.h>
0012 
0013 #include <media/v4l2-h264.h>
0014 
0015 /*
0016  * Size of the tempory buffer allocated when printing reference lists. The
0017  * output will be truncated if the size is too small.
0018  */
0019 static const int tmp_str_size = 1024;
0020 
0021 /**
0022  * v4l2_h264_init_reflist_builder() - Initialize a P/B0/B1 reference list
0023  *                    builder
0024  *
0025  * @b: the builder context to initialize
0026  * @dec_params: decode parameters control
0027  * @sps: SPS control
0028  * @dpb: DPB to use when creating the reference list
0029  */
0030 void
0031 v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
0032         const struct v4l2_ctrl_h264_decode_params *dec_params,
0033         const struct v4l2_ctrl_h264_sps *sps,
0034         const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES])
0035 {
0036     int cur_frame_num, max_frame_num;
0037     unsigned int i;
0038 
0039     max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
0040     cur_frame_num = dec_params->frame_num;
0041 
0042     memset(b, 0, sizeof(*b));
0043     if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) {
0044         b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt,
0045                          dec_params->top_field_order_cnt);
0046         b->cur_pic_fields = V4L2_H264_FRAME_REF;
0047     } else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) {
0048         b->cur_pic_order_count = dec_params->bottom_field_order_cnt;
0049         b->cur_pic_fields = V4L2_H264_BOTTOM_FIELD_REF;
0050     } else {
0051         b->cur_pic_order_count = dec_params->top_field_order_cnt;
0052         b->cur_pic_fields = V4L2_H264_TOP_FIELD_REF;
0053     }
0054 
0055     for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
0056         if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
0057             continue;
0058 
0059         if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
0060             b->refs[i].longterm = true;
0061 
0062         /*
0063          * Handle frame_num wraparound as described in section
0064          * '8.2.4.1 Decoding process for picture numbers' of the spec.
0065          * For long term references, frame_num is set to
0066          * long_term_frame_idx which requires no wrapping.
0067          */
0068         if (!b->refs[i].longterm && dpb[i].frame_num > cur_frame_num)
0069             b->refs[i].frame_num = (int)dpb[i].frame_num -
0070                            max_frame_num;
0071         else
0072             b->refs[i].frame_num = dpb[i].frame_num;
0073 
0074         b->refs[i].top_field_order_cnt = dpb[i].top_field_order_cnt;
0075         b->refs[i].bottom_field_order_cnt = dpb[i].bottom_field_order_cnt;
0076 
0077         if (b->cur_pic_fields == V4L2_H264_FRAME_REF) {
0078             u8 fields = V4L2_H264_FRAME_REF;
0079 
0080             b->unordered_reflist[b->num_valid].index = i;
0081             b->unordered_reflist[b->num_valid].fields = fields;
0082             b->num_valid++;
0083             continue;
0084         }
0085 
0086         if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF) {
0087             u8 fields = V4L2_H264_TOP_FIELD_REF;
0088 
0089             b->unordered_reflist[b->num_valid].index = i;
0090             b->unordered_reflist[b->num_valid].fields = fields;
0091             b->num_valid++;
0092         }
0093 
0094         if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF) {
0095             u8 fields = V4L2_H264_BOTTOM_FIELD_REF;
0096 
0097             b->unordered_reflist[b->num_valid].index = i;
0098             b->unordered_reflist[b->num_valid].fields = fields;
0099             b->num_valid++;
0100         }
0101     }
0102 
0103     for (i = b->num_valid; i < ARRAY_SIZE(b->unordered_reflist); i++)
0104         b->unordered_reflist[i].index = i;
0105 }
0106 EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder);
0107 
0108 static s32 v4l2_h264_get_poc(const struct v4l2_h264_reflist_builder *b,
0109                  const struct v4l2_h264_reference *ref)
0110 {
0111     switch (ref->fields) {
0112     case V4L2_H264_FRAME_REF:
0113         return min(b->refs[ref->index].top_field_order_cnt,
0114                 b->refs[ref->index].bottom_field_order_cnt);
0115     case V4L2_H264_TOP_FIELD_REF:
0116         return b->refs[ref->index].top_field_order_cnt;
0117     case V4L2_H264_BOTTOM_FIELD_REF:
0118         return b->refs[ref->index].bottom_field_order_cnt;
0119     }
0120 
0121     /* not reached */
0122     return 0;
0123 }
0124 
0125 static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb,
0126                     const void *data)
0127 {
0128     const struct v4l2_h264_reflist_builder *builder = data;
0129     u8 idxa, idxb;
0130 
0131     idxa = ((struct v4l2_h264_reference *)ptra)->index;
0132     idxb = ((struct v4l2_h264_reference *)ptrb)->index;
0133 
0134     if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
0135             idxb >= V4L2_H264_NUM_DPB_ENTRIES))
0136         return 1;
0137 
0138     if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
0139         /* Short term pics first. */
0140         if (!builder->refs[idxa].longterm)
0141             return -1;
0142         else
0143             return 1;
0144     }
0145 
0146     /*
0147      * For frames, short term pics are in descending pic num order and long
0148      * term ones in ascending order. For fields, the same direction is used
0149      * but with frame_num (wrapped). For frames, the value of pic_num and
0150      * frame_num are the same (see formula (8-28) and (8-29)). For this
0151      * reason we can use frame_num only and share this function between
0152      * frames and fields reflist.
0153      */
0154     if (!builder->refs[idxa].longterm)
0155         return builder->refs[idxb].frame_num <
0156                builder->refs[idxa].frame_num ?
0157                -1 : 1;
0158 
0159     return builder->refs[idxa].frame_num < builder->refs[idxb].frame_num ?
0160            -1 : 1;
0161 }
0162 
0163 static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb,
0164                      const void *data)
0165 {
0166     const struct v4l2_h264_reflist_builder *builder = data;
0167     s32 poca, pocb;
0168     u8 idxa, idxb;
0169 
0170     idxa = ((struct v4l2_h264_reference *)ptra)->index;
0171     idxb = ((struct v4l2_h264_reference *)ptrb)->index;
0172 
0173     if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
0174             idxb >= V4L2_H264_NUM_DPB_ENTRIES))
0175         return 1;
0176 
0177     if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
0178         /* Short term pics first. */
0179         if (!builder->refs[idxa].longterm)
0180             return -1;
0181         else
0182             return 1;
0183     }
0184 
0185     /* Long term pics in ascending frame num order. */
0186     if (builder->refs[idxa].longterm)
0187         return builder->refs[idxa].frame_num <
0188                builder->refs[idxb].frame_num ?
0189                -1 : 1;
0190 
0191     poca = v4l2_h264_get_poc(builder, ptra);
0192     pocb = v4l2_h264_get_poc(builder, ptrb);
0193 
0194     /*
0195      * Short term pics with POC < cur POC first in POC descending order
0196      * followed by short term pics with POC > cur POC in POC ascending
0197      * order.
0198      */
0199     if ((poca < builder->cur_pic_order_count) !=
0200          (pocb < builder->cur_pic_order_count))
0201         return poca < pocb ? -1 : 1;
0202     else if (poca < builder->cur_pic_order_count)
0203         return pocb < poca ? -1 : 1;
0204 
0205     return poca < pocb ? -1 : 1;
0206 }
0207 
0208 static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb,
0209                      const void *data)
0210 {
0211     const struct v4l2_h264_reflist_builder *builder = data;
0212     s32 poca, pocb;
0213     u8 idxa, idxb;
0214 
0215     idxa = ((struct v4l2_h264_reference *)ptra)->index;
0216     idxb = ((struct v4l2_h264_reference *)ptrb)->index;
0217 
0218     if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
0219             idxb >= V4L2_H264_NUM_DPB_ENTRIES))
0220         return 1;
0221 
0222     if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
0223         /* Short term pics first. */
0224         if (!builder->refs[idxa].longterm)
0225             return -1;
0226         else
0227             return 1;
0228     }
0229 
0230     /* Long term pics in ascending frame num order. */
0231     if (builder->refs[idxa].longterm)
0232         return builder->refs[idxa].frame_num <
0233                builder->refs[idxb].frame_num ?
0234                -1 : 1;
0235 
0236     poca = v4l2_h264_get_poc(builder, ptra);
0237     pocb = v4l2_h264_get_poc(builder, ptrb);
0238 
0239     /*
0240      * Short term pics with POC > cur POC first in POC ascending order
0241      * followed by short term pics with POC < cur POC in POC descending
0242      * order.
0243      */
0244     if ((poca < builder->cur_pic_order_count) !=
0245         (pocb < builder->cur_pic_order_count))
0246         return pocb < poca ? -1 : 1;
0247     else if (poca < builder->cur_pic_order_count)
0248         return pocb < poca ? -1 : 1;
0249 
0250     return poca < pocb ? -1 : 1;
0251 }
0252 
0253 /*
0254  * The references need to be reordered so that references are alternating
0255  * between top and bottom field references starting with the current picture
0256  * parity. This has to be done for short term and long term references
0257  * separately.
0258  */
0259 static void reorder_field_reflist(const struct v4l2_h264_reflist_builder *b,
0260                   struct v4l2_h264_reference *reflist)
0261 {
0262     struct v4l2_h264_reference tmplist[V4L2_H264_REF_LIST_LEN];
0263     u8 lt, i = 0, j = 0, k = 0;
0264 
0265     memcpy(tmplist, reflist, sizeof(tmplist[0]) * b->num_valid);
0266 
0267     for (lt = 0; lt <= 1; lt++) {
0268         do {
0269             for (; i < b->num_valid && b->refs[tmplist[i].index].longterm == lt; i++) {
0270                 if (tmplist[i].fields == b->cur_pic_fields) {
0271                     reflist[k++] = tmplist[i++];
0272                     break;
0273                 }
0274             }
0275 
0276             for (; j < b->num_valid && b->refs[tmplist[j].index].longterm == lt; j++) {
0277                 if (tmplist[j].fields != b->cur_pic_fields) {
0278                     reflist[k++] = tmplist[j++];
0279                     break;
0280                 }
0281             }
0282         } while ((i < b->num_valid && b->refs[tmplist[i].index].longterm == lt) ||
0283              (j < b->num_valid && b->refs[tmplist[j].index].longterm == lt));
0284     }
0285 }
0286 
0287 static char ref_type_to_char(u8 ref_type)
0288 {
0289     switch (ref_type) {
0290     case V4L2_H264_FRAME_REF:
0291         return 'f';
0292     case V4L2_H264_TOP_FIELD_REF:
0293         return 't';
0294     case V4L2_H264_BOTTOM_FIELD_REF:
0295         return 'b';
0296     }
0297 
0298     return '?';
0299 }
0300 
0301 static const char *format_ref_list_p(const struct v4l2_h264_reflist_builder *builder,
0302                      struct v4l2_h264_reference *reflist,
0303                      char **out_str)
0304 {
0305     int n = 0, i;
0306 
0307     *out_str = kmalloc(tmp_str_size, GFP_KERNEL);
0308 
0309     n += snprintf(*out_str + n, tmp_str_size - n, "|");
0310 
0311     for (i = 0; i < builder->num_valid; i++) {
0312         /* this is pic_num for frame and frame_num (wrapped) for field,
0313          * but for frame pic_num is equal to frame_num (wrapped).
0314          */
0315         int frame_num = builder->refs[reflist[i].index].frame_num;
0316         bool longterm = builder->refs[reflist[i].index].longterm;
0317 
0318         n += scnprintf(*out_str + n, tmp_str_size - n, "%i%c%c|",
0319                    frame_num, longterm ? 'l' : 's',
0320                    ref_type_to_char(reflist[i].fields));
0321     }
0322 
0323     return *out_str;
0324 }
0325 
0326 static void print_ref_list_p(const struct v4l2_h264_reflist_builder *builder,
0327                  struct v4l2_h264_reference *reflist)
0328 {
0329     char *buf = NULL;
0330 
0331     pr_debug("ref_pic_list_p (cur_poc %u%c) %s\n",
0332          builder->cur_pic_order_count,
0333          ref_type_to_char(builder->cur_pic_fields),
0334          format_ref_list_p(builder, reflist, &buf));
0335 
0336     kfree(buf);
0337 }
0338 
0339 static const char *format_ref_list_b(const struct v4l2_h264_reflist_builder *builder,
0340                      struct v4l2_h264_reference *reflist,
0341                      char **out_str)
0342 {
0343     int n = 0, i;
0344 
0345     *out_str = kmalloc(tmp_str_size, GFP_KERNEL);
0346 
0347     n += snprintf(*out_str + n, tmp_str_size - n, "|");
0348 
0349     for (i = 0; i < builder->num_valid; i++) {
0350         int frame_num = builder->refs[reflist[i].index].frame_num;
0351         u32 poc = v4l2_h264_get_poc(builder, reflist + i);
0352         bool longterm = builder->refs[reflist[i].index].longterm;
0353 
0354         n += scnprintf(*out_str + n, tmp_str_size - n, "%i%c%c|",
0355                    longterm ? frame_num : poc,
0356                    longterm ? 'l' : 's',
0357                    ref_type_to_char(reflist[i].fields));
0358     }
0359 
0360     return *out_str;
0361 }
0362 
0363 static void print_ref_list_b(const struct v4l2_h264_reflist_builder *builder,
0364                  struct v4l2_h264_reference *reflist, u8 list_num)
0365 {
0366     char *buf = NULL;
0367 
0368     pr_debug("ref_pic_list_b%u (cur_poc %u%c) %s",
0369          list_num, builder->cur_pic_order_count,
0370          ref_type_to_char(builder->cur_pic_fields),
0371          format_ref_list_b(builder, reflist, &buf));
0372 
0373     kfree(buf);
0374 }
0375 
0376 /**
0377  * v4l2_h264_build_p_ref_list() - Build the P reference list
0378  *
0379  * @builder: reference list builder context
0380  * @reflist: 32 sized array used to store the P reference list. Each entry
0381  *       is a v4l2_h264_reference structure
0382  *
0383  * This functions builds the P reference lists. This procedure is describe in
0384  * section '8.2.4 Decoding process for reference picture lists construction'
0385  * of the H264 spec. This function can be used by H264 decoder drivers that
0386  * need to pass a P reference list to the hardware.
0387  */
0388 void
0389 v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder,
0390                struct v4l2_h264_reference *reflist)
0391 {
0392     memcpy(reflist, builder->unordered_reflist,
0393            sizeof(builder->unordered_reflist[0]) * builder->num_valid);
0394     sort_r(reflist, builder->num_valid, sizeof(*reflist),
0395            v4l2_h264_p_ref_list_cmp, NULL, builder);
0396 
0397     if (builder->cur_pic_fields != V4L2_H264_FRAME_REF)
0398         reorder_field_reflist(builder, reflist);
0399 
0400     print_ref_list_p(builder, reflist);
0401 }
0402 EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list);
0403 
0404 /**
0405  * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists
0406  *
0407  * @builder: reference list builder context
0408  * @b0_reflist: 32 sized array used to store the B0 reference list. Each entry
0409  *      is a v4l2_h264_reference structure
0410  * @b1_reflist: 32 sized array used to store the B1 reference list. Each entry
0411  *      is a v4l2_h264_reference structure
0412  *
0413  * This functions builds the B0/B1 reference lists. This procedure is described
0414  * in section '8.2.4 Decoding process for reference picture lists construction'
0415  * of the H264 spec. This function can be used by H264 decoder drivers that
0416  * need to pass B0/B1 reference lists to the hardware.
0417  */
0418 void
0419 v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder,
0420                 struct v4l2_h264_reference *b0_reflist,
0421                 struct v4l2_h264_reference *b1_reflist)
0422 {
0423     memcpy(b0_reflist, builder->unordered_reflist,
0424            sizeof(builder->unordered_reflist[0]) * builder->num_valid);
0425     sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist),
0426            v4l2_h264_b0_ref_list_cmp, NULL, builder);
0427 
0428     memcpy(b1_reflist, builder->unordered_reflist,
0429            sizeof(builder->unordered_reflist[0]) * builder->num_valid);
0430     sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist),
0431            v4l2_h264_b1_ref_list_cmp, NULL, builder);
0432 
0433     if (builder->cur_pic_fields != V4L2_H264_FRAME_REF) {
0434         reorder_field_reflist(builder, b0_reflist);
0435         reorder_field_reflist(builder, b1_reflist);
0436     }
0437 
0438     if (builder->num_valid > 1 &&
0439         !memcmp(b1_reflist, b0_reflist, builder->num_valid))
0440         swap(b1_reflist[0], b1_reflist[1]);
0441 
0442     print_ref_list_b(builder, b0_reflist, 0);
0443     print_ref_list_b(builder, b1_reflist, 1);
0444 }
0445 EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists);
0446 
0447 MODULE_LICENSE("GPL");
0448 MODULE_DESCRIPTION("V4L2 H264 Helpers");
0449 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");