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

media: allegro: add support for HEVC encoding

The Allegro Codec supports HEVC encoding. The messages to the MCU are
the same for H.264 and HEVC, but some options have to be changed. These
are actually only a few options.

The driver, however, must add the HEVC VPS/SPS/PPS NAL Units to the
coded stream and must properly provide the HEVC format and controls to
user space.

[hverkuil: fix warning for wrong enum type (h264 instead of hevc)]
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+huawei@kernel.org>
parent 99b05ce7
......@@ -30,6 +30,7 @@
#include "allegro-mail.h"
#include "nal-h264.h"
#include "nal-hevc.h"
/*
* Support up to 4k video streams. The hardware actually supports higher
......@@ -209,6 +210,8 @@ struct allegro_channel {
bool enable_loop_filter_across_tiles;
bool enable_loop_filter_across_slices;
bool enable_deblocking_filter_override;
bool enable_reordering;
bool dbf_ovr_en;
unsigned int num_ref_idx_l0;
......@@ -235,6 +238,16 @@ struct allegro_channel {
struct v4l2_ctrl *mpeg_video_h264_min_qp;
struct v4l2_ctrl *mpeg_video_h264_p_frame_qp;
struct v4l2_ctrl *mpeg_video_h264_b_frame_qp;
struct v4l2_ctrl *mpeg_video_hevc_profile;
struct v4l2_ctrl *mpeg_video_hevc_level;
struct v4l2_ctrl *mpeg_video_hevc_tier;
struct v4l2_ctrl *mpeg_video_hevc_i_frame_qp;
struct v4l2_ctrl *mpeg_video_hevc_max_qp;
struct v4l2_ctrl *mpeg_video_hevc_min_qp;
struct v4l2_ctrl *mpeg_video_hevc_p_frame_qp;
struct v4l2_ctrl *mpeg_video_hevc_b_frame_qp;
struct v4l2_ctrl *mpeg_video_frame_rc_enable;
struct { /* video bitrate mode control cluster */
struct v4l2_ctrl *mpeg_video_bitrate_mode;
......@@ -267,30 +280,45 @@ struct allegro_channel {
static inline int
allegro_channel_get_i_frame_qp(struct allegro_channel *channel)
{
if (channel->codec == V4L2_PIX_FMT_HEVC)
return v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_i_frame_qp);
else
return v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_i_frame_qp);
}
static inline int
allegro_channel_get_p_frame_qp(struct allegro_channel *channel)
{
if (channel->codec == V4L2_PIX_FMT_HEVC)
return v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_p_frame_qp);
else
return v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_p_frame_qp);
}
static inline int
allegro_channel_get_b_frame_qp(struct allegro_channel *channel)
{
if (channel->codec == V4L2_PIX_FMT_HEVC)
return v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_b_frame_qp);
else
return v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_b_frame_qp);
}
static inline int
allegro_channel_get_min_qp(struct allegro_channel *channel)
{
if (channel->codec == V4L2_PIX_FMT_HEVC)
return v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_min_qp);
else
return v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_min_qp);
}
static inline int
allegro_channel_get_max_qp(struct allegro_channel *channel)
{
if (channel->codec == V4L2_PIX_FMT_HEVC)
return v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_max_qp);
else
return v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_max_qp);
}
......@@ -585,6 +613,86 @@ static unsigned int h264_maximum_cpb_size(enum v4l2_mpeg_video_h264_level level)
}
}
static enum v4l2_mpeg_video_hevc_level
select_minimum_hevc_level(unsigned int width, unsigned int height)
{
unsigned int luma_picture_size = width * height;
enum v4l2_mpeg_video_hevc_level level;
if (luma_picture_size <= 36864)
level = V4L2_MPEG_VIDEO_HEVC_LEVEL_1;
else if (luma_picture_size <= 122880)
level = V4L2_MPEG_VIDEO_HEVC_LEVEL_2;
else if (luma_picture_size <= 245760)
level = V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1;
else if (luma_picture_size <= 552960)
level = V4L2_MPEG_VIDEO_HEVC_LEVEL_3;
else if (luma_picture_size <= 983040)
level = V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1;
else if (luma_picture_size <= 2228224)
level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4;
else if (luma_picture_size <= 8912896)
level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5;
else
level = V4L2_MPEG_VIDEO_HEVC_LEVEL_6;
return level;
}
static unsigned int hevc_maximum_bitrate(enum v4l2_mpeg_video_hevc_level level)
{
/*
* See Rec. ITU-T H.265 v5 (02/2018), A.4.2 Profile-specific level
* limits for the video profiles.
*/
switch (level) {
case V4L2_MPEG_VIDEO_HEVC_LEVEL_1:
return 128;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_2:
return 1500;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1:
return 3000;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_3:
return 6000;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1:
return 10000;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_4:
return 12000;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1:
return 20000;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_5:
return 25000;
default:
case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1:
return 40000;
}
}
static unsigned int hevc_maximum_cpb_size(enum v4l2_mpeg_video_hevc_level level)
{
switch (level) {
case V4L2_MPEG_VIDEO_HEVC_LEVEL_1:
return 350;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_2:
return 1500;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1:
return 3000;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_3:
return 6000;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1:
return 10000;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_4:
return 12000;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1:
return 20000;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_5:
return 25000;
default:
case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1:
return 40000;
}
}
static const struct fw_info *
allegro_get_firmware_info(struct allegro_dev *dev,
const struct firmware *fw,
......@@ -908,6 +1016,55 @@ static u16 v4l2_level_to_mcu_level(enum v4l2_mpeg_video_h264_level level)
}
}
static u8 hevc_profile_to_mcu_profile(enum v4l2_mpeg_video_hevc_profile profile)
{
switch (profile) {
default:
case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN:
return 1;
case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10:
return 2;
case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE:
return 3;
}
}
static u16 hevc_level_to_mcu_level(enum v4l2_mpeg_video_hevc_level level)
{
switch (level) {
case V4L2_MPEG_VIDEO_HEVC_LEVEL_1:
return 10;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_2:
return 20;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1:
return 21;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_3:
return 30;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1:
return 31;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_4:
return 40;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1:
return 41;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_5:
return 50;
default:
case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1:
return 51;
}
}
static u8 hevc_tier_to_mcu_tier(enum v4l2_mpeg_video_hevc_tier tier)
{
switch (tier) {
default:
case V4L2_MPEG_VIDEO_HEVC_TIER_MAIN:
return 0;
case V4L2_MPEG_VIDEO_HEVC_TIER_HIGH:
return 1;
}
}
static u32
v4l2_bitrate_mode_to_mcu_mode(enum v4l2_mpeg_video_bitrate_mode mode)
{
......@@ -949,6 +1106,10 @@ static u32 allegro_channel_get_entropy_mode(struct allegro_channel *channel)
#define ALLEGRO_ENTROPY_MODE_CAVLC 0
#define ALLEGRO_ENTROPY_MODE_CABAC 1
/* HEVC always uses CABAC, but this has to be explicitly set */
if (channel->codec == V4L2_PIX_FMT_HEVC)
return ALLEGRO_ENTROPY_MODE_CABAC;
return ALLEGRO_ENTROPY_MODE_CAVLC;
}
......@@ -960,8 +1121,6 @@ static int fill_create_channel_param(struct allegro_channel *channel,
int b_frame_qp = allegro_channel_get_b_frame_qp(channel);
int bitrate_mode = v4l2_ctrl_g_ctrl(channel->mpeg_video_bitrate_mode);
unsigned int cpb_size = v4l2_ctrl_g_ctrl(channel->mpeg_video_cpb_size);
enum v4l2_mpeg_video_h264_profile profile;
enum v4l2_mpeg_video_h264_level level;
param->width = channel->width;
param->height = channel->height;
......@@ -971,17 +1130,37 @@ static int fill_create_channel_param(struct allegro_channel *channel,
param->src_mode = 0x0;
param->codec = channel->codec;
if (channel->codec == V4L2_PIX_FMT_H264) {
enum v4l2_mpeg_video_h264_profile profile;
enum v4l2_mpeg_video_h264_level level;
profile = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_profile);
level = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_level);
param->profile = v4l2_profile_to_mcu_profile(profile);
param->constraint_set_flags = BIT(1);
param->level = v4l2_level_to_mcu_level(level);
} else {
enum v4l2_mpeg_video_hevc_profile profile;
enum v4l2_mpeg_video_hevc_level level;
enum v4l2_mpeg_video_hevc_tier tier;
profile = v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_profile);
level = v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_level);
tier = v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_tier);
param->profile = hevc_profile_to_mcu_profile(profile);
param->level = hevc_level_to_mcu_level(level);
param->tier = hevc_tier_to_mcu_tier(tier);
}
param->log2_max_poc = LOG2_MAX_PIC_ORDER_CNT;
param->log2_max_frame_num = channel->log2_max_frame_num;
param->temporal_mvp_enable = channel->temporal_mvp_enable;
param->dbf_ovr_en = channel->dbf_ovr_en;
param->override_lf = channel->enable_deblocking_filter_override;
param->enable_reordering = channel->enable_reordering;
param->entropy_mode = allegro_channel_get_entropy_mode(channel);
param->rdo_cost_mode = 1;
param->custom_lda = 1;
......@@ -1454,6 +1633,158 @@ static void allegro_channel_eos_event(struct allegro_channel *channel)
v4l2_event_queue_fh(&channel->fh, &eos_event);
}
static ssize_t allegro_hevc_write_vps(struct allegro_channel *channel,
void *dest, size_t n)
{
struct allegro_dev *dev = channel->dev;
struct nal_hevc_vps *vps;
struct nal_hevc_profile_tier_level *ptl;
ssize_t size;
unsigned int num_ref_frames = channel->num_ref_idx_l0;
s32 profile = v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_profile);
s32 level = v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_level);
s32 tier = v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_tier);
vps = kzalloc(sizeof(*vps), GFP_KERNEL);
if (!vps)
return -ENOMEM;
vps->base_layer_internal_flag = 1;
vps->base_layer_available_flag = 1;
vps->temporal_id_nesting_flag = 1;
ptl = &vps->profile_tier_level;
ptl->general_profile_idc = nal_hevc_profile_from_v4l2(profile);
ptl->general_profile_compatibility_flag[ptl->general_profile_idc] = 1;
ptl->general_tier_flag = nal_hevc_tier_from_v4l2(tier);
ptl->general_progressive_source_flag = 1;
ptl->general_frame_only_constraint_flag = 1;
ptl->general_level_idc = nal_hevc_level_from_v4l2(level);
vps->sub_layer_ordering_info_present_flag = 0;
vps->max_dec_pic_buffering_minus1[0] = num_ref_frames;
vps->max_num_reorder_pics[0] = num_ref_frames;
size = nal_hevc_write_vps(&dev->plat_dev->dev, dest, n, vps);
kfree(vps);
return size;
}
static ssize_t allegro_hevc_write_sps(struct allegro_channel *channel,
void *dest, size_t n)
{
struct allegro_dev *dev = channel->dev;
struct nal_hevc_sps *sps;
struct nal_hevc_profile_tier_level *ptl;
ssize_t size;
unsigned int num_ref_frames = channel->num_ref_idx_l0;
s32 profile = v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_profile);
s32 level = v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_level);
s32 tier = v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_tier);
sps = kzalloc(sizeof(*sps), GFP_KERNEL);
if (!sps)
return -ENOMEM;
sps->temporal_id_nesting_flag = 1;
ptl = &sps->profile_tier_level;
ptl->general_profile_idc = nal_hevc_profile_from_v4l2(profile);
ptl->general_profile_compatibility_flag[ptl->general_profile_idc] = 1;
ptl->general_tier_flag = nal_hevc_tier_from_v4l2(tier);
ptl->general_progressive_source_flag = 1;
ptl->general_frame_only_constraint_flag = 1;
ptl->general_level_idc = nal_hevc_level_from_v4l2(level);
sps->seq_parameter_set_id = 0;
sps->chroma_format_idc = 1; /* Only 4:2:0 sampling supported */
sps->pic_width_in_luma_samples = round_up(channel->width, 8);
sps->pic_height_in_luma_samples = round_up(channel->height, 8);
sps->conf_win_right_offset =
sps->pic_width_in_luma_samples - channel->width;
sps->conf_win_bottom_offset =
sps->pic_height_in_luma_samples - channel->height;
sps->conformance_window_flag =
sps->conf_win_right_offset || sps->conf_win_bottom_offset;
sps->log2_max_pic_order_cnt_lsb_minus4 = LOG2_MAX_PIC_ORDER_CNT - 4;
sps->sub_layer_ordering_info_present_flag = 1;
sps->max_dec_pic_buffering_minus1[0] = num_ref_frames;
sps->max_num_reorder_pics[0] = num_ref_frames;
sps->log2_min_luma_coding_block_size_minus3 =
channel->min_cu_size - 3;
sps->log2_diff_max_min_luma_coding_block_size =
channel->max_cu_size - channel->min_cu_size;
sps->log2_min_luma_transform_block_size_minus2 =
channel->min_tu_size - 2;
sps->log2_diff_max_min_luma_transform_block_size =
channel->max_tu_size - channel->min_tu_size;
sps->max_transform_hierarchy_depth_intra =
channel->max_transfo_depth_intra;
sps->max_transform_hierarchy_depth_inter =
channel->max_transfo_depth_inter;
sps->sps_temporal_mvp_enabled_flag = channel->temporal_mvp_enable;
sps->strong_intra_smoothing_enabled_flag = channel->max_cu_size > 4;
size = nal_hevc_write_sps(&dev->plat_dev->dev, dest, n, sps);
kfree(sps);
return size;
}
static ssize_t allegro_hevc_write_pps(struct allegro_channel *channel,
struct mcu_msg_encode_frame_response *msg,
void *dest, size_t n)
{
struct allegro_dev *dev = channel->dev;
struct nal_hevc_pps *pps;
ssize_t size;
int i;
pps = kzalloc(sizeof(*pps), GFP_KERNEL);
if (!pps)
return -ENOMEM;
pps->pps_pic_parameter_set_id = 0;
pps->pps_seq_parameter_set_id = 0;
if (msg->num_column > 1 || msg->num_row > 1) {
pps->tiles_enabled_flag = 1;
pps->num_tile_columns_minus1 = msg->num_column - 1;
pps->num_tile_rows_minus1 = msg->num_row - 1;
for (i = 0; i < msg->num_column; i++)
pps->column_width_minus1[i] = msg->tile_width[i] - 1;
for (i = 0; i < msg->num_row; i++)
pps->row_height_minus1[i] = msg->tile_height[i] - 1;
}
pps->loop_filter_across_tiles_enabled_flag =
channel->enable_loop_filter_across_tiles;
pps->pps_loop_filter_across_slices_enabled_flag =
channel->enable_loop_filter_across_slices;
pps->deblocking_filter_control_present_flag = 1;
pps->deblocking_filter_override_enabled_flag =
channel->enable_deblocking_filter_override;
pps->pps_beta_offset_div2 = BETA_OFFSET_DIV_2;
pps->pps_tc_offset_div2 = TC_OFFSET_DIV_2;
pps->lists_modification_present_flag = channel->enable_reordering;
size = nal_hevc_write_pps(&dev->plat_dev->dev, dest, n, pps);
kfree(pps);
return size;
}
static u64 allegro_put_buffer(struct allegro_channel *channel,
struct list_head *list,
struct vb2_v4l2_buffer *buffer)
......@@ -1577,8 +1908,27 @@ static void allegro_channel_finish_frame(struct allegro_channel *channel,
curr = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
free = partition->offset;
if (channel->codec == V4L2_PIX_FMT_HEVC && msg->is_idr) {
len = allegro_hevc_write_vps(channel, curr, free);
if (len < 0) {
v4l2_err(&dev->v4l2_dev,
"not enough space for video parameter set: %zd left\n",
free);
goto err;
}
curr += len;
free -= len;
v4l2_dbg(1, debug, &dev->v4l2_dev,
"channel %d: wrote %zd byte VPS nal unit\n",
channel->mcu_channel_id, len);
}
if (msg->is_idr) {
if (channel->codec == V4L2_PIX_FMT_H264)
len = allegro_h264_write_sps(channel, curr, free);
else
len = allegro_hevc_write_sps(channel, curr, free);
if (len < 0) {
v4l2_err(&dev->v4l2_dev,
"not enough space for sequence parameter set: %zd left\n",
......@@ -1593,7 +1943,10 @@ static void allegro_channel_finish_frame(struct allegro_channel *channel,
}
if (msg->slice_type == AL_ENC_SLICE_TYPE_I) {
if (channel->codec == V4L2_PIX_FMT_H264)
len = allegro_h264_write_pps(channel, curr, free);
else
len = allegro_hevc_write_pps(channel, msg, curr, free);
if (len < 0) {
v4l2_err(&dev->v4l2_dev,
"not enough space for picture parameter set: %zd left\n",
......@@ -1611,7 +1964,10 @@ static void allegro_channel_finish_frame(struct allegro_channel *channel,
dst_buf->vb2_buf.planes[0].data_offset = free;
free = 0;
} else {
if (channel->codec == V4L2_PIX_FMT_H264)
len = nal_h264_write_filler(&dev->plat_dev->dev, curr, free);
else
len = nal_hevc_write_filler(&dev->plat_dev->dev, curr, free);
if (len < 0) {
v4l2_err(&dev->v4l2_dev,
"failed to write %zd filler data\n", free);
......@@ -2011,6 +2367,16 @@ static void allegro_destroy_channel(struct allegro_channel *channel)
v4l2_ctrl_grab(channel->mpeg_video_h264_min_qp, false);
v4l2_ctrl_grab(channel->mpeg_video_h264_p_frame_qp, false);
v4l2_ctrl_grab(channel->mpeg_video_h264_b_frame_qp, false);
v4l2_ctrl_grab(channel->mpeg_video_hevc_profile, false);
v4l2_ctrl_grab(channel->mpeg_video_hevc_level, false);
v4l2_ctrl_grab(channel->mpeg_video_hevc_tier, false);
v4l2_ctrl_grab(channel->mpeg_video_hevc_i_frame_qp, false);
v4l2_ctrl_grab(channel->mpeg_video_hevc_max_qp, false);
v4l2_ctrl_grab(channel->mpeg_video_hevc_min_qp, false);
v4l2_ctrl_grab(channel->mpeg_video_hevc_p_frame_qp, false);
v4l2_ctrl_grab(channel->mpeg_video_hevc_b_frame_qp, false);
v4l2_ctrl_grab(channel->mpeg_video_frame_rc_enable, false);
v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, false);
v4l2_ctrl_grab(channel->mpeg_video_bitrate, false);
......@@ -2067,6 +2433,16 @@ static int allegro_create_channel(struct allegro_channel *channel)
v4l2_ctrl_grab(channel->mpeg_video_h264_min_qp, true);
v4l2_ctrl_grab(channel->mpeg_video_h264_p_frame_qp, true);
v4l2_ctrl_grab(channel->mpeg_video_h264_b_frame_qp, true);
v4l2_ctrl_grab(channel->mpeg_video_hevc_profile, true);
v4l2_ctrl_grab(channel->mpeg_video_hevc_level, true);
v4l2_ctrl_grab(channel->mpeg_video_hevc_tier, true);
v4l2_ctrl_grab(channel->mpeg_video_hevc_i_frame_qp, true);
v4l2_ctrl_grab(channel->mpeg_video_hevc_max_qp, true);
v4l2_ctrl_grab(channel->mpeg_video_hevc_min_qp, true);
v4l2_ctrl_grab(channel->mpeg_video_hevc_p_frame_qp, true);
v4l2_ctrl_grab(channel->mpeg_video_hevc_b_frame_qp, true);
v4l2_ctrl_grab(channel->mpeg_video_frame_rc_enable, true);
v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, true);
v4l2_ctrl_grab(channel->mpeg_video_bitrate, true);
......@@ -2113,8 +2489,13 @@ static void allegro_channel_adjust(struct allegro_channel *channel)
channel->sizeimage_encoded =
estimate_stream_size(channel->width, channel->height);
if (codec == V4L2_PIX_FMT_H264) {
ctrl = channel->mpeg_video_h264_level;
min = select_minimum_h264_level(channel->width, channel->height);
} else {
ctrl = channel->mpeg_video_hevc_level;
min = select_minimum_hevc_level(channel->width, channel->height);
}
if (ctrl->minimum > min)
v4l2_dbg(1, debug, &dev->v4l2_dev,
"%s.minimum: %lld -> %lld\n",
......@@ -2125,7 +2506,10 @@ static void allegro_channel_adjust(struct allegro_channel *channel)
v4l2_ctrl_unlock(ctrl);
ctrl = channel->mpeg_video_bitrate;
if (codec == V4L2_PIX_FMT_H264)
max = h264_maximum_bitrate(v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_level));
else
max = hevc_maximum_bitrate(v4l2_ctrl_g_ctrl(channel->mpeg_video_hevc_level));
if (ctrl->maximum < max)
v4l2_dbg(1, debug, &dev->v4l2_dev,
"%s: maximum: %lld -> %lld\n",
......@@ -2156,13 +2540,33 @@ static void allegro_channel_adjust(struct allegro_channel *channel)
v4l2_ctrl_activate(channel->mpeg_video_h264_b_frame_qp,
codec == V4L2_PIX_FMT_H264);
v4l2_ctrl_activate(channel->mpeg_video_hevc_profile,
codec == V4L2_PIX_FMT_HEVC);
v4l2_ctrl_activate(channel->mpeg_video_hevc_level,
codec == V4L2_PIX_FMT_HEVC);
v4l2_ctrl_activate(channel->mpeg_video_hevc_tier,
codec == V4L2_PIX_FMT_HEVC);
v4l2_ctrl_activate(channel->mpeg_video_hevc_i_frame_qp,
codec == V4L2_PIX_FMT_HEVC);
v4l2_ctrl_activate(channel->mpeg_video_hevc_max_qp,
codec == V4L2_PIX_FMT_HEVC);
v4l2_ctrl_activate(channel->mpeg_video_hevc_min_qp,
codec == V4L2_PIX_FMT_HEVC);
v4l2_ctrl_activate(channel->mpeg_video_hevc_p_frame_qp,
codec == V4L2_PIX_FMT_HEVC);
v4l2_ctrl_activate(channel->mpeg_video_hevc_b_frame_qp,
codec == V4L2_PIX_FMT_HEVC);
if (codec == V4L2_PIX_FMT_H264)
channel->log2_max_frame_num = LOG2_MAX_FRAME_NUM;
channel->temporal_mvp_enable = true;
channel->dbf_ovr_en = true;
channel->dbf_ovr_en = (codec == V4L2_PIX_FMT_H264);
channel->enable_deblocking_filter_override = (codec == V4L2_PIX_FMT_HEVC);
channel->enable_reordering = (codec == V4L2_PIX_FMT_HEVC);
channel->enable_loop_filter_across_tiles = true;
channel->enable_loop_filter_across_slices = true;
if (codec == V4L2_PIX_FMT_H264) {
channel->b_hrz_me_range = 8;
channel->b_vrt_me_range = 8;
channel->p_hrz_me_range = 16;
......@@ -2171,6 +2575,16 @@ static void allegro_channel_adjust(struct allegro_channel *channel)
channel->min_cu_size = ilog2(8);
channel->max_tu_size = ilog2(4);
channel->min_tu_size = ilog2(4);
} else {
channel->b_hrz_me_range = 16;
channel->b_vrt_me_range = 16;
channel->p_hrz_me_range = 32;
channel->p_vrt_me_range = 32;
channel->max_cu_size = ilog2(32);
channel->min_cu_size = ilog2(8);
channel->max_tu_size = ilog2(32);
channel->min_tu_size = ilog2(4);
}
channel->max_transfo_depth_intra = 1;
channel->max_transfo_depth_inter = 1;
}
......@@ -2525,6 +2939,51 @@ static int allegro_open(struct file *file)
&allegro_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
0, 51, 1, 30);
channel->mpeg_video_hevc_profile =
v4l2_ctrl_new_std_menu(handler,
&allegro_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, 0x0,
V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN);
channel->mpeg_video_hevc_level =
v4l2_ctrl_new_std_menu(handler,
&allegro_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, 0x0,
V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1);
channel->mpeg_video_hevc_tier =
v4l2_ctrl_new_std_menu(handler,
&allegro_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_TIER,
V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, 0x0,
V4L2_MPEG_VIDEO_HEVC_TIER_MAIN);
channel->mpeg_video_hevc_i_frame_qp =
v4l2_ctrl_new_std(handler,
&allegro_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
0, 51, 1, 30);
channel->mpeg_video_hevc_max_qp =
v4l2_ctrl_new_std(handler,
&allegro_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
0, 51, 1, 51);
channel->mpeg_video_hevc_min_qp =
v4l2_ctrl_new_std(handler,
&allegro_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
0, 51, 1, 0);
channel->mpeg_video_hevc_p_frame_qp =
v4l2_ctrl_new_std(handler,
&allegro_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
0, 51, 1, 30);
channel->mpeg_video_hevc_b_frame_qp =
v4l2_ctrl_new_std(handler,
&allegro_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
0, 51, 1, 30);
channel->mpeg_video_frame_rc_enable =
v4l2_ctrl_new_std(handler,
&allegro_ctrl_ops,
......@@ -2537,10 +2996,17 @@ static int allegro_open(struct file *file)
V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
if (channel->codec == V4L2_PIX_FMT_H264) {
bitrate_max = h264_maximum_bitrate(V4L2_MPEG_VIDEO_H264_LEVEL_5_1);
bitrate_def = h264_maximum_bitrate(V4L2_MPEG_VIDEO_H264_LEVEL_5_1);
cpb_size_max = h264_maximum_cpb_size(V4L2_MPEG_VIDEO_H264_LEVEL_5_1);
cpb_size_def = h264_maximum_cpb_size(V4L2_MPEG_VIDEO_H264_LEVEL_5_1);
} else {
bitrate_max = hevc_maximum_bitrate(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1);
bitrate_def = hevc_maximum_bitrate(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1);
cpb_size_max = hevc_maximum_cpb_size(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1);
cpb_size_def = hevc_maximum_cpb_size(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1);
}
channel->mpeg_video_bitrate = v4l2_ctrl_new_std(handler,
&allegro_ctrl_ops,
V4L2_CID_MPEG_VIDEO_BITRATE,
......@@ -2644,9 +3110,12 @@ static int allegro_enum_fmt_vid(struct file *file, void *fh,
f->pixelformat = V4L2_PIX_FMT_NV12;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (f->index >= 1)
if (f->index >= 2)
return -EINVAL;
if (f->index == 0)
f->pixelformat = V4L2_PIX_FMT_H264;
if (f->index == 1)
f->pixelformat = V4L2_PIX_FMT_HEVC;
break;
default:
return -EINVAL;
......@@ -2685,7 +3154,10 @@ static int allegro_try_fmt_vid_cap(struct file *file, void *fh,
f->fmt.pix.height = clamp_t(__u32, f->fmt.pix.height,
ALLEGRO_HEIGHT_MIN, ALLEGRO_HEIGHT_MAX);
if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_HEVC &&
f->fmt.pix.pixelformat != V4L2_PIX_FMT_H264)
f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage =
estimate_stream_size(f->fmt.pix.width, f->fmt.pix.height);
......@@ -2832,6 +3304,7 @@ static int allegro_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
switch (fsize->pixel_format) {
case V4L2_PIX_FMT_HEVC:
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_NV12:
break;
......
......@@ -67,12 +67,16 @@ static inline u32 settings_get_mcu_codec(struct create_channel_param *param)
if (version < MCU_MSG_VERSION_2019_2) {
switch (pixelformat) {
case V4L2_PIX_FMT_HEVC:
return 2;
case V4L2_PIX_FMT_H264:
default:
return 1;
}
} else {
switch (pixelformat) {
case V4L2_PIX_FMT_HEVC:
return 1;
case V4L2_PIX_FMT_H264:
default:
return 0;
......@@ -117,7 +121,9 @@ allegro_encode_config_blob(u32 *dst, struct create_channel_param *param)
dst[i++] = val;
val = 0;
val |= param->enable_reordering ? BIT(0) : 0;
val |= param->dbf_ovr_en ? BIT(2) : 0;
val |= param->override_lf ? BIT(12) : 0;
dst[i++] = val;
if (version >= MCU_MSG_VERSION_2019_2) {
......
......@@ -65,6 +65,7 @@ struct create_channel_param {
u32 temporal_mvp_enable;
u32 enable_reordering;
u32 dbf_ovr_en;
u32 override_lf;
u32 num_ref_idx_l0;
u32 num_ref_idx_l1;
u32 custom_lda;
......
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