From 2a4d0a9b09a968bcdb5723cca5dd9a414022a577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 12 Aug 2019 18:56:34 +0300 Subject: [PATCH] rtpvp8depay: Add property for waiting until the next keyframe after packet loss If VP8 is not encoded with error resilience enabled then any packet loss causes very bad artefacts when decoding and waiting for the next keyframe instead improves user experience considerably. --- gst/rtp/gstrtpvp8depay.c | 63 +++++++++++++++++++++++++++++++++++++--- gst/rtp/gstrtpvp8depay.h | 4 ++- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/gst/rtp/gstrtpvp8depay.c b/gst/rtp/gstrtpvp8depay.c index 7c0d707d04..e71baf8165 100644 --- a/gst/rtp/gstrtpvp8depay.c +++ b/gst/rtp/gstrtpvp8depay.c @@ -33,6 +33,10 @@ GST_DEBUG_CATEGORY_STATIC (gst_rtp_vp8_depay_debug); #define GST_CAT_DEFAULT gst_rtp_vp8_depay_debug static void gst_rtp_vp8_depay_dispose (GObject * object); +static void gst_rtp_vp8_depay_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_rtp_vp8_depay_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); static GstBuffer *gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp); static GstStateChangeReturn gst_rtp_vp8_depay_change_state (GstElement * @@ -57,11 +61,20 @@ GST_STATIC_PAD_TEMPLATE ("sink", "media = (string) \"video\"," "encoding-name = (string) { \"VP8\", \"VP8-DRAFT-IETF-01\" }")); +#define DEFAULT_WAIT_FOR_KEYFRAME FALSE + +enum +{ + PROP_0, + PROP_WAIT_FOR_KEYFRAME +}; + static void gst_rtp_vp8_depay_init (GstRtpVP8Depay * self) { self->adapter = gst_adapter_new (); self->started = FALSE; + self->wait_for_keyframe = DEFAULT_WAIT_FOR_KEYFRAME; } static void @@ -72,7 +85,6 @@ gst_rtp_vp8_depay_class_init (GstRtpVP8DepayClass * gst_rtp_vp8_depay_class) GstRTPBaseDepayloadClass *depay_class = (GstRTPBaseDepayloadClass *) (gst_rtp_vp8_depay_class); - gst_element_class_add_static_pad_template (element_class, &gst_rtp_vp8_depay_sink_template); gst_element_class_add_static_pad_template (element_class, @@ -84,6 +96,14 @@ gst_rtp_vp8_depay_class_init (GstRtpVP8DepayClass * gst_rtp_vp8_depay_class) "Sjoerd Simons "); object_class->dispose = gst_rtp_vp8_depay_dispose; + object_class->set_property = gst_rtp_vp8_depay_set_property; + object_class->get_property = gst_rtp_vp8_depay_get_property; + + g_object_class_install_property (object_class, PROP_WAIT_FOR_KEYFRAME, + g_param_spec_boolean ("wait-for-keyframe", "Wait for Keyframe", + "Wait for the next keyframe after packet loss", + DEFAULT_WAIT_FOR_KEYFRAME, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); element_class->change_state = gst_rtp_vp8_depay_change_state; @@ -109,6 +129,38 @@ gst_rtp_vp8_depay_dispose (GObject * object) G_OBJECT_CLASS (gst_rtp_vp8_depay_parent_class)->dispose (object); } +static void +gst_rtp_vp8_depay_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (object); + + switch (prop_id) { + case PROP_WAIT_FOR_KEYFRAME: + self->wait_for_keyframe = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_rtp_vp8_depay_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (object); + + switch (prop_id) { + case PROP_WAIT_FOR_KEYFRAME: + g_value_set_boolean (value, self->wait_for_keyframe); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static GstBuffer * gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp) { @@ -122,6 +174,9 @@ gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp) GST_LOG_OBJECT (self, "Discontinuity, flushing adapter"); gst_adapter_clear (self->adapter); self->started = FALSE; + + if (self->wait_for_keyframe) + self->waiting_for_keyframe = TRUE; } size = gst_rtp_buffer_get_payload_len (rtp); @@ -190,7 +245,7 @@ gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp) if ((header[0] & 0x01)) { GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT); - if (!self->caps_sent) { + if (self->waiting_for_keyframe) { gst_buffer_unref (out); out = NULL; GST_INFO_OBJECT (self, "Dropping inter-frame before intra-frame"); @@ -222,11 +277,11 @@ gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp) gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), srccaps); gst_caps_unref (srccaps); - self->caps_sent = TRUE; self->last_width = width; self->last_height = height; self->last_profile = profile; } + self->waiting_for_keyframe = FALSE; } return out; @@ -253,7 +308,7 @@ gst_rtp_vp8_depay_change_state (GstElement * element, GstStateChange transition) self->last_profile = -1; self->last_height = -1; self->last_width = -1; - self->caps_sent = FALSE; + self->waiting_for_keyframe = TRUE; break; default: break; diff --git a/gst/rtp/gstrtpvp8depay.h b/gst/rtp/gstrtpvp8depay.h index 258546a1a5..cde8e5ea8e 100644 --- a/gst/rtp/gstrtpvp8depay.h +++ b/gst/rtp/gstrtpvp8depay.h @@ -54,10 +54,12 @@ struct _GstRtpVP8Depay GstAdapter *adapter; gboolean started; - gboolean caps_sent; + gboolean waiting_for_keyframe; gint last_profile; gint last_width; gint last_height; + + gboolean wait_for_keyframe; }; GType gst_rtp_vp8_depay_get_type (void);