media: amphion: Add H264 and HEVC profile and level control

For format H264 and HEVC, the firmware can report the parsed profile idc
and level idc to driver, these information may be useful.
Implement the H264 and HEVC profile and level control to report them.

Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
This commit is contained in:
Ming Qian 2025-05-12 10:01:36 +08:00 committed by Hans Verkuil
parent 642b70d526
commit ba4452b0c0
5 changed files with 205 additions and 1 deletions

View File

@ -232,6 +232,35 @@ static int vdec_ctrl_init(struct vpu_inst *inst)
V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE,
0, 1, 1, 0);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL,
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
V4L2_MPEG_VIDEO_H264_PROFILE_MAIN);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL,
V4L2_CID_MPEG_VIDEO_H264_LEVEL,
V4L2_MPEG_VIDEO_H264_LEVEL_6_2,
0,
V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL,
V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
~((1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) |
(1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10)),
V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL,
V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
0,
V4L2_MPEG_VIDEO_HEVC_LEVEL_4);
ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 2);
if (ctrl)
@ -1166,6 +1195,35 @@ static void vdec_clear_slots(struct vpu_inst *inst)
}
}
static void vdec_update_v4l2_ctrl(struct vpu_inst *inst, u32 id, u32 val)
{
struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&inst->ctrl_handler, id);
if (ctrl)
v4l2_ctrl_s_ctrl(ctrl, val);
}
static void vdec_update_v4l2_profile_level(struct vpu_inst *inst, struct vpu_dec_codec_info *hdr)
{
switch (inst->out_format.pixfmt) {
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_H264_MVC:
vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_PROFILE,
vpu_get_h264_v4l2_profile(hdr));
vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_LEVEL,
vpu_get_h264_v4l2_level(hdr));
break;
case V4L2_PIX_FMT_HEVC:
vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
vpu_get_hevc_v4l2_profile(hdr));
vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
vpu_get_hevc_v4l2_level(hdr));
break;
default:
return;
}
}
static void vdec_event_seq_hdr(struct vpu_inst *inst, struct vpu_dec_codec_info *hdr)
{
struct vdec_t *vdec = inst->priv;
@ -1189,6 +1247,7 @@ static void vdec_event_seq_hdr(struct vpu_inst *inst, struct vpu_dec_codec_info
vdec_init_crop(inst);
vdec_init_mbi(inst);
vdec_init_dcp(inst);
vdec_update_v4l2_profile_level(inst, hdr);
if (!vdec->seq_hdr_found) {
vdec->seq_tag = vdec->codec_info.tag;
if (vdec->is_source_changed) {

View File

@ -134,6 +134,7 @@ struct vpu_dec_codec_info {
u32 decoded_height;
struct v4l2_fract frame_rate;
u32 dsp_asp_ratio;
u32 profile_idc;
u32 level_idc;
u32 bit_depth_luma;
u32 bit_depth_chroma;
@ -147,6 +148,17 @@ struct vpu_dec_codec_info {
u32 mbi_size;
u32 dcp_size;
u32 stride;
union {
struct {
u32 constraint_set5_flag : 1;
u32 constraint_set4_flag : 1;
u32 constraint_set3_flag : 1;
u32 constraint_set2_flag : 1;
u32 constraint_set1_flag : 1;
u32 constraint_set0_flag : 1;
};
u32 constraint_set_flags;
};
};
struct vpu_dec_pic_info {

View File

@ -509,3 +509,126 @@ const char *vpu_codec_state_name(enum vpu_codec_state state)
}
return "<unknown>";
}
struct codec_id_mapping {
u32 id;
u32 v4l2_id;
};
static struct codec_id_mapping h264_profiles[] = {
{66, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE},
{77, V4L2_MPEG_VIDEO_H264_PROFILE_MAIN},
{88, V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED},
{100, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH}
};
static struct codec_id_mapping h264_levels[] = {
{10, V4L2_MPEG_VIDEO_H264_LEVEL_1_0},
{9, V4L2_MPEG_VIDEO_H264_LEVEL_1B},
{11, V4L2_MPEG_VIDEO_H264_LEVEL_1_1},
{12, V4L2_MPEG_VIDEO_H264_LEVEL_1_2},
{13, V4L2_MPEG_VIDEO_H264_LEVEL_1_3},
{20, V4L2_MPEG_VIDEO_H264_LEVEL_2_0},
{21, V4L2_MPEG_VIDEO_H264_LEVEL_2_1},
{22, V4L2_MPEG_VIDEO_H264_LEVEL_2_2},
{30, V4L2_MPEG_VIDEO_H264_LEVEL_3_0},
{31, V4L2_MPEG_VIDEO_H264_LEVEL_3_1},
{32, V4L2_MPEG_VIDEO_H264_LEVEL_3_2},
{40, V4L2_MPEG_VIDEO_H264_LEVEL_4_0},
{41, V4L2_MPEG_VIDEO_H264_LEVEL_4_1},
{42, V4L2_MPEG_VIDEO_H264_LEVEL_4_2},
{50, V4L2_MPEG_VIDEO_H264_LEVEL_5_0},
{51, V4L2_MPEG_VIDEO_H264_LEVEL_5_1},
{52, V4L2_MPEG_VIDEO_H264_LEVEL_5_2},
{60, V4L2_MPEG_VIDEO_H264_LEVEL_6_0},
{61, V4L2_MPEG_VIDEO_H264_LEVEL_6_1},
{62, V4L2_MPEG_VIDEO_H264_LEVEL_6_2}
};
static struct codec_id_mapping hevc_profiles[] = {
{1, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN},
{2, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10}
};
static struct codec_id_mapping hevc_levels[] = {
{30, V4L2_MPEG_VIDEO_HEVC_LEVEL_1},
{60, V4L2_MPEG_VIDEO_HEVC_LEVEL_2},
{63, V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1},
{90, V4L2_MPEG_VIDEO_HEVC_LEVEL_3},
{93, V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1},
{120, V4L2_MPEG_VIDEO_HEVC_LEVEL_4},
{123, V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1},
{150, V4L2_MPEG_VIDEO_HEVC_LEVEL_5},
{153, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1},
{156, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2},
{180, V4L2_MPEG_VIDEO_HEVC_LEVEL_6},
{183, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1},
{186, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2}
};
static u32 vpu_find_v4l2_id(u32 id, struct codec_id_mapping *array, u32 array_sz)
{
u32 i;
if (!array || !array_sz)
return 0;
for (i = 0; i < array_sz; i++) {
if (id == array[i].id)
return array[i].v4l2_id;
}
return 0;
}
u32 vpu_get_h264_v4l2_profile(struct vpu_dec_codec_info *hdr)
{
if (!hdr)
return 0;
/*
* In H.264 Document section A.2.1.1 Constrained Baseline profile
* Conformance of a bitstream to the Constrained Baseline profile is indicated by
* profile_idc being equal to 66 with constraint_set1_flag being equal to 1.
*/
if (hdr->profile_idc == 66 && hdr->constraint_set1_flag)
return V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE;
return vpu_find_v4l2_id(hdr->profile_idc, h264_profiles, ARRAY_SIZE(h264_profiles));
}
u32 vpu_get_h264_v4l2_level(struct vpu_dec_codec_info *hdr)
{
if (!hdr)
return 0;
/*
* In H.264 Document section 7.4.2.1.1 Sequence parameter set data semantics
* If profile_idc is equal to 66, 77, or 88 and level_idc is equal to 11,
* constraint_set3_flag equal to 1 indicates that the coded video sequence
* obeys all constraints specified in Annex A for level 1b
* and constraint_set3_flag equal to 0 indicates that the coded video sequence
* obeys all constraints specified in Annex A for level 1.1.
*/
if (hdr->level_idc == 11 && hdr->constraint_set3_flag &&
(hdr->profile_idc == 66 || hdr->profile_idc == 77 || hdr->profile_idc == 88))
return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
return vpu_find_v4l2_id(hdr->level_idc, h264_levels, ARRAY_SIZE(h264_levels));
}
u32 vpu_get_hevc_v4l2_profile(struct vpu_dec_codec_info *hdr)
{
if (!hdr)
return 0;
return vpu_find_v4l2_id(hdr->profile_idc, hevc_profiles, ARRAY_SIZE(hevc_profiles));
}
u32 vpu_get_hevc_v4l2_level(struct vpu_dec_codec_info *hdr)
{
if (!hdr)
return 0;
return vpu_find_v4l2_id(hdr->level_idc, hevc_levels, ARRAY_SIZE(hevc_levels));
}

View File

@ -6,6 +6,8 @@
#ifndef _AMPHION_VPU_HELPERS_H
#define _AMPHION_VPU_HELPERS_H
#include "vpu_defs.h"
struct vpu_pair {
u32 src;
u32 dst;
@ -65,4 +67,9 @@ u32 vpu_color_cvrt_full_range_i2v(u32 full_range);
int vpu_find_dst_by_src(struct vpu_pair *pairs, u32 cnt, u32 src);
int vpu_find_src_by_dst(struct vpu_pair *pairs, u32 cnt, u32 dst);
u32 vpu_get_h264_v4l2_profile(struct vpu_dec_codec_info *hdr);
u32 vpu_get_h264_v4l2_level(struct vpu_dec_codec_info *hdr);
u32 vpu_get_hevc_v4l2_profile(struct vpu_dec_codec_info *hdr);
u32 vpu_get_hevc_v4l2_level(struct vpu_dec_codec_info *hdr);
#endif

View File

@ -908,7 +908,8 @@ static void vpu_malone_unpack_seq_hdr(struct vpu_rpc_event *pkt,
info->frame_rate.numerator = 1000;
info->frame_rate.denominator = pkt->data[8];
info->dsp_asp_ratio = pkt->data[9];
info->level_idc = pkt->data[10];
info->profile_idc = (pkt->data[10] >> 8) & 0xff;
info->level_idc = pkt->data[10] & 0xff;
info->bit_depth_luma = pkt->data[13];
info->bit_depth_chroma = pkt->data[14];
info->chroma_fmt = pkt->data[15];
@ -925,6 +926,8 @@ static void vpu_malone_unpack_seq_hdr(struct vpu_rpc_event *pkt,
info->pixfmt = V4L2_PIX_FMT_NV12M_10BE_8L128;
else
info->pixfmt = V4L2_PIX_FMT_NV12M_8L128;
if (pkt->hdr.num > 28)
info->constraint_set_flags = pkt->data[28];
if (info->frame_rate.numerator && info->frame_rate.denominator) {
unsigned long n, d;