root/drivers/media/pci/tw5864/tw5864-h264.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bs_init
  2. bs_len
  3. bs_write
  4. bs_write1
  5. bs_write_ue
  6. bs_write_se
  7. bs_rbsp_trailing
  8. tw5864_h264_gen_sps_rbsp
  9. tw5864_h264_gen_pps_rbsp
  10. tw5864_h264_gen_slice_head
  11. tw5864_h264_put_stream_header
  12. tw5864_h264_put_slice_header

   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 }

/* [<][>][^][v][top][bottom][index][help] */