// SPDX-License-Identifier: GPL-2.0-or-later
/*
* TW5864 driver - H.264 headers generation functions
*
* Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com>
*/
#include <linux/log2.h>
#include "tw5864.h"
static u8 marker[] = { 0 x00, 0 x00, 0 x00, 0 x01 };
/*
* Exponential-Golomb coding functions
*
* These functions are used for generation of H.264 bitstream headers.
*
* This code is derived from tw5864 reference driver by manufacturers, which
* itself apparently was derived from x264 project.
*/
/* Bitstream writing context */
struct bs {
u8 *buf; /* pointer to buffer beginning */
u8 *buf_end; /* pointer to buffer end */
u8 *ptr; /* pointer to current byte in buffer */
unsigned int bits_left; /* number of available bits in current byte */
};
static void bs_init(struct bs *s, void *buf, int size)
{
s->buf = buf;
s->ptr = buf;
s->buf_end = s->ptr + size;
s->bits_left = 8 ;
}
static int bs_len(struct bs *s)
{
return s->ptr - s->buf;
}
static void bs_write(struct bs *s, int count, u32 bits)
{
if (s->ptr >= s->buf_end - 4 )
return ;
while (count > 0 ) {
if (count < 32 )
bits &= (1 << count) - 1 ;
if (count < s->bits_left) {
*s->ptr = (*s->ptr << count) | bits;
s->bits_left -= count;
break ;
}
*s->ptr = (*s->ptr << s->bits_left) |
(bits >> (count - s->bits_left));
count -= s->bits_left;
s->ptr++;
s->bits_left = 8 ;
}
}
static void bs_write1(struct bs *s, u32 bit)
{
if (s->ptr < s->buf_end) {
*s->ptr <<= 1 ;
*s->ptr |= bit;
s->bits_left--;
if (s->bits_left == 0 ) {
s->ptr++;
s->bits_left = 8 ;
}
}
}
static void bs_write_ue(struct bs *s, u32 val)
{
if (val == 0 ) {
bs_write1(s, 1 );
} else {
val++;
bs_write(s, 2 * fls(val) - 1 , val);
}
}
static void bs_write_se(struct bs *s, int val)
{
bs_write_ue(s, val <= 0 ? -val * 2 : val * 2 - 1 );
}
static void bs_rbsp_trailing(struct bs *s)
{
bs_write1(s, 1 );
if (s->bits_left != 8 )
bs_write(s, s->bits_left, 0 x00);
}
/* H.264 headers generation functions */
static int tw5864_h264_gen_sps_rbsp(u8 *buf, size_t size, int width, int height)
{
struct bs bs, *s;
s = &bs;
bs_init(s, buf, size);
bs_write(s, 8 , 0 x42); /* profile_idc, baseline */
bs_write(s, 1 , 1 ); /* constraint_set0_flag */
bs_write(s, 1 , 1 ); /* constraint_set1_flag */
bs_write(s, 1 , 0 ); /* constraint_set2_flag */
bs_write(s, 5 , 0 ); /* reserved_zero_5bits */
bs_write(s, 8 , 0 x1e); /* level_idc */
bs_write_ue(s, 0 ); /* seq_parameter_set_id */
bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4 ); /* log2_max_frame_num_minus4 */
bs_write_ue(s, 0 ); /* pic_order_cnt_type */
/* log2_max_pic_order_cnt_lsb_minus4 */
bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4 );
bs_write_ue(s, 1 ); /* num_ref_frames */
bs_write(s, 1 , 0 ); /* gaps_in_frame_num_value_allowed_flag */
bs_write_ue(s, width / 16 - 1 ); /* pic_width_in_mbs_minus1 */
bs_write_ue(s, height / 16 - 1 ); /* pic_height_in_map_units_minus1 */
bs_write(s, 1 , 1 ); /* frame_mbs_only_flag */
bs_write(s, 1 , 0 ); /* direct_8x8_inference_flag */
bs_write(s, 1 , 0 ); /* frame_cropping_flag */
bs_write(s, 1 , 0 ); /* vui_parameters_present_flag */
bs_rbsp_trailing(s);
return bs_len(s);
}
static int tw5864_h264_gen_pps_rbsp(u8 *buf, size_t size, int qp)
{
struct bs bs, *s;
s = &bs;
bs_init(s, buf, size);
bs_write_ue(s, 0 ); /* pic_parameter_set_id */
bs_write_ue(s, 0 ); /* seq_parameter_set_id */
bs_write(s, 1 , 0 ); /* entropy_coding_mode_flag */
bs_write(s, 1 , 0 ); /* pic_order_present_flag */
bs_write_ue(s, 0 ); /* num_slice_groups_minus1 */
bs_write_ue(s, 0 ); /* i_num_ref_idx_l0_active_minus1 */
bs_write_ue(s, 0 ); /* i_num_ref_idx_l1_active_minus1 */
bs_write(s, 1 , 0 ); /* weighted_pred_flag */
bs_write(s, 2 , 0 ); /* weighted_bipred_idc */
bs_write_se(s, qp - 26 ); /* pic_init_qp_minus26 */
bs_write_se(s, qp - 26 ); /* pic_init_qs_minus26 */
bs_write_se(s, 0 ); /* chroma_qp_index_offset */
bs_write(s, 1 , 0 ); /* deblocking_filter_control_present_flag */
bs_write(s, 1 , 0 ); /* constrained_intra_pred_flag */
bs_write(s, 1 , 0 ); /* redundant_pic_cnt_present_flag */
bs_rbsp_trailing(s);
return bs_len(s);
}
static int tw5864_h264_gen_slice_head(u8 *buf, size_t size,
unsigned int idr_pic_id,
unsigned int frame_gop_seqno,
int *tail_nb_bits, u8 *tail)
{
struct bs bs, *s;
int is_i_frame = frame_gop_seqno == 0 ;
s = &bs;
bs_init(s, buf, size);
bs_write_ue(s, 0 ); /* first_mb_in_slice */
bs_write_ue(s, is_i_frame ? 2 : 5 ); /* slice_type - I or P */
bs_write_ue(s, 0 ); /* pic_parameter_set_id */
bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno); /* frame_num */
if (is_i_frame)
bs_write_ue(s, idr_pic_id);
/* pic_order_cnt_lsb */
bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno);
if (is_i_frame) {
bs_write1(s, 0 ); /* no_output_of_prior_pics_flag */
bs_write1(s, 0 ); /* long_term_reference_flag */
} else {
bs_write1(s, 0 ); /* num_ref_idx_active_override_flag */
bs_write1(s, 0 ); /* ref_pic_list_reordering_flag_l0 */
bs_write1(s, 0 ); /* adaptive_ref_pic_marking_mode_flag */
}
bs_write_se(s, 0 ); /* slice_qp_delta */
if (s->bits_left != 8 ) {
*tail = ((s->ptr[0 ]) << s->bits_left);
*tail_nb_bits = 8 - s->bits_left;
} else {
*tail = 0 ;
*tail_nb_bits = 0 ;
}
return bs_len(s);
}
void tw5864_h264_put_stream_header(u8 **buf, size_t *space_left, int qp,
int width, int height)
{
int nal_len;
/* SPS */
memcpy(*buf, marker, sizeof (marker));
*buf += 4 ;
*space_left -= 4 ;
**buf = 0 x67; /* SPS NAL header */
*buf += 1 ;
*space_left -= 1 ;
nal_len = tw5864_h264_gen_sps_rbsp(*buf, *space_left, width, height);
*buf += nal_len;
*space_left -= nal_len;
/* PPS */
memcpy(*buf, marker, sizeof (marker));
*buf += 4 ;
*space_left -= 4 ;
**buf = 0 x68; /* PPS NAL header */
*buf += 1 ;
*space_left -= 1 ;
nal_len = tw5864_h264_gen_pps_rbsp(*buf, *space_left, qp);
*buf += nal_len;
*space_left -= nal_len;
}
void tw5864_h264_put_slice_header(u8 **buf, size_t *space_left,
unsigned int idr_pic_id,
unsigned int frame_gop_seqno,
int *tail_nb_bits, u8 *tail)
{
int nal_len;
memcpy(*buf, marker, sizeof (marker));
*buf += 4 ;
*space_left -= 4 ;
/* Frame NAL header */
**buf = (frame_gop_seqno == 0 ) ? 0 x25 : 0 x21;
*buf += 1 ;
*space_left -= 1 ;
nal_len = tw5864_h264_gen_slice_head(*buf, *space_left, idr_pic_id,
frame_gop_seqno, tail_nb_bits,
tail);
*buf += nal_len;
*space_left -= nal_len;
}
Messung V0.5 in Prozent C=96 H=92 G=93
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland