From a4286c4564b9e1557ce5a9440096665887fa13fe Mon Sep 17 00:00:00 2001 From: Hirokazu Honda <hiroh@chromium.org> Date: Thu, 26 Dec 2019 15:43:23 +0900 Subject: [PATCH] libv4lplugins: Change h264 level to a specified one An app can specify the h264 stream of the encoded stream by calling VIDIOC_S_EXT_CTRL with V4L2_CID_MPEG_VIDEO_H264_LEVEL. However, libv4lplugins ignores the specified level the h264 level is always 4.0. The plugin must change the level to the level set by app. BUG=chromium:1036219, chromium:1036220, b:146854692 TEST=webrtc.RTCPeerConnectionAccelUsed.enc_h264 on kevin TEST=android.media.cts.MediaRecorderTest#testProfileAvcBaselineLevel1 Change-Id: I6c010af8862624e37418b86458a7f9df8aa2c868 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/libv4lplugins/+/1980599 Commit-Queue: Hirokazu Honda <hiroh@chromium.org> Tested-by: Hirokazu Honda <hiroh@chromium.org> Reviewed-by: Alexandre Courbot <acourbot@chromium.org> Reviewed-by: Chih-Yu Huang <akahuang@chromium.org> --- .../libv4l-encplugin-rockchip.c | 18 +++++- libv4l-rockchip_v2/libvepu/h264e/h264e.c | 61 ++++++++++++++++--- libv4l-rockchip_v2/libvepu/h264e/h264e.h | 1 - .../libvepu/rk_vepu_interface.h | 3 +- 4 files changed, 70 insertions(+), 13 deletions(-) diff --git a/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c b/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c index 3bf90ac..009c207 100644 --- a/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c +++ b/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c @@ -199,6 +199,8 @@ static pthread_once_t g_get_log_level_once = PTHREAD_ONCE_INIT; /* Returns true when the H264 profile is supported. */ static bool is_supported_h264_profile(uint8_t profile); +/* Returns true when the H264 true is supported. */ +static bool is_supported_h264_level(uint8_t level); static void *plugin_init(int fd) { @@ -508,7 +510,13 @@ static int ioctl_s_ext_ctrls_locked(struct encoder_context *ctx, int fd, case V4L2_CID_MPEG_VIDEO_H264_PROFILE: if (!is_supported_h264_profile(ext_ctrls->controls[i].value)) return -EINVAL; - ctx->init_param.h264e.h264_profile = + ctx->init_param.h264e.v4l2_h264_profile = + ext_ctrls->controls[i].value; + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + if (!is_supported_h264_level(ext_ctrls->controls[i].value)) + return -EINVAL; + ctx->init_param.h264e.v4l2_h264_level = ext_ctrls->controls[i].value; break; default: @@ -770,6 +778,9 @@ static int initialize_libvpu(struct encoder_context *ctx, int fd) { struct rk_vepu_init_param init_param; memset(&init_param, 0, sizeof(init_param)); + /* The default value of h264 level is 4.0. */ + init_param.h264e.v4l2_h264_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; + /* Get the input format. */ struct v4l2_format format; @@ -939,6 +950,11 @@ static bool is_supported_h264_profile(uint8_t profile) { profile == V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; } +static bool is_supported_h264_level(uint8_t level) { + // RK3399 is capable of encoding h264 whose level is 4.1 and lower. + return level <= V4L2_MPEG_VIDEO_H264_LEVEL_4_1; +} + PLUGIN_PUBLIC const struct libv4l_dev_ops libv4l2_plugin = { .init = &plugin_init, .close = &plugin_close, diff --git a/libv4l-rockchip_v2/libvepu/h264e/h264e.c b/libv4l-rockchip_v2/libvepu/h264e/h264e.c index 0362089..847cb6e 100644 --- a/libv4l-rockchip_v2/libvepu/h264e/h264e.c +++ b/libv4l-rockchip_v2/libvepu/h264e/h264e.c @@ -33,9 +33,50 @@ const int32_t h264e_qp_tbl[2][11] = { const int baseline_idc = 66; const int main_idc = 77; -static void h264e_init_sps(struct v4l2_plugin_h264_sps *sps, uint8_t profile) +static uint8_t v4l2_level_to_h264_level(uint8_t level) { + switch (level) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + return H264ENC_LEVEL_1; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + return H264ENC_LEVEL_1_b; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + return H264ENC_LEVEL_1_1; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + return H264ENC_LEVEL_1_2; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + return H264ENC_LEVEL_1_3; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + return H264ENC_LEVEL_2; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + return H264ENC_LEVEL_2_1; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + return H264ENC_LEVEL_2_2; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + return H264ENC_LEVEL_3; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + return H264ENC_LEVEL_3_1; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + return H264ENC_LEVEL_3_2; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + return H264ENC_LEVEL_4_0; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + return H264ENC_LEVEL_4_1; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + return 42; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + return 50; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + return 51; + default: + fprintf(stderr, "Unknown h264 level=%d, use 4.0", (int) level); + return H264ENC_LEVEL_4_0; + }; +} + + +static void h264e_init_sps(struct v4l2_plugin_h264_sps *sps, uint8_t v4l2_profile, uint8_t v4l2_level) { - switch(profile) { + switch(v4l2_profile) { case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: sps->profile_idc = baseline_idc; @@ -54,9 +95,7 @@ static void h264e_init_sps(struct v4l2_plugin_h264_sps *sps, uint8_t profile) /* if level idc == 1b, constraint_set3_flag need to be set true */ sps->constraint_set3_flag = 0; - /* if level max than 31, we prefer disable 4x4 mv mode - to limit max mv count per 2mb */ - sps->level_idc = H264ENC_LEVEL_4_0; + sps->level_idc = v4l2_level_to_h264_level(v4l2_level); sps->seq_parameter_set_id = 0; /* fixed values limited by hardware */ @@ -79,13 +118,13 @@ static void h264e_init_sps(struct v4l2_plugin_h264_sps *sps, uint8_t profile) sps->vui_parameters_present_flag = 1; } -static void h264e_init_pps(struct v4l2_plugin_h264_pps *pps, uint8_t profile) +static void h264e_init_pps(struct v4l2_plugin_h264_pps *pps, uint8_t v4l2_profile) { pps->pic_parameter_set_id = 0; pps->seq_parameter_set_id = 0; pps->entropy_coding_mode_flag = 0; - if (profile >= V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) { + if (v4l2_profile >= V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) { /* enable cabac coding need set profile_idc large than 77 */ pps->entropy_coding_mode_flag = 1; } @@ -413,15 +452,15 @@ static int h264e_init(struct rk_venc *ictx, ictx->fmt = ENC_FORMAT_H264; ctx->h264_sps_pps_before_idr = param->h264e.h264_sps_pps_before_idr; - ctx->h264_profile = param->h264e.h264_profile; ctx->width = param->width; ctx->height = param->height; ctx->slice_size_mb_rows = 0; ctx->frm_in_gop = 0; - h264e_init_sps(&ctx->sps, ctx->h264_profile); - h264e_init_pps(&ctx->pps, ctx->h264_profile); + h264e_init_sps(&ctx->sps, param->h264e.v4l2_h264_profile, + param->h264e.v4l2_h264_level); + h264e_init_pps(&ctx->pps, param->h264e.v4l2_h264_profile); h264e_init_slice(&ctx->slice); ctx->sps.pic_width_in_mbs = MB_COUNT(ctx->width); @@ -441,6 +480,8 @@ static int h264e_init(struct rk_venc *ictx, h264e_init_rc(ictx); + /* if level is 31 or greater, we prefer disable 4x4 mv mode + to limit max mv count per 2mb */ if (ctx->sps.level_idc >= H264ENC_LEVEL_3_1) ctx->h264_inter4x4_disabled = 1; else diff --git a/libv4l-rockchip_v2/libvepu/h264e/h264e.h b/libv4l-rockchip_v2/libvepu/h264e/h264e.h index c944527..32b8bf7 100644 --- a/libv4l-rockchip_v2/libvepu/h264e/h264e.h +++ b/libv4l-rockchip_v2/libvepu/h264e/h264e.h @@ -44,7 +44,6 @@ struct rk_h264_encoder { char stream_header[H264E_MAX_STREAM_HEADER_SIZE]; int stream_header_size; int h264_sps_pps_before_idr; - uint8_t h264_profile; int width; int height; diff --git a/libv4l-rockchip_v2/libvepu/rk_vepu_interface.h b/libv4l-rockchip_v2/libvepu/rk_vepu_interface.h index 78457fe..31727ea 100644 --- a/libv4l-rockchip_v2/libvepu/rk_vepu_interface.h +++ b/libv4l-rockchip_v2/libvepu/rk_vepu_interface.h @@ -39,7 +39,8 @@ struct rk_vepu_init_param { union { struct { bool h264_sps_pps_before_idr; - uint8_t h264_profile; + uint8_t v4l2_h264_profile; + uint8_t v4l2_h264_level; } h264e; }; }; -- GitLab