Commit 878344de authored by Michael Tretter's avatar Michael Tretter Committed by Mauro Carvalho Chehab

media: allegro: add SPS/PPS nal unit writer

The allegro hardware encoder does not write SPS/PPS nal units into the
encoded video stream. Therefore, we need to write the units in software.

The implementation follows Rec. ITU-T H.264 (04/2017) to allow to
convert between a C struct and the RBSP representation of the SPS and
PPS nal units.

The allegro driver writes the nal units into the v4l2 capture buffer in
front of the actual video data which is written at an offset by the IP
core. The remaining gap is filled with a filler nal unit.

[hverkuil-cisco@xs4all.nl: added missing @dev description for nal_h264_read_sps()]
[mchehab+samsung@kernel.org: removed uneeded "-ccflags-y $(src)" from Makefile]
Signed-off-by: default avatarMichael Tretter <m.tretter@pengutronix.de>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent f20387df
# SPDX-License-Identifier: GPL-2.0
allegro-objs := allegro-core.o
allegro-objs := allegro-core.o nal-h264.o
obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro.o
......@@ -26,6 +26,8 @@
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-v4l2.h>
#include "nal-h264.h"
/*
* Support up to 4k video streams. The hardware actually supports higher
* resolutions, which are specified in PG252 June 6, 2018 (H.264/H.265 Video
......@@ -1301,6 +1303,131 @@ static int allocate_reference_buffers(struct allegro_channel *channel,
n, PAGE_ALIGN(size));
}
static ssize_t allegro_h264_write_sps(struct allegro_channel *channel,
void *dest, size_t n)
{
struct allegro_dev *dev = channel->dev;
struct nal_h264_sps *sps;
ssize_t size;
unsigned int size_mb = SIZE_MACROBLOCK;
/* Calculation of crop units in Rec. ITU-T H.264 (04/2017) p. 76 */
unsigned int crop_unit_x = 2;
unsigned int crop_unit_y = 2;
sps = kzalloc(sizeof(*sps), GFP_KERNEL);
if (!sps)
return -ENOMEM;
sps->profile_idc = nal_h264_profile_from_v4l2(channel->profile);
sps->constraint_set0_flag = 0;
sps->constraint_set1_flag = 1;
sps->constraint_set2_flag = 0;
sps->constraint_set3_flag = 0;
sps->constraint_set4_flag = 0;
sps->constraint_set5_flag = 0;
sps->level_idc = nal_h264_level_from_v4l2(channel->level);
sps->seq_parameter_set_id = 0;
sps->log2_max_frame_num_minus4 = 0;
sps->pic_order_cnt_type = 0;
sps->log2_max_pic_order_cnt_lsb_minus4 = 6;
sps->max_num_ref_frames = 3;
sps->gaps_in_frame_num_value_allowed_flag = 0;
sps->pic_width_in_mbs_minus1 =
DIV_ROUND_UP(channel->width, size_mb) - 1;
sps->pic_height_in_map_units_minus1 =
DIV_ROUND_UP(channel->height, size_mb) - 1;
sps->frame_mbs_only_flag = 1;
sps->mb_adaptive_frame_field_flag = 0;
sps->direct_8x8_inference_flag = 1;
sps->frame_cropping_flag =
(channel->width % size_mb) || (channel->height % size_mb);
if (sps->frame_cropping_flag) {
sps->crop_left = 0;
sps->crop_right = (round_up(channel->width, size_mb) - channel->width) / crop_unit_x;
sps->crop_top = 0;
sps->crop_bottom = (round_up(channel->height, size_mb) - channel->height) / crop_unit_y;
}
sps->vui_parameters_present_flag = 1;
sps->vui.aspect_ratio_info_present_flag = 0;
sps->vui.overscan_info_present_flag = 0;
sps->vui.video_signal_type_present_flag = 1;
sps->vui.video_format = 1;
sps->vui.video_full_range_flag = 0;
sps->vui.colour_description_present_flag = 1;
sps->vui.colour_primaries = 5;
sps->vui.transfer_characteristics = 5;
sps->vui.matrix_coefficients = 5;
sps->vui.chroma_loc_info_present_flag = 1;
sps->vui.chroma_sample_loc_type_top_field = 0;
sps->vui.chroma_sample_loc_type_bottom_field = 0;
sps->vui.timing_info_present_flag = 1;
sps->vui.num_units_in_tick = 1;
sps->vui.time_scale = 50;
sps->vui.fixed_frame_rate_flag = 1;
sps->vui.nal_hrd_parameters_present_flag = 0;
sps->vui.vcl_hrd_parameters_present_flag = 1;
sps->vui.vcl_hrd_parameters.cpb_cnt_minus1 = 0;
sps->vui.vcl_hrd_parameters.bit_rate_scale = 0;
sps->vui.vcl_hrd_parameters.cpb_size_scale = 1;
/* See Rec. ITU-T H.264 (04/2017) p. 410 E-53 */
sps->vui.vcl_hrd_parameters.bit_rate_value_minus1[0] =
channel->bitrate_peak / (1 << (6 + sps->vui.vcl_hrd_parameters.bit_rate_scale)) - 1;
/* See Rec. ITU-T H.264 (04/2017) p. 410 E-54 */
sps->vui.vcl_hrd_parameters.cpb_size_value_minus1[0] =
(channel->cpb_size * 1000) / (1 << (4 + sps->vui.vcl_hrd_parameters.cpb_size_scale)) - 1;
sps->vui.vcl_hrd_parameters.cbr_flag[0] = 1;
sps->vui.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 = 31;
sps->vui.vcl_hrd_parameters.cpb_removal_delay_length_minus1 = 31;
sps->vui.vcl_hrd_parameters.dpb_output_delay_length_minus1 = 31;
sps->vui.vcl_hrd_parameters.time_offset_length = 0;
sps->vui.low_delay_hrd_flag = 0;
sps->vui.pic_struct_present_flag = 1;
sps->vui.bitstream_restriction_flag = 0;
size = nal_h264_write_sps(&dev->plat_dev->dev, dest, n, sps);
kfree(sps);
return size;
}
static ssize_t allegro_h264_write_pps(struct allegro_channel *channel,
void *dest, size_t n)
{
struct allegro_dev *dev = channel->dev;
struct nal_h264_pps *pps;
ssize_t size;
pps = kzalloc(sizeof(*pps), GFP_KERNEL);
if (!pps)
return -ENOMEM;
pps->pic_parameter_set_id = 0;
pps->seq_parameter_set_id = 0;
pps->entropy_coding_mode_flag = 0;
pps->bottom_field_pic_order_in_frame_present_flag = 0;
pps->num_slice_groups_minus1 = 0;
pps->num_ref_idx_l0_default_active_minus1 = 2;
pps->num_ref_idx_l1_default_active_minus1 = 2;
pps->weighted_pred_flag = 0;
pps->weighted_bipred_idc = 0;
pps->pic_init_qp_minus26 = 0;
pps->pic_init_qs_minus26 = 0;
pps->chroma_qp_index_offset = 0;
pps->deblocking_filter_control_present_flag = 1;
pps->constrained_intra_pred_flag = 0;
pps->redundant_pic_cnt_present_flag = 0;
pps->transform_8x8_mode_flag = 0;
pps->pic_scaling_matrix_present_flag = 0;
pps->second_chroma_qp_index_offset = 0;
size = nal_h264_write_pps(&dev->plat_dev->dev, dest, n, pps);
kfree(pps);
return size;
}
static bool allegro_channel_is_at_eos(struct allegro_channel *channel)
{
bool is_at_eos = false;
......@@ -1350,6 +1477,9 @@ static void allegro_channel_finish_frame(struct allegro_channel *channel,
u32 size;
} *partition;
enum vb2_buffer_state state = VB2_BUF_STATE_ERROR;
char *curr;
ssize_t len;
ssize_t free;
src_buf = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx);
......@@ -1400,6 +1530,57 @@ static void allegro_channel_finish_frame(struct allegro_channel *channel,
vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
partition->offset + partition->size);
curr = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
free = partition->offset;
if (msg->is_idr) {
len = allegro_h264_write_sps(channel, curr, free);
if (len < 0) {
v4l2_err(&dev->v4l2_dev,
"not enough space for sequence parameter set: %zd left\n",
free);
goto err;
}
curr += len;
free -= len;
v4l2_dbg(1, debug, &dev->v4l2_dev,
"channel %d: wrote %zd byte SPS nal unit\n",
channel->mcu_channel_id, len);
}
if (msg->slice_type == AL_ENC_SLICE_TYPE_I) {
len = allegro_h264_write_pps(channel, curr, free);
if (len < 0) {
v4l2_err(&dev->v4l2_dev,
"not enough space for picture parameter set: %zd left\n",
free);
goto err;
}
curr += len;
free -= len;
v4l2_dbg(1, debug, &dev->v4l2_dev,
"channel %d: wrote %zd byte PPS nal unit\n",
channel->mcu_channel_id, len);
}
len = nal_h264_write_filler(&dev->plat_dev->dev, curr, free);
if (len < 0) {
v4l2_err(&dev->v4l2_dev,
"failed to write %zd filler data\n", free);
goto err;
}
curr += len;
free -= len;
v4l2_dbg(2, debug, &dev->v4l2_dev,
"channel %d: wrote %zd bytes filler nal unit\n",
channel->mcu_channel_id, len);
if (free != 0) {
v4l2_err(&dev->v4l2_dev,
"non-VCL NAL units do not fill space until VCL NAL unit: %zd bytes left\n",
free);
goto err;
}
state = VB2_BUF_STATE_DONE;
v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
*
* Convert NAL units between raw byte sequence payloads (RBSP) and C structs.
*/
#ifndef __NAL_H264_H__
#define __NAL_H264_H__
#include <linux/kernel.h>
#include <linux/types.h>
/**
* struct nal_h264_hdr_parameters - HDR parameters
*
* C struct representation of the sequence parameter set NAL unit as defined by
* Rec. ITU-T H.264 (04/2017) E.1.2 HRD parameters syntax.
*/
struct nal_h264_hrd_parameters {
unsigned int cpb_cnt_minus1;
unsigned int bit_rate_scale;
unsigned int cpb_size_scale;
struct {
int bit_rate_value_minus1[16];
int cpb_size_value_minus1[16];
unsigned int cbr_flag[16];
};
unsigned int initial_cpb_removal_delay_length_minus1;
unsigned int cpb_removal_delay_length_minus1;
unsigned int dpb_output_delay_length_minus1;
unsigned int time_offset_length;
};
/**
* struct nal_h264_vui_parameters - VUI parameters
*
* C struct representation of the VUI parameters as defined by Rec. ITU-T
* H.264 (04/2017) E.1.1 VUI parameters syntax.
*/
struct nal_h264_vui_parameters {
unsigned int aspect_ratio_info_present_flag;
struct {
unsigned int aspect_ratio_idc;
unsigned int sar_width;
unsigned int sar_height;
};
unsigned int overscan_info_present_flag;
unsigned int overscan_appropriate_flag;
unsigned int video_signal_type_present_flag;
struct {
unsigned int video_format;
unsigned int video_full_range_flag;
unsigned int colour_description_present_flag;
struct {
unsigned int colour_primaries;
unsigned int transfer_characteristics;
unsigned int matrix_coefficients;
};
};
unsigned int chroma_loc_info_present_flag;
struct {
unsigned int chroma_sample_loc_type_top_field;
unsigned int chroma_sample_loc_type_bottom_field;
};
unsigned int timing_info_present_flag;
struct {
unsigned int num_units_in_tick;
unsigned int time_scale;
unsigned int fixed_frame_rate_flag;
};
unsigned int nal_hrd_parameters_present_flag;
struct nal_h264_hrd_parameters nal_hrd_parameters;
unsigned int vcl_hrd_parameters_present_flag;
struct nal_h264_hrd_parameters vcl_hrd_parameters;
unsigned int low_delay_hrd_flag;
unsigned int pic_struct_present_flag;
unsigned int bitstream_restriction_flag;
struct {
unsigned int motion_vectors_over_pic_boundaries_flag;
unsigned int max_bytes_per_pic_denom;
unsigned int max_bits_per_mb_denom;
unsigned int log2_max_mv_length_horizontal;
unsigned int log21_max_mv_length_vertical;
unsigned int max_num_reorder_frames;
unsigned int max_dec_frame_buffering;
};
};
/**
* struct nal_h264_sps - Sequence parameter set
*
* C struct representation of the sequence parameter set NAL unit as defined by
* Rec. ITU-T H.264 (04/2017) 7.3.2.1.1 Sequence parameter set data syntax.
*/
struct nal_h264_sps {
unsigned int profile_idc;
unsigned int constraint_set0_flag;
unsigned int constraint_set1_flag;
unsigned int constraint_set2_flag;
unsigned int constraint_set3_flag;
unsigned int constraint_set4_flag;
unsigned int constraint_set5_flag;
unsigned int reserved_zero_2bits;
unsigned int level_idc;
unsigned int seq_parameter_set_id;
struct {
unsigned int chroma_format_idc;
unsigned int separate_colour_plane_flag;
unsigned int bit_depth_luma_minus8;
unsigned int bit_depth_chroma_minus8;
unsigned int qpprime_y_zero_transform_bypass_flag;
unsigned int seq_scaling_matrix_present_flag;
};
unsigned int log2_max_frame_num_minus4;
unsigned int pic_order_cnt_type;
union {
unsigned int log2_max_pic_order_cnt_lsb_minus4;
struct {
unsigned int delta_pic_order_always_zero_flag;
int offset_for_non_ref_pic;
int offset_for_top_to_bottom_field;
unsigned int num_ref_frames_in_pic_order_cnt_cycle;
int offset_for_ref_frame[255];
};
};
unsigned int max_num_ref_frames;
unsigned int gaps_in_frame_num_value_allowed_flag;
unsigned int pic_width_in_mbs_minus1;
unsigned int pic_height_in_map_units_minus1;
unsigned int frame_mbs_only_flag;
unsigned int mb_adaptive_frame_field_flag;
unsigned int direct_8x8_inference_flag;
unsigned int frame_cropping_flag;
struct {
unsigned int crop_left;
unsigned int crop_right;
unsigned int crop_top;
unsigned int crop_bottom;
};
unsigned int vui_parameters_present_flag;
struct nal_h264_vui_parameters vui;
};
/**
* struct nal_h264_pps - Picture parameter set
*
* C struct representation of the picture parameter set NAL unit as defined by
* Rec. ITU-T H.264 (04/2017) 7.3.2.2 Picture parameter set RBSP syntax.
*/
struct nal_h264_pps {
unsigned int pic_parameter_set_id;
unsigned int seq_parameter_set_id;
unsigned int entropy_coding_mode_flag;
unsigned int bottom_field_pic_order_in_frame_present_flag;
unsigned int num_slice_groups_minus1;
unsigned int slice_group_map_type;
union {
unsigned int run_length_minus1[8];
struct {
unsigned int top_left[8];
unsigned int bottom_right[8];
};
struct {
unsigned int slice_group_change_direction_flag;
unsigned int slice_group_change_rate_minus1;
};
struct {
unsigned int pic_size_in_map_units_minus1;
unsigned int slice_group_id[8];
};
};
unsigned int num_ref_idx_l0_default_active_minus1;
unsigned int num_ref_idx_l1_default_active_minus1;
unsigned int weighted_pred_flag;
unsigned int weighted_bipred_idc;
int pic_init_qp_minus26;
int pic_init_qs_minus26;
int chroma_qp_index_offset;
unsigned int deblocking_filter_control_present_flag;
unsigned int constrained_intra_pred_flag;
unsigned int redundant_pic_cnt_present_flag;
struct {
unsigned int transform_8x8_mode_flag;
unsigned int pic_scaling_matrix_present_flag;
int second_chroma_qp_index_offset;
};
};
int nal_h264_profile_from_v4l2(enum v4l2_mpeg_video_h264_profile profile);
int nal_h264_level_from_v4l2(enum v4l2_mpeg_video_h264_level level);
ssize_t nal_h264_write_sps(const struct device *dev,
void *dest, size_t n, struct nal_h264_sps *sps);
ssize_t nal_h264_read_sps(const struct device *dev,
struct nal_h264_sps *sps, void *src, size_t n);
void nal_h264_print_sps(const struct device *dev, struct nal_h264_sps *sps);
ssize_t nal_h264_write_pps(const struct device *dev,
void *dest, size_t n, struct nal_h264_pps *pps);
ssize_t nal_h264_read_pps(const struct device *dev,
struct nal_h264_pps *pps, void *src, size_t n);
void nal_h264_print_pps(const struct device *dev, struct nal_h264_pps *pps);
ssize_t nal_h264_write_filler(const struct device *dev, void *dest, size_t n);
ssize_t nal_h264_read_filler(const struct device *dev, void *src, size_t n);
#endif /* __NAL_H264_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment