diff options
author | He Junyan <junyan.he@intel.com> | 2022-04-18 22:36:09 +0800 |
---|---|---|
committer | He Junyan <junyan.he@intel.com> | 2022-12-01 09:44:41 +0800 |
commit | 2677d4c6db7c58fb5a98f85b43ea4317d84eaaf1 (patch) | |
tree | c5da52a389daeab041826c7f72cea61316f940eb | |
parent | 9ee657cdee2407e1ff62aacab94552cc2cc861fc (diff) | |
download | gstreamer-2677d4c6db7c58fb5a98f85b43ea4317d84eaaf1.tar.gz |
va: Add the low-delay-b frame support for H265.
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2036>
-rw-r--r-- | subprojects/gst-plugins-bad/sys/va/gstvah265enc.c | 85 |
1 files changed, 73 insertions, 12 deletions
diff --git a/subprojects/gst-plugins-bad/sys/va/gstvah265enc.c b/subprojects/gst-plugins-bad/sys/va/gstvah265enc.c index d493229e8e..a86c6e0266 100644 --- a/subprojects/gst-plugins-bad/sys/va/gstvah265enc.c +++ b/subprojects/gst-plugins-bad/sys/va/gstvah265enc.c @@ -277,6 +277,7 @@ struct _GstVaH265Enc guint32 max_l1_num; guint32 forward_ref_num; guint32 backward_ref_num; + gboolean low_delay_b_mode; guint num_reorder_frames; guint max_dpb_size; @@ -1265,7 +1266,12 @@ _h265_to_va_coding_type (GstVaH265Enc * self, GstVaH265EncFrame * frame) coding_type = 1; break; case GST_H265_P_SLICE: - coding_type = 2; + if (self->gop.low_delay_b_mode) { + /* Convert P into forward ref B */ + coding_type = 3; + } else { + coding_type = 2; + } break; case GST_H265_B_SLICE: /* We use hierarchical_level_plus1, so same for all B frames */ @@ -1431,6 +1437,7 @@ _h265_fill_slice_parameter (GstVaH265Enc * self, GstVaH265EncFrame * frame, VAEncSliceParameterBufferHEVC * slice) { int8_t slice_qp_delta = 0; + GstH265SliceType frame_type; gint i; /* *INDENT-OFF* */ @@ -1443,10 +1450,25 @@ _h265_fill_slice_parameter (GstVaH265Enc * self, GstVaH265EncFrame * frame, g_assert (slice_qp_delta <= 51 && slice_qp_delta >= -51); } + frame_type = frame->type; + /* If low_delay_b_mode, we convert P to low delay b, which has 2 + ref lists and clone L1 from L0. */ + if (self->gop.low_delay_b_mode && frame->type == GST_H265_P_SLICE) { + g_assert (self->gop.max_l1_num > 0); + g_assert (list1_num == 0); + + frame_type = GST_H265_B_SLICE; + list1_num = (list0_num <= self->gop.max_l1_num ? + list0_num : self->gop.max_l1_num); + + for (i = 0; i < list1_num; i++) + list1[i] = list0[i]; + } + *slice = (VAEncSliceParameterBufferHEVC) { .slice_segment_address = start_address, .num_ctu_in_slice = ctu_num, - .slice_type = frame->type, + .slice_type = frame_type, /* Only one parameter set supported now. */ .slice_pic_parameter_set_id = 0, /* Set the reference list later @@ -1490,7 +1512,7 @@ _h265_fill_slice_parameter (GstVaH265Enc * self, GstVaH265EncFrame * frame, /* deblocking_filter_control_present_flag not set now */ .slice_deblocking_filter_disabled_flag = 0, .slice_loop_filter_across_slices_enabled_flag = 1, - .collocated_from_l0_flag = (frame->type == GST_H265_I_SLICE ? + .collocated_from_l0_flag = (frame_type == GST_H265_I_SLICE ? 0 : self->features.collocated_from_l0_flag), }, #if VA_CHECK_VERSION(1, 10, 0) @@ -1500,16 +1522,17 @@ _h265_fill_slice_parameter (GstVaH265Enc * self, GstVaH265EncFrame * frame, }; /* *INDENT-ON* */ - if (frame->type == GST_H265_B_SLICE || frame->type == GST_H265_P_SLICE) { + if (frame_type == GST_H265_B_SLICE || frame_type == GST_H265_P_SLICE) { slice->slice_fields.bits.num_ref_idx_active_override_flag = (list0_num > 0 || list1_num > 0); slice->num_ref_idx_l0_active_minus1 = list0_num > 0 ? list0_num - 1 : 0; - if (frame->type == GST_H265_B_SLICE) + + if (frame_type == GST_H265_B_SLICE) slice->num_ref_idx_l1_active_minus1 = list1_num > 0 ? list1_num - 1 : 0; } i = 0; - if (frame->type != GST_H265_I_SLICE) { + if (frame_type != GST_H265_I_SLICE) { for (; i < list0_num; i++) { slice->ref_pic_list0[i].picture_id = gst_va_encode_picture_get_reconstruct_surface (list0[i]->picture); @@ -1522,7 +1545,7 @@ _h265_fill_slice_parameter (GstVaH265Enc * self, GstVaH265EncFrame * frame, } i = 0; - if (frame->type == GST_H265_B_SLICE) { + if (frame_type == GST_H265_B_SLICE) { for (; i < list1_num; i++) { slice->ref_pic_list1[i].picture_id = gst_va_encode_picture_get_reconstruct_surface (list1[i]->picture); @@ -2311,6 +2334,7 @@ gst_va_h265_enc_reset_state (GstVaBaseEnc * base) self->gop.i_period = 0; self->gop.total_idr_count = 0; self->gop.ip_period = 0; + self->gop.low_delay_b_mode = FALSE; self->gop.highest_pyramid_level = 0; memset (self->gop.frame_types, 0, sizeof (self->gop.frame_types)); self->gop.cur_frame_index = 0; @@ -2942,8 +2966,13 @@ _h265_print_gop_structure (GstVaH265Enc * self) g_string_append_printf (str, ", "); } - g_string_append_printf (str, "%s", - _h265_slice_type_name (self->gop.frame_types[i].slice_type)); + if (self->gop.low_delay_b_mode && + self->gop.frame_types[i].slice_type == GST_H265_P_SLICE) { + g_string_append_printf (str, "%s", "LDB"); + } else { + g_string_append_printf (str, "%s", + _h265_slice_type_name (self->gop.frame_types[i].slice_type)); + } if (self->gop.b_pyramid && self->gop.frame_types[i].slice_type == GST_H265_B_SLICE) { @@ -3028,13 +3057,14 @@ _get_log2_max_num (guint num) /* Consider the idr_period, num_bframes, L0/L1 reference number. * TODO: Load some preset fixed GOP structure. * TODO: Skip this if in lookahead mode. */ -static void +static gboolean _h265_generate_gop_structure (GstVaH265Enc * self) { GstVaBaseEnc *base = GST_VA_BASE_ENC (self); guint32 log2_max_frame_num; guint32 list0, list1, forward_num, backward_num, gop_ref_num; gint32 p_frames; + guint32 prediction_direction; /* If not set, generate a idr every second */ if (self->gop.idr_period == 0) { @@ -3085,12 +3115,40 @@ _h265_generate_gop_structure (GstVaH265Enc * self) forward_num = list0; backward_num = list1; + + prediction_direction = gst_va_encoder_get_prediction_direction (base->encoder, + base->profile, GST_VA_BASE_ENC_ENTRYPOINT (base)); + if (prediction_direction) { +#if VA_CHECK_VERSION(1,9,0) + if (!(prediction_direction & VA_PREDICTION_DIRECTION_PREVIOUS)) { + GST_INFO_OBJECT (self, "No forward prediction support"); + forward_num = 0; + /* Only backward ref is insane. */ + backward_num = 0; + } + + if (!(prediction_direction & VA_PREDICTION_DIRECTION_FUTURE)) { + GST_INFO_OBJECT (self, "No backward prediction support"); + backward_num = 0; + } + + if (prediction_direction & VA_PREDICTION_DIRECTION_BI_NOT_EMPTY) { + if (self->gop.max_l1_num == 0) { + GST_INFO_OBJECT (self, "Not possible to support " + "VA_PREDICTION_DIRECTION_BI_NOT_EMPTY while list1 is 0"); + return FALSE; + } + GST_INFO_OBJECT (self, "Enable low-delay-b mode"); + self->gop.low_delay_b_mode = TRUE; + } +#endif + } + if (forward_num > self->gop.num_ref_frames) forward_num = self->gop.num_ref_frames; if (backward_num > self->gop.num_ref_frames) backward_num = self->gop.num_ref_frames; - if (forward_num == 0) { GST_INFO_OBJECT (self, "No reference support, fallback to intra only stream"); @@ -3261,6 +3319,8 @@ create_poc: self->gop.num_bframes, PROP_BFRAMES); update_property_bool (base, &self->prop.b_pyramid, self->gop.b_pyramid, PROP_B_PYRAMID); + + return TRUE; } static gboolean @@ -3770,7 +3830,8 @@ gst_va_h265_enc_reconfig (GstVaBaseEnc * base) if (!_h265_calculate_tier_level (self)) return FALSE; - _h265_generate_gop_structure (self); + if (!_h265_generate_gop_structure (self)) + return FALSE; _h265_setup_encoding_features (self); |