162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * TW5864 driver - H.264 headers generation functions 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/log2.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "tw5864.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic u8 marker[] = { 0x00, 0x00, 0x00, 0x01 }; 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* 1562306a36Sopenharmony_ci * Exponential-Golomb coding functions 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * These functions are used for generation of H.264 bitstream headers. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * This code is derived from tw5864 reference driver by manufacturers, which 2062306a36Sopenharmony_ci * itself apparently was derived from x264 project. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* Bitstream writing context */ 2462306a36Sopenharmony_cistruct bs { 2562306a36Sopenharmony_ci u8 *buf; /* pointer to buffer beginning */ 2662306a36Sopenharmony_ci u8 *buf_end; /* pointer to buffer end */ 2762306a36Sopenharmony_ci u8 *ptr; /* pointer to current byte in buffer */ 2862306a36Sopenharmony_ci unsigned int bits_left; /* number of available bits in current byte */ 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void bs_init(struct bs *s, void *buf, int size) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci s->buf = buf; 3462306a36Sopenharmony_ci s->ptr = buf; 3562306a36Sopenharmony_ci s->buf_end = s->ptr + size; 3662306a36Sopenharmony_ci s->bits_left = 8; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic int bs_len(struct bs *s) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci return s->ptr - s->buf; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic void bs_write(struct bs *s, int count, u32 bits) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci if (s->ptr >= s->buf_end - 4) 4762306a36Sopenharmony_ci return; 4862306a36Sopenharmony_ci while (count > 0) { 4962306a36Sopenharmony_ci if (count < 32) 5062306a36Sopenharmony_ci bits &= (1 << count) - 1; 5162306a36Sopenharmony_ci if (count < s->bits_left) { 5262306a36Sopenharmony_ci *s->ptr = (*s->ptr << count) | bits; 5362306a36Sopenharmony_ci s->bits_left -= count; 5462306a36Sopenharmony_ci break; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci *s->ptr = (*s->ptr << s->bits_left) | 5762306a36Sopenharmony_ci (bits >> (count - s->bits_left)); 5862306a36Sopenharmony_ci count -= s->bits_left; 5962306a36Sopenharmony_ci s->ptr++; 6062306a36Sopenharmony_ci s->bits_left = 8; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void bs_write1(struct bs *s, u32 bit) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci if (s->ptr < s->buf_end) { 6762306a36Sopenharmony_ci *s->ptr <<= 1; 6862306a36Sopenharmony_ci *s->ptr |= bit; 6962306a36Sopenharmony_ci s->bits_left--; 7062306a36Sopenharmony_ci if (s->bits_left == 0) { 7162306a36Sopenharmony_ci s->ptr++; 7262306a36Sopenharmony_ci s->bits_left = 8; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic void bs_write_ue(struct bs *s, u32 val) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci if (val == 0) { 8062306a36Sopenharmony_ci bs_write1(s, 1); 8162306a36Sopenharmony_ci } else { 8262306a36Sopenharmony_ci val++; 8362306a36Sopenharmony_ci bs_write(s, 2 * fls(val) - 1, val); 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void bs_write_se(struct bs *s, int val) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci bs_write_ue(s, val <= 0 ? -val * 2 : val * 2 - 1); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic void bs_rbsp_trailing(struct bs *s) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci bs_write1(s, 1); 9562306a36Sopenharmony_ci if (s->bits_left != 8) 9662306a36Sopenharmony_ci bs_write(s, s->bits_left, 0x00); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* H.264 headers generation functions */ 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int tw5864_h264_gen_sps_rbsp(u8 *buf, size_t size, int width, int height) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct bs bs, *s; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci s = &bs; 10662306a36Sopenharmony_ci bs_init(s, buf, size); 10762306a36Sopenharmony_ci bs_write(s, 8, 0x42); /* profile_idc, baseline */ 10862306a36Sopenharmony_ci bs_write(s, 1, 1); /* constraint_set0_flag */ 10962306a36Sopenharmony_ci bs_write(s, 1, 1); /* constraint_set1_flag */ 11062306a36Sopenharmony_ci bs_write(s, 1, 0); /* constraint_set2_flag */ 11162306a36Sopenharmony_ci bs_write(s, 5, 0); /* reserved_zero_5bits */ 11262306a36Sopenharmony_ci bs_write(s, 8, 0x1e); /* level_idc */ 11362306a36Sopenharmony_ci bs_write_ue(s, 0); /* seq_parameter_set_id */ 11462306a36Sopenharmony_ci bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4); /* log2_max_frame_num_minus4 */ 11562306a36Sopenharmony_ci bs_write_ue(s, 0); /* pic_order_cnt_type */ 11662306a36Sopenharmony_ci /* log2_max_pic_order_cnt_lsb_minus4 */ 11762306a36Sopenharmony_ci bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4); 11862306a36Sopenharmony_ci bs_write_ue(s, 1); /* num_ref_frames */ 11962306a36Sopenharmony_ci bs_write(s, 1, 0); /* gaps_in_frame_num_value_allowed_flag */ 12062306a36Sopenharmony_ci bs_write_ue(s, width / 16 - 1); /* pic_width_in_mbs_minus1 */ 12162306a36Sopenharmony_ci bs_write_ue(s, height / 16 - 1); /* pic_height_in_map_units_minus1 */ 12262306a36Sopenharmony_ci bs_write(s, 1, 1); /* frame_mbs_only_flag */ 12362306a36Sopenharmony_ci bs_write(s, 1, 0); /* direct_8x8_inference_flag */ 12462306a36Sopenharmony_ci bs_write(s, 1, 0); /* frame_cropping_flag */ 12562306a36Sopenharmony_ci bs_write(s, 1, 0); /* vui_parameters_present_flag */ 12662306a36Sopenharmony_ci bs_rbsp_trailing(s); 12762306a36Sopenharmony_ci return bs_len(s); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int tw5864_h264_gen_pps_rbsp(u8 *buf, size_t size, int qp) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct bs bs, *s; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci s = &bs; 13562306a36Sopenharmony_ci bs_init(s, buf, size); 13662306a36Sopenharmony_ci bs_write_ue(s, 0); /* pic_parameter_set_id */ 13762306a36Sopenharmony_ci bs_write_ue(s, 0); /* seq_parameter_set_id */ 13862306a36Sopenharmony_ci bs_write(s, 1, 0); /* entropy_coding_mode_flag */ 13962306a36Sopenharmony_ci bs_write(s, 1, 0); /* pic_order_present_flag */ 14062306a36Sopenharmony_ci bs_write_ue(s, 0); /* num_slice_groups_minus1 */ 14162306a36Sopenharmony_ci bs_write_ue(s, 0); /* i_num_ref_idx_l0_active_minus1 */ 14262306a36Sopenharmony_ci bs_write_ue(s, 0); /* i_num_ref_idx_l1_active_minus1 */ 14362306a36Sopenharmony_ci bs_write(s, 1, 0); /* weighted_pred_flag */ 14462306a36Sopenharmony_ci bs_write(s, 2, 0); /* weighted_bipred_idc */ 14562306a36Sopenharmony_ci bs_write_se(s, qp - 26); /* pic_init_qp_minus26 */ 14662306a36Sopenharmony_ci bs_write_se(s, qp - 26); /* pic_init_qs_minus26 */ 14762306a36Sopenharmony_ci bs_write_se(s, 0); /* chroma_qp_index_offset */ 14862306a36Sopenharmony_ci bs_write(s, 1, 0); /* deblocking_filter_control_present_flag */ 14962306a36Sopenharmony_ci bs_write(s, 1, 0); /* constrained_intra_pred_flag */ 15062306a36Sopenharmony_ci bs_write(s, 1, 0); /* redundant_pic_cnt_present_flag */ 15162306a36Sopenharmony_ci bs_rbsp_trailing(s); 15262306a36Sopenharmony_ci return bs_len(s); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int tw5864_h264_gen_slice_head(u8 *buf, size_t size, 15662306a36Sopenharmony_ci unsigned int idr_pic_id, 15762306a36Sopenharmony_ci unsigned int frame_gop_seqno, 15862306a36Sopenharmony_ci int *tail_nb_bits, u8 *tail) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct bs bs, *s; 16162306a36Sopenharmony_ci int is_i_frame = frame_gop_seqno == 0; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci s = &bs; 16462306a36Sopenharmony_ci bs_init(s, buf, size); 16562306a36Sopenharmony_ci bs_write_ue(s, 0); /* first_mb_in_slice */ 16662306a36Sopenharmony_ci bs_write_ue(s, is_i_frame ? 2 : 5); /* slice_type - I or P */ 16762306a36Sopenharmony_ci bs_write_ue(s, 0); /* pic_parameter_set_id */ 16862306a36Sopenharmony_ci bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno); /* frame_num */ 16962306a36Sopenharmony_ci if (is_i_frame) 17062306a36Sopenharmony_ci bs_write_ue(s, idr_pic_id); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* pic_order_cnt_lsb */ 17362306a36Sopenharmony_ci bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (is_i_frame) { 17662306a36Sopenharmony_ci bs_write1(s, 0); /* no_output_of_prior_pics_flag */ 17762306a36Sopenharmony_ci bs_write1(s, 0); /* long_term_reference_flag */ 17862306a36Sopenharmony_ci } else { 17962306a36Sopenharmony_ci bs_write1(s, 0); /* num_ref_idx_active_override_flag */ 18062306a36Sopenharmony_ci bs_write1(s, 0); /* ref_pic_list_reordering_flag_l0 */ 18162306a36Sopenharmony_ci bs_write1(s, 0); /* adaptive_ref_pic_marking_mode_flag */ 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci bs_write_se(s, 0); /* slice_qp_delta */ 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (s->bits_left != 8) { 18762306a36Sopenharmony_ci *tail = ((s->ptr[0]) << s->bits_left); 18862306a36Sopenharmony_ci *tail_nb_bits = 8 - s->bits_left; 18962306a36Sopenharmony_ci } else { 19062306a36Sopenharmony_ci *tail = 0; 19162306a36Sopenharmony_ci *tail_nb_bits = 0; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return bs_len(s); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_civoid tw5864_h264_put_stream_header(u8 **buf, size_t *space_left, int qp, 19862306a36Sopenharmony_ci int width, int height) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci int nal_len; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* SPS */ 20362306a36Sopenharmony_ci memcpy(*buf, marker, sizeof(marker)); 20462306a36Sopenharmony_ci *buf += 4; 20562306a36Sopenharmony_ci *space_left -= 4; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci **buf = 0x67; /* SPS NAL header */ 20862306a36Sopenharmony_ci *buf += 1; 20962306a36Sopenharmony_ci *space_left -= 1; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci nal_len = tw5864_h264_gen_sps_rbsp(*buf, *space_left, width, height); 21262306a36Sopenharmony_ci *buf += nal_len; 21362306a36Sopenharmony_ci *space_left -= nal_len; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* PPS */ 21662306a36Sopenharmony_ci memcpy(*buf, marker, sizeof(marker)); 21762306a36Sopenharmony_ci *buf += 4; 21862306a36Sopenharmony_ci *space_left -= 4; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci **buf = 0x68; /* PPS NAL header */ 22162306a36Sopenharmony_ci *buf += 1; 22262306a36Sopenharmony_ci *space_left -= 1; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci nal_len = tw5864_h264_gen_pps_rbsp(*buf, *space_left, qp); 22562306a36Sopenharmony_ci *buf += nal_len; 22662306a36Sopenharmony_ci *space_left -= nal_len; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_civoid tw5864_h264_put_slice_header(u8 **buf, size_t *space_left, 23062306a36Sopenharmony_ci unsigned int idr_pic_id, 23162306a36Sopenharmony_ci unsigned int frame_gop_seqno, 23262306a36Sopenharmony_ci int *tail_nb_bits, u8 *tail) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci int nal_len; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci memcpy(*buf, marker, sizeof(marker)); 23762306a36Sopenharmony_ci *buf += 4; 23862306a36Sopenharmony_ci *space_left -= 4; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Frame NAL header */ 24162306a36Sopenharmony_ci **buf = (frame_gop_seqno == 0) ? 0x25 : 0x21; 24262306a36Sopenharmony_ci *buf += 1; 24362306a36Sopenharmony_ci *space_left -= 1; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci nal_len = tw5864_h264_gen_slice_head(*buf, *space_left, idr_pic_id, 24662306a36Sopenharmony_ci frame_gop_seqno, tail_nb_bits, 24762306a36Sopenharmony_ci tail); 24862306a36Sopenharmony_ci *buf += nal_len; 24962306a36Sopenharmony_ci *space_left -= nal_len; 25062306a36Sopenharmony_ci} 251