media: allegro: add support for HEVC encoding
authorMichael Tretter <m.tretter@pengutronix.de>
Thu, 3 Dec 2020 11:01:06 +0000 (12:01 +0100)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Wed, 27 Jan 2021 15:15:04 +0000 (16:15 +0100)
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: Michael Tretter <m.tretter@pengutronix.de>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/platform/allegro-dvt/allegro-core.c
drivers/media/platform/allegro-dvt/allegro-mail.c
drivers/media/platform/allegro-dvt/allegro-mail.h

index f3a656ab2b06a6c6492722c674bbab4fafc78ef3..887b492e4ad1c6d4e23881dfdc1a437b92092b27 100644 (file)
@@ -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,31 +280,46 @@ struct allegro_channel {
 static inline int
 allegro_channel_get_i_frame_qp(struct allegro_channel *channel)
 {
-       return v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_i_frame_qp);
+       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)
 {
-       return v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_p_frame_qp);
+       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)
 {
-       return v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_b_frame_qp);
+       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)
 {
-       return v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_min_qp);
+       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)
 {
-       return v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_max_qp);
+       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);
 }
 
 struct allegro_m2m_buffer {
@@ -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;
-       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);
+       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) {
-               len = allegro_h264_write_sps(channel, curr, free);
+               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) {
-               len = allegro_h264_write_pps(channel, curr, free);
+               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 {
-               len = nal_h264_write_filler(&dev->plat_dev->dev, curr, free);
+               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);
 
-       ctrl = channel->mpeg_video_h264_level;
-       min = select_minimum_h264_level(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;
-       max = h264_maximum_bitrate(v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_level));
+       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,21 +2540,51 @@ static void allegro_channel_adjust(struct allegro_channel *channel)
        v4l2_ctrl_activate(channel->mpeg_video_h264_b_frame_qp,
                           codec == V4L2_PIX_FMT_H264);
 
-       channel->log2_max_frame_num = LOG2_MAX_FRAME_NUM;
+       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;
 
-       channel->b_hrz_me_range = 8;
-       channel->b_vrt_me_range = 8;
-       channel->p_hrz_me_range = 16;
-       channel->p_vrt_me_range = 16;
-       channel->max_cu_size = ilog2(16);
-       channel->min_cu_size = ilog2(8);
-       channel->max_tu_size = ilog2(4);
-       channel->min_tu_size = ilog2(4);
+       if (codec == V4L2_PIX_FMT_H264) {
+               channel->b_hrz_me_range = 8;
+               channel->b_vrt_me_range = 8;
+               channel->p_hrz_me_range = 16;
+               channel->p_vrt_me_range = 16;
+               channel->max_cu_size = ilog2(16);
+               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);
 
-       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);
+       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;
-               f->pixelformat = V4L2_PIX_FMT_H264;
+               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);
 
-       f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
+       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;
index 5dbc1c029020c30822bf14acdb1c03f10314fca3..7e08c5050f2e2a31f502b5366518f6f41d0b06a6 100644 (file)
@@ -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) {
index f7485cf78c4f537cdc1b3561c98974a0939ee030..2c7bc509eac3d6961e5993e9cb9926c76f027888 100644 (file)
@@ -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;