On Mon May 12 10:01:36 2025 +0800, Ming Qian wrote:
> 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 <[email protected]>
> Signed-off-by: Nicolas Dufresne <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Hans Verkuil

 drivers/media/platform/amphion/vdec.c        |  59 +++++++++++++
 drivers/media/platform/amphion/vpu_defs.h    |  12 +++
 drivers/media/platform/amphion/vpu_helpers.c | 123 +++++++++++++++++++++++++++
 drivers/media/platform/amphion/vpu_helpers.h |   7 ++
 drivers/media/platform/amphion/vpu_malone.c  |   5 +-
 5 files changed, 205 insertions(+), 1 deletion(-)

---

diff --git a/drivers/media/platform/amphion/vdec.c 
b/drivers/media/platform/amphion/vdec.c
index 85d518823159..55067d9405c2 100644
--- a/drivers/media/platform/amphion/vdec.c
+++ b/drivers/media/platform/amphion/vdec.c
@@ -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) {
diff --git a/drivers/media/platform/amphion/vpu_defs.h 
b/drivers/media/platform/amphion/vpu_defs.h
index 428d988cf2f7..f56245ae2205 100644
--- a/drivers/media/platform/amphion/vpu_defs.h
+++ b/drivers/media/platform/amphion/vpu_defs.h
@@ -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 {
diff --git a/drivers/media/platform/amphion/vpu_helpers.c 
b/drivers/media/platform/amphion/vpu_helpers.c
index d12310af9ebc..886d5632388e 100644
--- a/drivers/media/platform/amphion/vpu_helpers.c
+++ b/drivers/media/platform/amphion/vpu_helpers.c
@@ -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));
+}
diff --git a/drivers/media/platform/amphion/vpu_helpers.h 
b/drivers/media/platform/amphion/vpu_helpers.h
index 84d16eb39650..76fba0d6090c 100644
--- a/drivers/media/platform/amphion/vpu_helpers.h
+++ b/drivers/media/platform/amphion/vpu_helpers.h
@@ -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
diff --git a/drivers/media/platform/amphion/vpu_malone.c 
b/drivers/media/platform/amphion/vpu_malone.c
index feca7d4220ed..ba688566dffd 100644
--- a/drivers/media/platform/amphion/vpu_malone.c
+++ b/drivers/media/platform/amphion/vpu_malone.c
@@ -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;
 

Reply via email to