Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  TW5864 driver - H.264 headers generation functions
0004  *
0005  *  Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com>
0006  */
0007 
0008 #include <linux/log2.h>
0009 
0010 #include "tw5864.h"
0011 
0012 static u8 marker[] = { 0x00, 0x00, 0x00, 0x01 };
0013 
0014 /*
0015  * Exponential-Golomb coding functions
0016  *
0017  * These functions are used for generation of H.264 bitstream headers.
0018  *
0019  * This code is derived from tw5864 reference driver by manufacturers, which
0020  * itself apparently was derived from x264 project.
0021  */
0022 
0023 /* Bitstream writing context */
0024 struct bs {
0025     u8 *buf; /* pointer to buffer beginning */
0026     u8 *buf_end; /* pointer to buffer end */
0027     u8 *ptr; /* pointer to current byte in buffer */
0028     unsigned int bits_left; /* number of available bits in current byte */
0029 };
0030 
0031 static void bs_init(struct bs *s, void *buf, int size)
0032 {
0033     s->buf = buf;
0034     s->ptr = buf;
0035     s->buf_end = s->ptr + size;
0036     s->bits_left = 8;
0037 }
0038 
0039 static int bs_len(struct bs *s)
0040 {
0041     return s->ptr - s->buf;
0042 }
0043 
0044 static void bs_write(struct bs *s, int count, u32 bits)
0045 {
0046     if (s->ptr >= s->buf_end - 4)
0047         return;
0048     while (count > 0) {
0049         if (count < 32)
0050             bits &= (1 << count) - 1;
0051         if (count < s->bits_left) {
0052             *s->ptr = (*s->ptr << count) | bits;
0053             s->bits_left -= count;
0054             break;
0055         }
0056         *s->ptr = (*s->ptr << s->bits_left) |
0057             (bits >> (count - s->bits_left));
0058         count -= s->bits_left;
0059         s->ptr++;
0060         s->bits_left = 8;
0061     }
0062 }
0063 
0064 static void bs_write1(struct bs *s, u32 bit)
0065 {
0066     if (s->ptr < s->buf_end) {
0067         *s->ptr <<= 1;
0068         *s->ptr |= bit;
0069         s->bits_left--;
0070         if (s->bits_left == 0) {
0071             s->ptr++;
0072             s->bits_left = 8;
0073         }
0074     }
0075 }
0076 
0077 static void bs_write_ue(struct bs *s, u32 val)
0078 {
0079     if (val == 0) {
0080         bs_write1(s, 1);
0081     } else {
0082         val++;
0083         bs_write(s, 2 * fls(val) - 1, val);
0084     }
0085 }
0086 
0087 static void bs_write_se(struct bs *s, int val)
0088 {
0089     bs_write_ue(s, val <= 0 ? -val * 2 : val * 2 - 1);
0090 }
0091 
0092 static void bs_rbsp_trailing(struct bs *s)
0093 {
0094     bs_write1(s, 1);
0095     if (s->bits_left != 8)
0096         bs_write(s, s->bits_left, 0x00);
0097 }
0098 
0099 /* H.264 headers generation functions */
0100 
0101 static int tw5864_h264_gen_sps_rbsp(u8 *buf, size_t size, int width, int height)
0102 {
0103     struct bs bs, *s;
0104 
0105     s = &bs;
0106     bs_init(s, buf, size);
0107     bs_write(s, 8, 0x42); /* profile_idc, baseline */
0108     bs_write(s, 1, 1); /* constraint_set0_flag */
0109     bs_write(s, 1, 1); /* constraint_set1_flag */
0110     bs_write(s, 1, 0); /* constraint_set2_flag */
0111     bs_write(s, 5, 0); /* reserved_zero_5bits */
0112     bs_write(s, 8, 0x1e); /* level_idc */
0113     bs_write_ue(s, 0); /* seq_parameter_set_id */
0114     bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4); /* log2_max_frame_num_minus4 */
0115     bs_write_ue(s, 0); /* pic_order_cnt_type */
0116     /* log2_max_pic_order_cnt_lsb_minus4 */
0117     bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4);
0118     bs_write_ue(s, 1); /* num_ref_frames */
0119     bs_write(s, 1, 0); /* gaps_in_frame_num_value_allowed_flag */
0120     bs_write_ue(s, width / 16 - 1); /* pic_width_in_mbs_minus1 */
0121     bs_write_ue(s, height / 16 - 1); /* pic_height_in_map_units_minus1 */
0122     bs_write(s, 1, 1); /* frame_mbs_only_flag */
0123     bs_write(s, 1, 0); /* direct_8x8_inference_flag */
0124     bs_write(s, 1, 0); /* frame_cropping_flag */
0125     bs_write(s, 1, 0); /* vui_parameters_present_flag */
0126     bs_rbsp_trailing(s);
0127     return bs_len(s);
0128 }
0129 
0130 static int tw5864_h264_gen_pps_rbsp(u8 *buf, size_t size, int qp)
0131 {
0132     struct bs bs, *s;
0133 
0134     s = &bs;
0135     bs_init(s, buf, size);
0136     bs_write_ue(s, 0); /* pic_parameter_set_id */
0137     bs_write_ue(s, 0); /* seq_parameter_set_id */
0138     bs_write(s, 1, 0); /* entropy_coding_mode_flag */
0139     bs_write(s, 1, 0); /* pic_order_present_flag */
0140     bs_write_ue(s, 0); /* num_slice_groups_minus1 */
0141     bs_write_ue(s, 0); /* i_num_ref_idx_l0_active_minus1 */
0142     bs_write_ue(s, 0); /* i_num_ref_idx_l1_active_minus1 */
0143     bs_write(s, 1, 0); /* weighted_pred_flag */
0144     bs_write(s, 2, 0); /* weighted_bipred_idc */
0145     bs_write_se(s, qp - 26); /* pic_init_qp_minus26 */
0146     bs_write_se(s, qp - 26); /* pic_init_qs_minus26 */
0147     bs_write_se(s, 0); /* chroma_qp_index_offset */
0148     bs_write(s, 1, 0); /* deblocking_filter_control_present_flag */
0149     bs_write(s, 1, 0); /* constrained_intra_pred_flag */
0150     bs_write(s, 1, 0); /* redundant_pic_cnt_present_flag */
0151     bs_rbsp_trailing(s);
0152     return bs_len(s);
0153 }
0154 
0155 static int tw5864_h264_gen_slice_head(u8 *buf, size_t size,
0156                       unsigned int idr_pic_id,
0157                       unsigned int frame_gop_seqno,
0158                       int *tail_nb_bits, u8 *tail)
0159 {
0160     struct bs bs, *s;
0161     int is_i_frame = frame_gop_seqno == 0;
0162 
0163     s = &bs;
0164     bs_init(s, buf, size);
0165     bs_write_ue(s, 0); /* first_mb_in_slice */
0166     bs_write_ue(s, is_i_frame ? 2 : 5); /* slice_type - I or P */
0167     bs_write_ue(s, 0); /* pic_parameter_set_id */
0168     bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno); /* frame_num */
0169     if (is_i_frame)
0170         bs_write_ue(s, idr_pic_id);
0171 
0172     /* pic_order_cnt_lsb */
0173     bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno);
0174 
0175     if (is_i_frame) {
0176         bs_write1(s, 0); /* no_output_of_prior_pics_flag */
0177         bs_write1(s, 0); /* long_term_reference_flag */
0178     } else {
0179         bs_write1(s, 0); /* num_ref_idx_active_override_flag */
0180         bs_write1(s, 0); /* ref_pic_list_reordering_flag_l0 */
0181         bs_write1(s, 0); /* adaptive_ref_pic_marking_mode_flag */
0182     }
0183 
0184     bs_write_se(s, 0); /* slice_qp_delta */
0185 
0186     if (s->bits_left != 8) {
0187         *tail = ((s->ptr[0]) << s->bits_left);
0188         *tail_nb_bits = 8 - s->bits_left;
0189     } else {
0190         *tail = 0;
0191         *tail_nb_bits = 0;
0192     }
0193 
0194     return bs_len(s);
0195 }
0196 
0197 void tw5864_h264_put_stream_header(u8 **buf, size_t *space_left, int qp,
0198                    int width, int height)
0199 {
0200     int nal_len;
0201 
0202     /* SPS */
0203     memcpy(*buf, marker, sizeof(marker));
0204     *buf += 4;
0205     *space_left -= 4;
0206 
0207     **buf = 0x67; /* SPS NAL header */
0208     *buf += 1;
0209     *space_left -= 1;
0210 
0211     nal_len = tw5864_h264_gen_sps_rbsp(*buf, *space_left, width, height);
0212     *buf += nal_len;
0213     *space_left -= nal_len;
0214 
0215     /* PPS */
0216     memcpy(*buf, marker, sizeof(marker));
0217     *buf += 4;
0218     *space_left -= 4;
0219 
0220     **buf = 0x68; /* PPS NAL header */
0221     *buf += 1;
0222     *space_left -= 1;
0223 
0224     nal_len = tw5864_h264_gen_pps_rbsp(*buf, *space_left, qp);
0225     *buf += nal_len;
0226     *space_left -= nal_len;
0227 }
0228 
0229 void tw5864_h264_put_slice_header(u8 **buf, size_t *space_left,
0230                   unsigned int idr_pic_id,
0231                   unsigned int frame_gop_seqno,
0232                   int *tail_nb_bits, u8 *tail)
0233 {
0234     int nal_len;
0235 
0236     memcpy(*buf, marker, sizeof(marker));
0237     *buf += 4;
0238     *space_left -= 4;
0239 
0240     /* Frame NAL header */
0241     **buf = (frame_gop_seqno == 0) ? 0x25 : 0x21;
0242     *buf += 1;
0243     *space_left -= 1;
0244 
0245     nal_len = tw5864_h264_gen_slice_head(*buf, *space_left, idr_pic_id,
0246                          frame_gop_seqno, tail_nb_bits,
0247                          tail);
0248     *buf += nal_len;
0249     *space_left -= nal_len;
0250 }