From 67ce55f33eb3f63080de0793b517cc85fdea9f30 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Wed, 3 Aug 2022 17:52:25 +0200 Subject: [PATCH] vah264enc: Lock properties read/write. This is a first step for changing properties at runtime. And add missing bitrate upate and notification. Fixes: #1258 Part-of: --- subprojects/gst-plugins-bad/sys/va/gstvabaseenc.c | 29 ++++ subprojects/gst-plugins-bad/sys/va/gstvabaseenc.h | 9 ++ subprojects/gst-plugins-bad/sys/va/gstvah264enc.c | 168 ++++++++++------------ 3 files changed, 116 insertions(+), 90 deletions(-) diff --git a/subprojects/gst-plugins-bad/sys/va/gstvabaseenc.c b/subprojects/gst-plugins-bad/sys/va/gstvabaseenc.c index 1a2ff73..7775be2 100644 --- a/subprojects/gst-plugins-bad/sys/va/gstvabaseenc.c +++ b/subprojects/gst-plugins-bad/sys/va/gstvabaseenc.c @@ -1100,3 +1100,32 @@ gst_va_base_enc_add_codec_tag (GstVaBaseEnc * base, const gchar * codec_name) gst_video_encoder_merge_tags (venc, tags, GST_TAG_MERGE_REPLACE); gst_tag_list_unref (tags); } + +/* *INDENT-OFF* */ +#define UPDATE_PROPERTY \ + GST_OBJECT_LOCK (base); \ + if (*old_val == new_val) { \ + GST_OBJECT_UNLOCK (base); \ + return; \ + } \ + *old_val = new_val; \ + GST_OBJECT_UNLOCK (base); \ + if (pspec) \ + g_object_notify_by_pspec (G_OBJECT (base), pspec); \ + +void +gst_va_base_enc_update_property_uint (GstVaBaseEnc * base, guint32 * old_val, + guint32 new_val, GParamSpec * pspec) +{ + UPDATE_PROPERTY +} + +void +gst_va_base_enc_update_property_bool (GstVaBaseEnc * base, gboolean * old_val, + gboolean new_val, GParamSpec * pspec) +{ + UPDATE_PROPERTY +} + +#undef UPDATE_PROPERTY +/* *INDENT-ON* */ diff --git a/subprojects/gst-plugins-bad/sys/va/gstvabaseenc.h b/subprojects/gst-plugins-bad/sys/va/gstvabaseenc.h index 3fa2f9b..b6aa033 100644 --- a/subprojects/gst-plugins-bad/sys/va/gstvabaseenc.h +++ b/subprojects/gst-plugins-bad/sys/va/gstvabaseenc.h @@ -129,6 +129,15 @@ gboolean gst_va_base_enc_add_trellis_parameter (GstVaBaseEnc * base void gst_va_base_enc_add_codec_tag (GstVaBaseEnc * base, const gchar * codec_name); +void gst_va_base_enc_update_property_uint (GstVaBaseEnc * base, + guint32 * old_val, + guint32 new_val, + GParamSpec * pspec); +void gst_va_base_enc_update_property_bool (GstVaBaseEnc * base, + gboolean * old_val, + gboolean new_val, + GParamSpec * pspec); + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaBaseEnc, gst_object_unref) G_END_DECLS diff --git a/subprojects/gst-plugins-bad/sys/va/gstvah264enc.c b/subprojects/gst-plugins-bad/sys/va/gstvah264enc.c index 6d5f227..1f08a1f 100644 --- a/subprojects/gst-plugins-bad/sys/va/gstvah264enc.c +++ b/subprojects/gst-plugins-bad/sys/va/gstvah264enc.c @@ -431,6 +431,13 @@ _calculate_bitrate_hrd (GstVaH264Enc * self) self->rc.cpb_length_bits = cpb_bits_size; } +#define update_property(type, obj, old_val, new_val, prop_id) \ + gst_va_base_enc_update_property_##type (obj, old_val, new_val, properties[prop_id]) +#define update_property_uint(obj, old_val, new_val, prop_id) \ + update_property (uint, obj, old_val, new_val, prop_id) +#define update_property_bool(obj, old_val, new_val, prop_id) \ + update_property (bool, obj, old_val, new_val, prop_id) + /* Estimates a good enough bitrate if none was supplied */ static void _ensure_rate_control (GstVaH264Enc * self) @@ -482,7 +489,7 @@ _ensure_rate_control (GstVaH264Enc * self) GstVaBaseEnc *base = GST_VA_BASE_ENC (self); guint bitrate; - guint32 rc_mode, quality_level; + guint32 rc_ctrl, rc_mode, quality_level; quality_level = gst_va_encoder_get_quality_level (base->encoder, base->profile, base->entrypoint); @@ -491,23 +498,27 @@ _ensure_rate_control (GstVaH264Enc * self) "fallback to %d", self->rc.target_usage, quality_level); self->rc.target_usage = quality_level; - self->prop.target_usage = self->rc.target_usage; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TARGET_USAGE]); + update_property_uint (base, &self->prop.target_usage, self->rc.target_usage, + PROP_TARGET_USAGE); } - if (self->prop.rc_ctrl != VA_RC_NONE) { + GST_OBJECT_LOCK (self); + rc_ctrl = self->prop.rc_ctrl; + GST_OBJECT_UNLOCK (self); + + if (rc_ctrl != VA_RC_NONE) { rc_mode = gst_va_encoder_get_rate_control_mode (base->encoder, base->profile, base->entrypoint); - if (!(rc_mode & self->prop.rc_ctrl)) { + if (!(rc_mode & rc_ctrl)) { guint32 defval = G_PARAM_SPEC_ENUM (properties[PROP_RATE_CONTROL])->default_value; GST_INFO_OBJECT (self, "The rate control mode %s is not supported, " - "fallback to %s mode", - _rate_control_get_name (self->prop.rc_ctrl), + "fallback to %s mode", _rate_control_get_name (rc_ctrl), _rate_control_get_name (defval)); self->rc.rc_ctrl_mode = defval; - self->prop.rc_ctrl = self->rc.rc_ctrl_mode; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RATE_CONTROL]); + + update_property_uint (base, &self->prop.rc_ctrl, self->rc.rc_ctrl_mode, + PROP_RATE_CONTROL); } } else { self->rc.rc_ctrl_mode = VA_RC_NONE; @@ -518,8 +529,8 @@ _ensure_rate_control (GstVaH264Enc * self) "set it to the max_qp", self->rc.min_qp, self->rc.max_qp); self->rc.min_qp = self->rc.max_qp; - self->prop.min_qp = self->rc.min_qp; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MIN_QP]); + update_property_uint (base, &self->prop.min_qp, self->rc.min_qp, + PROP_MIN_QP); } /* Make all the qp in the valid range */ @@ -562,7 +573,10 @@ _ensure_rate_control (GstVaH264Enc * self) self->rc.qp_b = self->rc.max_qp; } + GST_OBJECT_LOCK (self); bitrate = self->prop.bitrate; + GST_OBJECT_UNLOCK (self); + /* Calculate a bitrate is not set. */ if ((self->rc.rc_ctrl_mode == VA_RC_CBR || self->rc.rc_ctrl_mode == VA_RC_VBR || self->rc.rc_ctrl_mode == VA_RC_VCM) && bitrate == 0) { @@ -625,30 +639,15 @@ _ensure_rate_control (GstVaH264Enc * self) if (self->rc.rc_ctrl_mode != VA_RC_CQP) _calculate_bitrate_hrd (self); - /* notifications */ - if (self->rc.cpb_size != self->prop.cpb_size) { - self->prop.cpb_size = self->rc.cpb_size; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CPB_SIZE]); - } - - if (self->prop.target_percentage != self->rc.target_percentage) { - self->prop.target_percentage = self->rc.target_percentage; - g_object_notify_by_pspec (G_OBJECT (self), - properties[PROP_TARGET_PERCENTAGE]); - } - - if (self->prop.qp_i != self->rc.qp_i) { - self->prop.qp_i = self->rc.qp_i; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_QP_I]); - } - if (self->prop.qp_p != self->rc.qp_p) { - self->prop.qp_p = self->rc.qp_p; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_QP_P]); - } - if (self->prop.qp_b != self->rc.qp_b) { - self->prop.qp_b = self->rc.qp_b; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_QP_B]); - } + /* update & notifications */ + update_property_uint (base, &self->prop.bitrate, bitrate, PROP_BITRATE); + update_property_uint (base, &self->prop.cpb_size, self->rc.cpb_size, + PROP_CPB_SIZE); + update_property_uint (base, &self->prop.target_percentage, + self->rc.target_percentage, PROP_TARGET_PERCENTAGE); + update_property_uint (base, &self->prop.qp_i, self->rc.qp_i, PROP_QP_I); + update_property_uint (base, &self->prop.qp_p, self->rc.qp_p, PROP_QP_P); + update_property_uint (base, &self->prop.qp_b, self->rc.qp_b, PROP_QP_B); } static guint @@ -731,10 +730,8 @@ _validate_parameters (GstVaH264Enc * self) if (self->num_slices > ((self->mb_width * self->mb_height + 1) / 2)) self->num_slices = ((self->mb_width * self->mb_height + 1) / 2); - if (self->prop.num_slices != self->num_slices) { - self->prop.num_slices = self->num_slices; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_NUM_SLICES]); - } + update_property_uint (base, &self->prop.num_slices, + self->num_slices, PROP_NUM_SLICES); /* Ensure trellis. */ if (self->use_trellis && @@ -744,10 +741,8 @@ _validate_parameters (GstVaH264Enc * self) self->use_trellis = FALSE; } - if (self->prop.use_trellis != self->use_trellis) { - self->prop.use_trellis = self->use_trellis; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TRELLIS]); - } + update_property_bool (base, &self->prop.use_trellis, self->use_trellis, + PROP_TRELLIS); } /* Get log2_max_frame_num_minus4, log2_max_pic_order_cnt_lsb_minus4 @@ -948,10 +943,8 @@ _generate_gop_structure (GstVaH264Enc * self) GST_INFO_OBJECT (self, "Lowering the GOP size to %d", self->gop.idr_period); } - if (self->gop.idr_period != self->prop.key_int_max) { - self->prop.key_int_max = self->gop.idr_period; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_KEY_INT_MAX]); - } + update_property_uint (base, &self->prop.key_int_max, self->gop.idr_period, + PROP_KEY_INT_MAX); /* Prefer have more than 1 refs for the GOP which is not very small. */ if (self->gop.idr_period > 8) { @@ -1137,17 +1130,11 @@ create_poc: _create_gop_frame_types (self); _print_gop_structure (self); - /* notifications */ - if (self->prop.num_ref_frames != self->gop.num_ref_frames) { - self->prop.num_ref_frames = self->gop.num_ref_frames; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_NUM_REF_FRAMES]); - } - - if (self->prop.num_iframes != self->gop.num_iframes) { - self->prop.num_iframes = self->gop.num_iframes; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_IFRAMES]); - } - + /* updates & notifications */ + update_property_uint (base, &self->prop.num_ref_frames, + self->gop.num_ref_frames, PROP_NUM_REF_FRAMES); + update_property_uint (base, &self->prop.num_iframes, self->gop.num_iframes, + PROP_IFRAMES); } static void @@ -1423,8 +1410,8 @@ _decide_profile (GstVaH264Enc * self) GST_INFO_OBJECT (self, "Disable dct8x8, profile %s does not support it", gst_va_profile_name (base->profile)); self->use_dct8x8 = FALSE; - self->prop.use_dct8x8 = FALSE; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DCT8X8]); + update_property_bool (base, &self->prop.use_dct8x8, self->use_dct8x8, + PROP_DCT8X8); } if (self->use_cabac && (!g_strstr_len (profile_name, -1, "main") @@ -1432,8 +1419,8 @@ _decide_profile (GstVaH264Enc * self) GST_INFO_OBJECT (self, "Disable cabac, profile %s does not support it", gst_va_profile_name (base->profile)); self->use_cabac = FALSE; - self->prop.use_cabac = FALSE; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CABAC]); + update_property_bool (base, &self->prop.use_cabac, self->use_cabac, + PROP_CABAC); } if (self->gop.num_bframes > 0 && g_strstr_len (profile_name, -1, "baseline")) { @@ -1467,10 +1454,7 @@ gst_va_h264_enc_reset_state (GstVaBaseEnc * base) GST_VA_BASE_ENC_CLASS (parent_class)->reset_state (base); - self->level_idc = 0; - self->level_str = NULL; - self->mb_width = 0; - self->mb_height = 0; + GST_OBJECT_LOCK (self); self->use_cabac = self->prop.use_cabac; self->use_dct8x8 = self->prop.use_dct8x8; self->use_trellis = self->prop.use_trellis; @@ -1478,13 +1462,33 @@ gst_va_h264_enc_reset_state (GstVaBaseEnc * base) self->num_slices = self->prop.num_slices; self->gop.idr_period = self->prop.key_int_max; + self->gop.num_bframes = self->prop.num_bframes; + self->gop.b_pyramid = self->prop.b_pyramid; + self->gop.num_iframes = self->prop.num_iframes; + self->gop.num_ref_frames = self->prop.num_ref_frames; + + self->rc.rc_ctrl_mode = self->prop.rc_ctrl; + self->rc.min_qp = self->prop.min_qp; + self->rc.max_qp = self->prop.max_qp; + self->rc.qp_i = self->prop.qp_i; + self->rc.qp_p = self->prop.qp_p; + self->rc.qp_b = self->prop.qp_b; + self->rc.mbbrc = self->prop.mbbrc; + + self->rc.target_percentage = self->prop.target_percentage; + self->rc.target_usage = self->prop.target_usage; + self->rc.cpb_size = self->prop.cpb_size; + GST_OBJECT_UNLOCK (self); + + self->level_idc = 0; + self->level_str = NULL; + self->mb_width = 0; + self->mb_height = 0; + self->gop.i_period = 0; self->gop.total_idr_count = 0; self->gop.ip_period = 0; - self->gop.num_bframes = self->prop.num_bframes; - self->gop.b_pyramid = self->prop.b_pyramid; self->gop.highest_pyramid_level = 0; - self->gop.num_iframes = self->prop.num_iframes; memset (self->gop.frame_types, 0, sizeof (self->gop.frame_types)); self->gop.cur_frame_index = 0; self->gop.cur_frame_num = 0; @@ -1492,25 +1496,14 @@ gst_va_h264_enc_reset_state (GstVaBaseEnc * base) self->gop.log2_max_frame_num = 0; self->gop.max_pic_order_cnt = 0; self->gop.log2_max_pic_order_cnt = 0; - self->gop.num_ref_frames = self->prop.num_ref_frames; self->gop.ref_num_list0 = 0; self->gop.ref_num_list1 = 0; self->gop.num_reorder_frames = 0; - self->rc.rc_ctrl_mode = self->prop.rc_ctrl; - self->rc.min_qp = self->prop.min_qp; - self->rc.max_qp = self->prop.max_qp; - self->rc.qp_i = self->prop.qp_i; - self->rc.qp_p = self->prop.qp_p; - self->rc.qp_b = self->prop.qp_b; - self->rc.mbbrc = self->prop.mbbrc; self->rc.max_bitrate = 0; self->rc.target_bitrate = 0; - self->rc.target_percentage = self->prop.target_percentage; - self->rc.target_usage = self->prop.target_usage; self->rc.max_bitrate_bits = 0; self->rc.target_bitrate_bits = 0; - self->rc.cpb_size = self->prop.cpb_size; self->rc.cpb_length_bits = 0; memset (&self->sequence_hdr, 0, sizeof (GstH264SPS)); @@ -1562,17 +1555,12 @@ gst_va_h264_enc_reconfig (GstVaBaseEnc * base) _generate_gop_structure (self); _calculate_coded_size (self); - /* notifications */ + /* updates & notifications */ /* num_bframes are modified several times before */ - if (self->prop.num_bframes != self->gop.num_bframes) { - self->prop.num_bframes = self->gop.num_bframes; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BFRAMES]); - } - - if (self->prop.b_pyramid != self->gop.b_pyramid) { - self->prop.b_pyramid = self->gop.b_pyramid; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_B_PYRAMID]); - } + update_property_uint (base, &self->prop.num_bframes, self->gop.num_bframes, + PROP_BFRAMES); + update_property_bool (base, &self->prop.b_pyramid, self->gop.b_pyramid, + PROP_B_PYRAMID); if (!_init_packed_headers (self)) return FALSE; -- 2.7.4