mirror of
https://github.com/torvalds/linux.git
synced 2024-12-13 14:43:03 +00:00
c942fddf87
Based on 3 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version [author] [kishon] [vijay] [abraham] [i] [kishon]@[ti] [com] this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version [author] [graeme] [gregory] [gg]@[slimlogic] [co] [uk] [author] [kishon] [vijay] [abraham] [i] [kishon]@[ti] [com] [based] [on] [twl6030]_[usb] [c] [author] [hema] [hk] [hemahk]@[ti] [com] this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 1105 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Richard Fontana <rfontana@redhat.com> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070033.202006027@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
251 lines
6.3 KiB
C
251 lines
6.3 KiB
C
// 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[] = { 0x00, 0x00, 0x00, 0x01 };
|
|
|
|
/*
|
|
* 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, 0x00);
|
|
}
|
|
|
|
/* 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, 0x42); /* 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, 0x1e); /* 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 = 0x67; /* 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 = 0x68; /* 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) ? 0x25 : 0x21;
|
|
*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;
|
|
}
|