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 */ 25 void 26 v4l2_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 } 85 EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder); 86 87 static 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 121 static 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 166 static 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 */ 223 void 224 v4l2_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 } 232 EXPORT_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 */ 248 void 249 v4l2_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 } 266 EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists); 267 268 MODULE_LICENSE("GPL"); 269 MODULE_DESCRIPTION("V4L2 H264 Helpers"); 270 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>"); 271