linux/drivers/media/v4l2-core/v4l2-h264.c
<<
>>
Prefs
   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 */
  24void
  25v4l2_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}
  83EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder);
  84
  85static 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
 119static 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
 164static 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 */
 221void
 222v4l2_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}
 230EXPORT_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 */
 246void
 247v4l2_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}
 264EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists);
 265
 266MODULE_LICENSE("GPL");
 267MODULE_DESCRIPTION("V4L2 H264 Helpers");
 268MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");
 269