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 * @slice_params: first slice parameters control
  22 * @sps: SPS control
  23 * @dpb: DPB to use when creating the reference list
  24 */
  25void
  26v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
  27                const struct v4l2_ctrl_h264_decode_params *dec_params,
  28                const struct v4l2_ctrl_h264_slice_params *slice_params,
  29                const struct v4l2_ctrl_h264_sps *sps,
  30                const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES])
  31{
  32        int cur_frame_num, max_frame_num;
  33        unsigned int i;
  34
  35        max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
  36        cur_frame_num = slice_params->frame_num;
  37
  38        memset(b, 0, sizeof(*b));
  39        if (!(slice_params->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC))
  40                b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt,
  41                                             dec_params->top_field_order_cnt);
  42        else if (slice_params->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)
  43                b->cur_pic_order_count = dec_params->bottom_field_order_cnt;
  44        else
  45                b->cur_pic_order_count = dec_params->top_field_order_cnt;
  46
  47        for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
  48                u32 pic_order_count;
  49
  50                if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
  51                        continue;
  52
  53                b->refs[i].pic_num = dpb[i].pic_num;
  54                if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
  55                        b->refs[i].longterm = true;
  56
  57                /*
  58                 * Handle frame_num wraparound as described in section
  59                 * '8.2.4.1 Decoding process for picture numbers' of the spec.
  60                 * TODO: This logic will have to be adjusted when we start
  61                 * supporting interlaced content.
  62                 */
  63                if (dpb[i].frame_num > cur_frame_num)
  64                        b->refs[i].frame_num = (int)dpb[i].frame_num -
  65                                               max_frame_num;
  66                else
  67                        b->refs[i].frame_num = dpb[i].frame_num;
  68
  69                if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD))
  70                        pic_order_count = min(dpb[i].top_field_order_cnt,
  71                                              dpb[i].bottom_field_order_cnt);
  72                else if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD)
  73                        pic_order_count = dpb[i].bottom_field_order_cnt;
  74                else
  75                        pic_order_count = dpb[i].top_field_order_cnt;
  76
  77                b->refs[i].pic_order_count = pic_order_count;
  78                b->unordered_reflist[b->num_valid] = i;
  79                b->num_valid++;
  80        }
  81
  82        for (i = b->num_valid; i < ARRAY_SIZE(b->unordered_reflist); i++)
  83                b->unordered_reflist[i] = i;
  84}
  85EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder);
  86
  87static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb,
  88                                    const void *data)
  89{
  90        const struct v4l2_h264_reflist_builder *builder = data;
  91        u8 idxa, idxb;
  92
  93        idxa = *((u8 *)ptra);
  94        idxb = *((u8 *)ptrb);
  95
  96        if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
  97                    idxb >= V4L2_H264_NUM_DPB_ENTRIES))
  98                return 1;
  99
 100        if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
 101                /* Short term pics first. */
 102                if (!builder->refs[idxa].longterm)
 103                        return -1;
 104                else
 105                        return 1;
 106        }
 107
 108        /*
 109         * Short term pics in descending pic num order, long term ones in
 110         * ascending order.
 111         */
 112        if (!builder->refs[idxa].longterm)
 113                return builder->refs[idxb].frame_num <
 114                       builder->refs[idxa].frame_num ?
 115                       -1 : 1;
 116
 117        return builder->refs[idxa].pic_num < builder->refs[idxb].pic_num ?
 118               -1 : 1;
 119}
 120
 121static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb,
 122                                     const void *data)
 123{
 124        const struct v4l2_h264_reflist_builder *builder = data;
 125        s32 poca, pocb;
 126        u8 idxa, idxb;
 127
 128        idxa = *((u8 *)ptra);
 129        idxb = *((u8 *)ptrb);
 130
 131        if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
 132                    idxb >= V4L2_H264_NUM_DPB_ENTRIES))
 133                return 1;
 134
 135        if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
 136                /* Short term pics first. */
 137                if (!builder->refs[idxa].longterm)
 138                        return -1;
 139                else
 140                        return 1;
 141        }
 142
 143        /* Long term pics in ascending pic num order. */
 144        if (builder->refs[idxa].longterm)
 145                return builder->refs[idxa].pic_num <
 146                       builder->refs[idxb].pic_num ?
 147                       -1 : 1;
 148
 149        poca = builder->refs[idxa].pic_order_count;
 150        pocb = builder->refs[idxb].pic_order_count;
 151
 152        /*
 153         * Short term pics with POC < cur POC first in POC descending order
 154         * followed by short term pics with POC > cur POC in POC ascending
 155         * order.
 156         */
 157        if ((poca < builder->cur_pic_order_count) !=
 158             (pocb < builder->cur_pic_order_count))
 159                return poca < pocb ? -1 : 1;
 160        else if (poca < builder->cur_pic_order_count)
 161                return pocb < poca ? -1 : 1;
 162
 163        return poca < pocb ? -1 : 1;
 164}
 165
 166static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb,
 167                                     const void *data)
 168{
 169        const struct v4l2_h264_reflist_builder *builder = data;
 170        s32 poca, pocb;
 171        u8 idxa, idxb;
 172
 173        idxa = *((u8 *)ptra);
 174        idxb = *((u8 *)ptrb);
 175
 176        if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
 177                    idxb >= V4L2_H264_NUM_DPB_ENTRIES))
 178                return 1;
 179
 180        if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
 181                /* Short term pics first. */
 182                if (!builder->refs[idxa].longterm)
 183                        return -1;
 184                else
 185                        return 1;
 186        }
 187
 188        /* Long term pics in ascending pic num order. */
 189        if (builder->refs[idxa].longterm)
 190                return builder->refs[idxa].pic_num <
 191                       builder->refs[idxb].pic_num ?
 192                       -1 : 1;
 193
 194        poca = builder->refs[idxa].pic_order_count;
 195        pocb = builder->refs[idxb].pic_order_count;
 196
 197        /*
 198         * Short term pics with POC > cur POC first in POC ascending order
 199         * followed by short term pics with POC < cur POC in POC descending
 200         * order.
 201         */
 202        if ((poca < builder->cur_pic_order_count) !=
 203            (pocb < builder->cur_pic_order_count))
 204                return pocb < poca ? -1 : 1;
 205        else if (poca < builder->cur_pic_order_count)
 206                return pocb < poca ? -1 : 1;
 207
 208        return poca < pocb ? -1 : 1;
 209}
 210
 211/**
 212 * v4l2_h264_build_p_ref_list() - Build the P reference list
 213 *
 214 * @builder: reference list builder context
 215 * @reflist: 16-bytes array used to store the P reference list. Each entry
 216 *           is an index in the DPB
 217 *
 218 * This functions builds the P reference lists. This procedure is describe in
 219 * section '8.2.4 Decoding process for reference picture lists construction'
 220 * of the H264 spec. This function can be used by H264 decoder drivers that
 221 * need to pass a P reference list to the hardware.
 222 */
 223void
 224v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder,
 225                           u8 *reflist)
 226{
 227        memcpy(reflist, builder->unordered_reflist,
 228               sizeof(builder->unordered_reflist[0]) * builder->num_valid);
 229        sort_r(reflist, builder->num_valid, sizeof(*reflist),
 230               v4l2_h264_p_ref_list_cmp, NULL, builder);
 231}
 232EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list);
 233
 234/**
 235 * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists
 236 *
 237 * @builder: reference list builder context
 238 * @b0_reflist: 16-bytes array used to store the B0 reference list. Each entry
 239 *              is an index in the DPB
 240 * @b1_reflist: 16-bytes array used to store the B1 reference list. Each entry
 241 *              is an index in the DPB
 242 *
 243 * This functions builds the B0/B1 reference lists. This procedure is described
 244 * in section '8.2.4 Decoding process for reference picture lists construction'
 245 * of the H264 spec. This function can be used by H264 decoder drivers that
 246 * need to pass B0/B1 reference lists to the hardware.
 247 */
 248void
 249v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder,
 250                            u8 *b0_reflist, u8 *b1_reflist)
 251{
 252        memcpy(b0_reflist, builder->unordered_reflist,
 253               sizeof(builder->unordered_reflist[0]) * builder->num_valid);
 254        sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist),
 255               v4l2_h264_b0_ref_list_cmp, NULL, builder);
 256
 257        memcpy(b1_reflist, builder->unordered_reflist,
 258               sizeof(builder->unordered_reflist[0]) * builder->num_valid);
 259        sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist),
 260               v4l2_h264_b1_ref_list_cmp, NULL, builder);
 261
 262        if (builder->num_valid > 1 &&
 263            !memcmp(b1_reflist, b0_reflist, builder->num_valid))
 264                swap(b1_reflist[0], b1_reflist[1]);
 265}
 266EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists);
 267
 268MODULE_LICENSE("GPL");
 269MODULE_DESCRIPTION("V4L2 H264 Helpers");
 270MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");
 271