From 4400caeaef0d731735f3c9a09b4f35db54004855 Mon Sep 17 00:00:00 2001 From: Julian Bouzas Date: Wed, 22 Jan 2025 12:44:51 -0500 Subject: [PATCH] rtph265depay: Add request-keyframe property Similar to the H264 depayloader, this property will request a new keyframe when packet loss is detected. Part-of: --- .../gst/rtp/gstrtph265depay.c | 62 ++++++++++++++++--- .../gst/rtp/gstrtph265depay.h | 1 + 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c index 2369f0f05c..e4303dd875 100644 --- a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c +++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c @@ -40,11 +40,13 @@ GST_DEBUG_CATEGORY_STATIC (rtph265depay_debug); #define DEFAULT_STREAM_FORMAT GST_H265_STREAM_FORMAT_BYTESTREAM #define DEFAULT_ACCESS_UNIT FALSE #define DEFAULT_WAIT_FOR_KEYFRAME FALSE +#define DEFAULT_REQUEST_KEYFRAME FALSE enum { PROP_0, - PROP_WAIT_FOR_KEYFRAME + PROP_WAIT_FOR_KEYFRAME, + PROP_REQUEST_KEYFRAME, }; @@ -137,6 +139,9 @@ gst_rtp_h265_depay_set_property (GObject * object, guint prop_id, case PROP_WAIT_FOR_KEYFRAME: self->wait_for_keyframe = g_value_get_boolean (value); break; + case PROP_REQUEST_KEYFRAME: + self->request_keyframe = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -153,6 +158,9 @@ gst_rtp_h265_depay_get_property (GObject * object, guint prop_id, case PROP_WAIT_FOR_KEYFRAME: g_value_set_boolean (value, self->wait_for_keyframe); break; + case PROP_REQUEST_KEYFRAME: + g_value_set_boolean (value, self->request_keyframe); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -191,6 +199,19 @@ gst_rtp_h265_depay_class_init (GstRtpH265DepayClass * klass) DEFAULT_WAIT_FOR_KEYFRAME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRtpH265Depay:request-keyframe: + * + * Request new keyframe when packet loss is detected. + * + * Since: 1.26 + */ + g_object_class_install_property (gobject_class, PROP_REQUEST_KEYFRAME, + g_param_spec_boolean ("request-keyframe", "Request Keyframe", + "Request new keyframe when packet loss is detected", + DEFAULT_REQUEST_KEYFRAME, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_element_class_add_static_pad_template (gstelement_class, &gst_rtp_h265_depay_src_template); gst_element_class_add_static_pad_template (gstelement_class, @@ -227,6 +248,7 @@ gst_rtp_h265_depay_init (GstRtpH265Depay * rtph265depay) rtph265depay->pps = g_ptr_array_new_with_free_func ( (GDestroyNotify) gst_buffer_unref); rtph265depay->wait_for_keyframe = DEFAULT_WAIT_FOR_KEYFRAME; + rtph265depay->request_keyframe = DEFAULT_REQUEST_KEYFRAME; } static void @@ -235,6 +257,7 @@ gst_rtp_h265_depay_reset (GstRtpH265Depay * rtph265depay, gboolean hard) gst_adapter_clear (rtph265depay->adapter); rtph265depay->wait_start = TRUE; rtph265depay->waiting_for_keyframe = rtph265depay->wait_for_keyframe; + rtph265depay->requesting_keyframe = FALSE; gst_adapter_clear (rtph265depay->picture_adapter); rtph265depay->picture_start = FALSE; rtph265depay->last_keyframe = FALSE; @@ -1256,8 +1279,10 @@ gst_rtp_h265_depay_handle_nal (GstRtpH265Depay * rtph265depay, GstBuffer * nal, /* add to adapter */ gst_buffer_unmap (nal, &map); - if (!rtph265depay->picture_start && start && out_keyframe) + if (!rtph265depay->picture_start && start && out_keyframe) { rtph265depay->waiting_for_keyframe = FALSE; + rtph265depay->requesting_keyframe = FALSE; + } GST_DEBUG_OBJECT (depayload, "adding NAL to picture adapter"); gst_adapter_push (rtph265depay->picture_adapter, nal); @@ -1276,7 +1301,17 @@ gst_rtp_h265_depay_handle_nal (GstRtpH265Depay * rtph265depay, GstBuffer * nal, } if (outbuf) { - if (!rtph265depay->waiting_for_keyframe) { + /* Request a new keyframe if we are waiting for one */ + if (rtph265depay->waiting_for_keyframe && + !rtph265depay->requesting_keyframe && rtph265depay->request_keyframe) { + rtph265depay->requesting_keyframe = TRUE; + GST_INFO_OBJECT (depayload, "Requesting keyframe while waiting for one"); + gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload), + gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE, + TRUE, 0)); + } + + if (!rtph265depay->waiting_for_keyframe || !rtph265depay->wait_for_keyframe) { GST_INFO_OBJECT (depayload, "Pushing frame %" GST_PTR_FORMAT, outbuf); gst_rtp_h265_depay_push (rtph265depay, outbuf, out_keyframe, out_timestamp, marker); @@ -1333,23 +1368,26 @@ gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstRtpH265Depay *rtph265depay; GstBuffer *outbuf = NULL; + gboolean is_discont; guint8 nal_unit_type; rtph265depay = GST_RTP_H265_DEPAY (depayload); - if (!rtph265depay->merge) + if (!rtph265depay->merge) { rtph265depay->waiting_for_keyframe = FALSE; + rtph265depay->requesting_keyframe = FALSE; + } /* flush remaining data on discont */ - if (GST_BUFFER_IS_DISCONT (rtp->buffer)) { + is_discont = GST_BUFFER_IS_DISCONT (rtp->buffer); + if (is_discont) { gst_adapter_clear (rtph265depay->adapter); rtph265depay->wait_start = TRUE; rtph265depay->current_fu_type = 0; rtph265depay->last_fu_seqnum = 0; - if (rtph265depay->merge && rtph265depay->wait_for_keyframe) { + if (rtph265depay->merge) rtph265depay->waiting_for_keyframe = TRUE; - } } { @@ -1589,6 +1627,16 @@ gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) /* and assemble in the adapter */ gst_adapter_push (rtph265depay->adapter, outbuf); } else { + /* If packet is discont and is not the first one of a FU, then we + * can tell it is not part of a keyframe, so request a new one */ + if (is_discont && rtph265depay->request_keyframe) { + GST_INFO_OBJECT (depayload, + "discont FU received without start bit. Requesting keyframe."); + gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload), + gst_video_event_new_upstream_force_key_unit + (GST_CLOCK_TIME_NONE, TRUE, 0)); + } + if (rtph265depay->current_fu_type == 0) { /* previous FU packet missing start bit? */ GST_WARNING_OBJECT (rtph265depay, "missing FU start bit on an " diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.h b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.h index 95dbbad50c..fc6248e85c 100644 --- a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.h +++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.h @@ -90,6 +90,7 @@ struct _GstRtpH265Depay gboolean wait_for_keyframe; gboolean request_keyframe; gboolean waiting_for_keyframe; + gboolean requesting_keyframe; }; struct _GstRtpH265DepayClass