18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * TW5864 driver - H.264 headers generation functions 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/log2.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "tw5864.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic u8 marker[] = { 0x00, 0x00, 0x00, 0x01 }; 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * Exponential-Golomb coding functions 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * These functions are used for generation of H.264 bitstream headers. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * This code is derived from tw5864 reference driver by manufacturers, which 208c2ecf20Sopenharmony_ci * itself apparently was derived from x264 project. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Bitstream writing context */ 248c2ecf20Sopenharmony_cistruct bs { 258c2ecf20Sopenharmony_ci u8 *buf; /* pointer to buffer beginning */ 268c2ecf20Sopenharmony_ci u8 *buf_end; /* pointer to buffer end */ 278c2ecf20Sopenharmony_ci u8 *ptr; /* pointer to current byte in buffer */ 288c2ecf20Sopenharmony_ci unsigned int bits_left; /* number of available bits in current byte */ 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic void bs_init(struct bs *s, void *buf, int size) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci s->buf = buf; 348c2ecf20Sopenharmony_ci s->ptr = buf; 358c2ecf20Sopenharmony_ci s->buf_end = s->ptr + size; 368c2ecf20Sopenharmony_ci s->bits_left = 8; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int bs_len(struct bs *s) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci return s->ptr - s->buf; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic void bs_write(struct bs *s, int count, u32 bits) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci if (s->ptr >= s->buf_end - 4) 478c2ecf20Sopenharmony_ci return; 488c2ecf20Sopenharmony_ci while (count > 0) { 498c2ecf20Sopenharmony_ci if (count < 32) 508c2ecf20Sopenharmony_ci bits &= (1 << count) - 1; 518c2ecf20Sopenharmony_ci if (count < s->bits_left) { 528c2ecf20Sopenharmony_ci *s->ptr = (*s->ptr << count) | bits; 538c2ecf20Sopenharmony_ci s->bits_left -= count; 548c2ecf20Sopenharmony_ci break; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci *s->ptr = (*s->ptr << s->bits_left) | 578c2ecf20Sopenharmony_ci (bits >> (count - s->bits_left)); 588c2ecf20Sopenharmony_ci count -= s->bits_left; 598c2ecf20Sopenharmony_ci s->ptr++; 608c2ecf20Sopenharmony_ci s->bits_left = 8; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void bs_write1(struct bs *s, u32 bit) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci if (s->ptr < s->buf_end) { 678c2ecf20Sopenharmony_ci *s->ptr <<= 1; 688c2ecf20Sopenharmony_ci *s->ptr |= bit; 698c2ecf20Sopenharmony_ci s->bits_left--; 708c2ecf20Sopenharmony_ci if (s->bits_left == 0) { 718c2ecf20Sopenharmony_ci s->ptr++; 728c2ecf20Sopenharmony_ci s->bits_left = 8; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void bs_write_ue(struct bs *s, u32 val) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci if (val == 0) { 808c2ecf20Sopenharmony_ci bs_write1(s, 1); 818c2ecf20Sopenharmony_ci } else { 828c2ecf20Sopenharmony_ci val++; 838c2ecf20Sopenharmony_ci bs_write(s, 2 * fls(val) - 1, val); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void bs_write_se(struct bs *s, int val) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci bs_write_ue(s, val <= 0 ? -val * 2 : val * 2 - 1); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic void bs_rbsp_trailing(struct bs *s) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci bs_write1(s, 1); 958c2ecf20Sopenharmony_ci if (s->bits_left != 8) 968c2ecf20Sopenharmony_ci bs_write(s, s->bits_left, 0x00); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* H.264 headers generation functions */ 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int tw5864_h264_gen_sps_rbsp(u8 *buf, size_t size, int width, int height) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct bs bs, *s; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci s = &bs; 1068c2ecf20Sopenharmony_ci bs_init(s, buf, size); 1078c2ecf20Sopenharmony_ci bs_write(s, 8, 0x42); /* profile_idc, baseline */ 1088c2ecf20Sopenharmony_ci bs_write(s, 1, 1); /* constraint_set0_flag */ 1098c2ecf20Sopenharmony_ci bs_write(s, 1, 1); /* constraint_set1_flag */ 1108c2ecf20Sopenharmony_ci bs_write(s, 1, 0); /* constraint_set2_flag */ 1118c2ecf20Sopenharmony_ci bs_write(s, 5, 0); /* reserved_zero_5bits */ 1128c2ecf20Sopenharmony_ci bs_write(s, 8, 0x1e); /* level_idc */ 1138c2ecf20Sopenharmony_ci bs_write_ue(s, 0); /* seq_parameter_set_id */ 1148c2ecf20Sopenharmony_ci bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4); /* log2_max_frame_num_minus4 */ 1158c2ecf20Sopenharmony_ci bs_write_ue(s, 0); /* pic_order_cnt_type */ 1168c2ecf20Sopenharmony_ci /* log2_max_pic_order_cnt_lsb_minus4 */ 1178c2ecf20Sopenharmony_ci bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4); 1188c2ecf20Sopenharmony_ci bs_write_ue(s, 1); /* num_ref_frames */ 1198c2ecf20Sopenharmony_ci bs_write(s, 1, 0); /* gaps_in_frame_num_value_allowed_flag */ 1208c2ecf20Sopenharmony_ci bs_write_ue(s, width / 16 - 1); /* pic_width_in_mbs_minus1 */ 1218c2ecf20Sopenharmony_ci bs_write_ue(s, height / 16 - 1); /* pic_height_in_map_units_minus1 */ 1228c2ecf20Sopenharmony_ci bs_write(s, 1, 1); /* frame_mbs_only_flag */ 1238c2ecf20Sopenharmony_ci bs_write(s, 1, 0); /* direct_8x8_inference_flag */ 1248c2ecf20Sopenharmony_ci bs_write(s, 1, 0); /* frame_cropping_flag */ 1258c2ecf20Sopenharmony_ci bs_write(s, 1, 0); /* vui_parameters_present_flag */ 1268c2ecf20Sopenharmony_ci bs_rbsp_trailing(s); 1278c2ecf20Sopenharmony_ci return bs_len(s); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int tw5864_h264_gen_pps_rbsp(u8 *buf, size_t size, int qp) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct bs bs, *s; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci s = &bs; 1358c2ecf20Sopenharmony_ci bs_init(s, buf, size); 1368c2ecf20Sopenharmony_ci bs_write_ue(s, 0); /* pic_parameter_set_id */ 1378c2ecf20Sopenharmony_ci bs_write_ue(s, 0); /* seq_parameter_set_id */ 1388c2ecf20Sopenharmony_ci bs_write(s, 1, 0); /* entropy_coding_mode_flag */ 1398c2ecf20Sopenharmony_ci bs_write(s, 1, 0); /* pic_order_present_flag */ 1408c2ecf20Sopenharmony_ci bs_write_ue(s, 0); /* num_slice_groups_minus1 */ 1418c2ecf20Sopenharmony_ci bs_write_ue(s, 0); /* i_num_ref_idx_l0_active_minus1 */ 1428c2ecf20Sopenharmony_ci bs_write_ue(s, 0); /* i_num_ref_idx_l1_active_minus1 */ 1438c2ecf20Sopenharmony_ci bs_write(s, 1, 0); /* weighted_pred_flag */ 1448c2ecf20Sopenharmony_ci bs_write(s, 2, 0); /* weighted_bipred_idc */ 1458c2ecf20Sopenharmony_ci bs_write_se(s, qp - 26); /* pic_init_qp_minus26 */ 1468c2ecf20Sopenharmony_ci bs_write_se(s, qp - 26); /* pic_init_qs_minus26 */ 1478c2ecf20Sopenharmony_ci bs_write_se(s, 0); /* chroma_qp_index_offset */ 1488c2ecf20Sopenharmony_ci bs_write(s, 1, 0); /* deblocking_filter_control_present_flag */ 1498c2ecf20Sopenharmony_ci bs_write(s, 1, 0); /* constrained_intra_pred_flag */ 1508c2ecf20Sopenharmony_ci bs_write(s, 1, 0); /* redundant_pic_cnt_present_flag */ 1518c2ecf20Sopenharmony_ci bs_rbsp_trailing(s); 1528c2ecf20Sopenharmony_ci return bs_len(s); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int tw5864_h264_gen_slice_head(u8 *buf, size_t size, 1568c2ecf20Sopenharmony_ci unsigned int idr_pic_id, 1578c2ecf20Sopenharmony_ci unsigned int frame_gop_seqno, 1588c2ecf20Sopenharmony_ci int *tail_nb_bits, u8 *tail) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct bs bs, *s; 1618c2ecf20Sopenharmony_ci int is_i_frame = frame_gop_seqno == 0; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci s = &bs; 1648c2ecf20Sopenharmony_ci bs_init(s, buf, size); 1658c2ecf20Sopenharmony_ci bs_write_ue(s, 0); /* first_mb_in_slice */ 1668c2ecf20Sopenharmony_ci bs_write_ue(s, is_i_frame ? 2 : 5); /* slice_type - I or P */ 1678c2ecf20Sopenharmony_ci bs_write_ue(s, 0); /* pic_parameter_set_id */ 1688c2ecf20Sopenharmony_ci bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno); /* frame_num */ 1698c2ecf20Sopenharmony_ci if (is_i_frame) 1708c2ecf20Sopenharmony_ci bs_write_ue(s, idr_pic_id); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* pic_order_cnt_lsb */ 1738c2ecf20Sopenharmony_ci bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (is_i_frame) { 1768c2ecf20Sopenharmony_ci bs_write1(s, 0); /* no_output_of_prior_pics_flag */ 1778c2ecf20Sopenharmony_ci bs_write1(s, 0); /* long_term_reference_flag */ 1788c2ecf20Sopenharmony_ci } else { 1798c2ecf20Sopenharmony_ci bs_write1(s, 0); /* num_ref_idx_active_override_flag */ 1808c2ecf20Sopenharmony_ci bs_write1(s, 0); /* ref_pic_list_reordering_flag_l0 */ 1818c2ecf20Sopenharmony_ci bs_write1(s, 0); /* adaptive_ref_pic_marking_mode_flag */ 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci bs_write_se(s, 0); /* slice_qp_delta */ 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (s->bits_left != 8) { 1878c2ecf20Sopenharmony_ci *tail = ((s->ptr[0]) << s->bits_left); 1888c2ecf20Sopenharmony_ci *tail_nb_bits = 8 - s->bits_left; 1898c2ecf20Sopenharmony_ci } else { 1908c2ecf20Sopenharmony_ci *tail = 0; 1918c2ecf20Sopenharmony_ci *tail_nb_bits = 0; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return bs_len(s); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_civoid tw5864_h264_put_stream_header(u8 **buf, size_t *space_left, int qp, 1988c2ecf20Sopenharmony_ci int width, int height) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci int nal_len; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* SPS */ 2038c2ecf20Sopenharmony_ci memcpy(*buf, marker, sizeof(marker)); 2048c2ecf20Sopenharmony_ci *buf += 4; 2058c2ecf20Sopenharmony_ci *space_left -= 4; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci **buf = 0x67; /* SPS NAL header */ 2088c2ecf20Sopenharmony_ci *buf += 1; 2098c2ecf20Sopenharmony_ci *space_left -= 1; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci nal_len = tw5864_h264_gen_sps_rbsp(*buf, *space_left, width, height); 2128c2ecf20Sopenharmony_ci *buf += nal_len; 2138c2ecf20Sopenharmony_ci *space_left -= nal_len; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* PPS */ 2168c2ecf20Sopenharmony_ci memcpy(*buf, marker, sizeof(marker)); 2178c2ecf20Sopenharmony_ci *buf += 4; 2188c2ecf20Sopenharmony_ci *space_left -= 4; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci **buf = 0x68; /* PPS NAL header */ 2218c2ecf20Sopenharmony_ci *buf += 1; 2228c2ecf20Sopenharmony_ci *space_left -= 1; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci nal_len = tw5864_h264_gen_pps_rbsp(*buf, *space_left, qp); 2258c2ecf20Sopenharmony_ci *buf += nal_len; 2268c2ecf20Sopenharmony_ci *space_left -= nal_len; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_civoid tw5864_h264_put_slice_header(u8 **buf, size_t *space_left, 2308c2ecf20Sopenharmony_ci unsigned int idr_pic_id, 2318c2ecf20Sopenharmony_ci unsigned int frame_gop_seqno, 2328c2ecf20Sopenharmony_ci int *tail_nb_bits, u8 *tail) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci int nal_len; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci memcpy(*buf, marker, sizeof(marker)); 2378c2ecf20Sopenharmony_ci *buf += 4; 2388c2ecf20Sopenharmony_ci *space_left -= 4; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Frame NAL header */ 2418c2ecf20Sopenharmony_ci **buf = (frame_gop_seqno == 0) ? 0x25 : 0x21; 2428c2ecf20Sopenharmony_ci *buf += 1; 2438c2ecf20Sopenharmony_ci *space_left -= 1; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci nal_len = tw5864_h264_gen_slice_head(*buf, *space_left, idr_pic_id, 2468c2ecf20Sopenharmony_ci frame_gop_seqno, tail_nb_bits, 2478c2ecf20Sopenharmony_ci tail); 2488c2ecf20Sopenharmony_ci *buf += nal_len; 2498c2ecf20Sopenharmony_ci *space_left -= nal_len; 2508c2ecf20Sopenharmony_ci} 251