1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * TW5864 driver - H.264 headers generation functions 4 * 5 * Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com> 6 */ 7 8 #include <linux/log2.h> 9 10 #include "tw5864.h" 11 12 static u8 marker[] = { 0x00, 0x00, 0x00, 0x01 }; 13 14 /* 15 * Exponential-Golomb coding functions 16 * 17 * These functions are used for generation of H.264 bitstream headers. 18 * 19 * This code is derived from tw5864 reference driver by manufacturers, which 20 * itself apparently was derived from x264 project. 21 */ 22 23 /* Bitstream writing context */ 24 struct bs { 25 u8 *buf; /* pointer to buffer beginning */ 26 u8 *buf_end; /* pointer to buffer end */ 27 u8 *ptr; /* pointer to current byte in buffer */ 28 unsigned int bits_left; /* number of available bits in current byte */ 29 }; 30 31 static void bs_init(struct bs *s, void *buf, int size) 32 { 33 s->buf = buf; 34 s->ptr = buf; 35 s->buf_end = s->ptr + size; 36 s->bits_left = 8; 37 } 38 39 static int bs_len(struct bs *s) 40 { 41 return s->ptr - s->buf; 42 } 43 44 static void bs_write(struct bs *s, int count, u32 bits) 45 { 46 if (s->ptr >= s->buf_end - 4) 47 return; 48 while (count > 0) { 49 if (count < 32) 50 bits &= (1 << count) - 1; 51 if (count < s->bits_left) { 52 *s->ptr = (*s->ptr << count) | bits; 53 s->bits_left -= count; 54 break; 55 } 56 *s->ptr = (*s->ptr << s->bits_left) | 57 (bits >> (count - s->bits_left)); 58 count -= s->bits_left; 59 s->ptr++; 60 s->bits_left = 8; 61 } 62 } 63 64 static void bs_write1(struct bs *s, u32 bit) 65 { 66 if (s->ptr < s->buf_end) { 67 *s->ptr <<= 1; 68 *s->ptr |= bit; 69 s->bits_left--; 70 if (s->bits_left == 0) { 71 s->ptr++; 72 s->bits_left = 8; 73 } 74 } 75 } 76 77 static void bs_write_ue(struct bs *s, u32 val) 78 { 79 if (val == 0) { 80 bs_write1(s, 1); 81 } else { 82 val++; 83 bs_write(s, 2 * fls(val) - 1, val); 84 } 85 } 86 87 static void bs_write_se(struct bs *s, int val) 88 { 89 bs_write_ue(s, val <= 0 ? -val * 2 : val * 2 - 1); 90 } 91 92 static void bs_rbsp_trailing(struct bs *s) 93 { 94 bs_write1(s, 1); 95 if (s->bits_left != 8) 96 bs_write(s, s->bits_left, 0x00); 97 } 98 99 /* H.264 headers generation functions */ 100 101 static int tw5864_h264_gen_sps_rbsp(u8 *buf, size_t size, int width, int height) 102 { 103 struct bs bs, *s; 104 105 s = &bs; 106 bs_init(s, buf, size); 107 bs_write(s, 8, 0x42); /* profile_idc, baseline */ 108 bs_write(s, 1, 1); /* constraint_set0_flag */ 109 bs_write(s, 1, 1); /* constraint_set1_flag */ 110 bs_write(s, 1, 0); /* constraint_set2_flag */ 111 bs_write(s, 5, 0); /* reserved_zero_5bits */ 112 bs_write(s, 8, 0x1e); /* level_idc */ 113 bs_write_ue(s, 0); /* seq_parameter_set_id */ 114 bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4); /* log2_max_frame_num_minus4 */ 115 bs_write_ue(s, 0); /* pic_order_cnt_type */ 116 /* log2_max_pic_order_cnt_lsb_minus4 */ 117 bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4); 118 bs_write_ue(s, 1); /* num_ref_frames */ 119 bs_write(s, 1, 0); /* gaps_in_frame_num_value_allowed_flag */ 120 bs_write_ue(s, width / 16 - 1); /* pic_width_in_mbs_minus1 */ 121 bs_write_ue(s, height / 16 - 1); /* pic_height_in_map_units_minus1 */ 122 bs_write(s, 1, 1); /* frame_mbs_only_flag */ 123 bs_write(s, 1, 0); /* direct_8x8_inference_flag */ 124 bs_write(s, 1, 0); /* frame_cropping_flag */ 125 bs_write(s, 1, 0); /* vui_parameters_present_flag */ 126 bs_rbsp_trailing(s); 127 return bs_len(s); 128 } 129 130 static int tw5864_h264_gen_pps_rbsp(u8 *buf, size_t size, int qp) 131 { 132 struct bs bs, *s; 133 134 s = &bs; 135 bs_init(s, buf, size); 136 bs_write_ue(s, 0); /* pic_parameter_set_id */ 137 bs_write_ue(s, 0); /* seq_parameter_set_id */ 138 bs_write(s, 1, 0); /* entropy_coding_mode_flag */ 139 bs_write(s, 1, 0); /* pic_order_present_flag */ 140 bs_write_ue(s, 0); /* num_slice_groups_minus1 */ 141 bs_write_ue(s, 0); /* i_num_ref_idx_l0_active_minus1 */ 142 bs_write_ue(s, 0); /* i_num_ref_idx_l1_active_minus1 */ 143 bs_write(s, 1, 0); /* weighted_pred_flag */ 144 bs_write(s, 2, 0); /* weighted_bipred_idc */ 145 bs_write_se(s, qp - 26); /* pic_init_qp_minus26 */ 146 bs_write_se(s, qp - 26); /* pic_init_qs_minus26 */ 147 bs_write_se(s, 0); /* chroma_qp_index_offset */ 148 bs_write(s, 1, 0); /* deblocking_filter_control_present_flag */ 149 bs_write(s, 1, 0); /* constrained_intra_pred_flag */ 150 bs_write(s, 1, 0); /* redundant_pic_cnt_present_flag */ 151 bs_rbsp_trailing(s); 152 return bs_len(s); 153 } 154 155 static int tw5864_h264_gen_slice_head(u8 *buf, size_t size, 156 unsigned int idr_pic_id, 157 unsigned int frame_gop_seqno, 158 int *tail_nb_bits, u8 *tail) 159 { 160 struct bs bs, *s; 161 int is_i_frame = frame_gop_seqno == 0; 162 163 s = &bs; 164 bs_init(s, buf, size); 165 bs_write_ue(s, 0); /* first_mb_in_slice */ 166 bs_write_ue(s, is_i_frame ? 2 : 5); /* slice_type - I or P */ 167 bs_write_ue(s, 0); /* pic_parameter_set_id */ 168 bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno); /* frame_num */ 169 if (is_i_frame) 170 bs_write_ue(s, idr_pic_id); 171 172 /* pic_order_cnt_lsb */ 173 bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno); 174 175 if (is_i_frame) { 176 bs_write1(s, 0); /* no_output_of_prior_pics_flag */ 177 bs_write1(s, 0); /* long_term_reference_flag */ 178 } else { 179 bs_write1(s, 0); /* num_ref_idx_active_override_flag */ 180 bs_write1(s, 0); /* ref_pic_list_reordering_flag_l0 */ 181 bs_write1(s, 0); /* adaptive_ref_pic_marking_mode_flag */ 182 } 183 184 bs_write_se(s, 0); /* slice_qp_delta */ 185 186 if (s->bits_left != 8) { 187 *tail = ((s->ptr[0]) << s->bits_left); 188 *tail_nb_bits = 8 - s->bits_left; 189 } else { 190 *tail = 0; 191 *tail_nb_bits = 0; 192 } 193 194 return bs_len(s); 195 } 196 197 void tw5864_h264_put_stream_header(u8 **buf, size_t *space_left, int qp, 198 int width, int height) 199 { 200 int nal_len; 201 202 /* SPS */ 203 memcpy(*buf, marker, sizeof(marker)); 204 *buf += 4; 205 *space_left -= 4; 206 207 **buf = 0x67; /* SPS NAL header */ 208 *buf += 1; 209 *space_left -= 1; 210 211 nal_len = tw5864_h264_gen_sps_rbsp(*buf, *space_left, width, height); 212 *buf += nal_len; 213 *space_left -= nal_len; 214 215 /* PPS */ 216 memcpy(*buf, marker, sizeof(marker)); 217 *buf += 4; 218 *space_left -= 4; 219 220 **buf = 0x68; /* PPS NAL header */ 221 *buf += 1; 222 *space_left -= 1; 223 224 nal_len = tw5864_h264_gen_pps_rbsp(*buf, *space_left, qp); 225 *buf += nal_len; 226 *space_left -= nal_len; 227 } 228 229 void tw5864_h264_put_slice_header(u8 **buf, size_t *space_left, 230 unsigned int idr_pic_id, 231 unsigned int frame_gop_seqno, 232 int *tail_nb_bits, u8 *tail) 233 { 234 int nal_len; 235 236 memcpy(*buf, marker, sizeof(marker)); 237 *buf += 4; 238 *space_left -= 4; 239 240 /* Frame NAL header */ 241 **buf = (frame_gop_seqno == 0) ? 0x25 : 0x21; 242 *buf += 1; 243 *space_left -= 1; 244 245 nal_len = tw5864_h264_gen_slice_head(*buf, *space_left, idr_pic_id, 246 frame_gop_seqno, tail_nb_bits, 247 tail); 248 *buf += nal_len; 249 *space_left -= nal_len; 250 } 251