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