rtpulpfecdec: add property for passthrough

Support for enabling and disabling decoding of FEC data decoding on
packet loss events and unconditional seqnum rewriting of packets.

See
https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/581
for background.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3212>
This commit is contained in:
Matthew Waters 2022-10-18 16:51:39 +11:00 committed by GStreamer Marge Bot
parent d0e2b31470
commit 093e9c8c9d
3 changed files with 81 additions and 1 deletions

View file

@ -16373,6 +16373,18 @@
} }
}, },
"properties": { "properties": {
"passthrough": {
"blurb": "Whether to passthrough all data as-is without modification and never attempt to recover packets",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "false",
"mutable": "null",
"readable": true,
"type": "gboolean",
"writable": true
},
"pt": { "pt": {
"blurb": "FEC packets payload type", "blurb": "FEC packets payload type",
"conditionally-available": false, "conditionally-available": false,

View file

@ -85,10 +85,12 @@ enum
PROP_STORAGE, PROP_STORAGE,
PROP_RECOVERED, PROP_RECOVERED,
PROP_UNRECOVERED, PROP_UNRECOVERED,
PROP_PASSTHROUGH,
N_PROPERTIES N_PROPERTIES
}; };
#define DEFAULT_FEC_PT 0 #define DEFAULT_FEC_PT 0
#define DEFAULT_PASSTHROUGH FALSE
static GParamSpec *klass_properties[N_PROPERTIES] = { NULL, }; static GParamSpec *klass_properties[N_PROPERTIES] = { NULL, };
@ -378,6 +380,7 @@ gst_rtp_ulpfec_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
if (G_LIKELY (GST_FLOW_OK == self->chain_return_val)) { if (G_LIKELY (GST_FLOW_OK == self->chain_return_val)) {
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
gboolean passthrough;
buf = gst_buffer_make_writable (buf); buf = gst_buffer_make_writable (buf);
if (G_UNLIKELY (self->unset_discont_flag)) { if (G_UNLIKELY (self->unset_discont_flag)) {
@ -385,8 +388,20 @@ gst_rtp_ulpfec_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT); GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
} }
GST_OBJECT_LOCK (self);
if (G_UNLIKELY (self->needs_discont)) {
self->needs_discont = FALSE;
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
}
passthrough = self->passthrough;
GST_OBJECT_UNLOCK (self);
gst_rtp_buffer_map (buf, GST_MAP_WRITE, &rtp); gst_rtp_buffer_map (buf, GST_MAP_WRITE, &rtp);
gst_rtp_buffer_set_seq (&rtp, self->next_seqnum++); if (passthrough) {
self->next_seqnum = gst_rtp_buffer_get_seq (&rtp) + 1;
} else {
gst_rtp_buffer_set_seq (&rtp, self->next_seqnum++);
}
gst_rtp_buffer_unmap (&rtp); gst_rtp_buffer_unmap (&rtp);
return gst_pad_push (self->srcpad, buf); return gst_pad_push (self->srcpad, buf);
@ -442,6 +457,13 @@ gst_rtp_ulpfec_dec_handle_packet_loss (GstRtpUlpFecDec * self, guint16 seqnum,
gst_rtp_buffer_set_seq (&rtp, self->next_seqnum++); gst_rtp_buffer_set_seq (&rtp, self->next_seqnum++);
gst_rtp_buffer_unmap (&rtp); gst_rtp_buffer_unmap (&rtp);
GST_OBJECT_LOCK (self);
if (G_UNLIKELY (self->needs_discont)) {
self->needs_discont = FALSE;
GST_BUFFER_FLAG_SET (sent_buffer, GST_BUFFER_FLAG_DISCONT);
}
GST_OBJECT_UNLOCK (self);
ret = FALSE; ret = FALSE;
self->unset_discont_flag = TRUE; self->unset_discont_flag = TRUE;
self->chain_return_val = gst_pad_push (self->srcpad, sent_buffer); self->chain_return_val = gst_pad_push (self->srcpad, sent_buffer);
@ -481,6 +503,18 @@ gst_rtp_ulpfec_dec_handle_sink_event (GstPad * pad, GstObject * parent,
guint seqnum; guint seqnum;
GstClockTime timestamp, duration; GstClockTime timestamp, duration;
GstStructure *s; GstStructure *s;
gboolean passthrough;
GST_OBJECT_LOCK (self);
passthrough = self->passthrough;
GST_OBJECT_UNLOCK (self);
if (passthrough) {
GST_TRACE_OBJECT (self,
"in passthrough mode, ignoring packet loss event");
forward = TRUE;
goto out;
}
event = gst_event_make_writable (event); event = gst_event_make_writable (event);
s = gst_event_writable_structure (event); s = gst_event_writable_structure (event);
@ -555,6 +589,7 @@ gst_rtp_ulpfec_dec_handle_sink_event (GstPad * pad, GstObject * parent,
self->caps_pt = caps_pt; self->caps_pt = caps_pt;
} }
out:
if (forward) if (forward)
return gst_pad_push_event (self->srcpad, event); return gst_pad_push_event (self->srcpad, event);
gst_event_unref (event); gst_event_unref (event);
@ -577,6 +612,7 @@ gst_rtp_ulpfec_dec_init (GstRtpUlpFecDec * self)
gst_element_add_pad (GST_ELEMENT (self), self->sinkpad); gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
self->fec_pt = DEFAULT_FEC_PT; self->fec_pt = DEFAULT_FEC_PT;
self->passthrough = DEFAULT_PASSTHROUGH;
self->next_seqnum = g_random_int_range (0, G_MAXINT16); self->next_seqnum = g_random_int_range (0, G_MAXINT16);
@ -642,6 +678,20 @@ gst_rtp_ulpfec_dec_set_property (GObject * object, guint prop_id,
if (self->storage) if (self->storage)
g_object_ref (self->storage); g_object_ref (self->storage);
break; break;
case PROP_PASSTHROUGH:{
gboolean newval = g_value_get_boolean (value);
GST_OBJECT_LOCK (self);
/* if we changing into non-passthrough mode, then the sequence numbers may
* be completely different and we need to advertise that with a discont */
GST_INFO_OBJECT (self, "passthrough changing from %u to %u",
self->passthrough, newval);
if (self->passthrough && !newval) {
self->needs_discont = TRUE;
}
self->passthrough = newval;
GST_OBJECT_UNLOCK (self);
break;
}
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -667,6 +717,9 @@ gst_rtp_ulpfec_dec_get_property (GObject * object, guint prop_id,
case PROP_UNRECOVERED: case PROP_UNRECOVERED:
g_value_set_uint (value, (guint) self->packets_unrecovered); g_value_set_uint (value, (guint) self->packets_unrecovered);
break; break;
case PROP_PASSTHROUGH:
g_value_set_boolean (value, self->passthrough);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -712,6 +765,19 @@ gst_rtp_ulpfec_dec_class_init (GstRtpUlpFecDecClass * klass)
g_param_spec_uint ("unrecovered", "unrecovered", g_param_spec_uint ("unrecovered", "unrecovered",
"The number of unrecovered packets", 0, G_MAXUINT, 0, "The number of unrecovered packets", 0, G_MAXUINT, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
/**
* GstRtpUlpFecDec:passthrough:
*
* Whether to push data through without any modification. If passthrough is
* enabled, then no packets will ever be recovered.
*
* Since: 1.22
*/
klass_properties[PROP_PASSTHROUGH] =
g_param_spec_boolean ("passthrough", "Passthrough",
"Whether to passthrough all data as-is without modification and "
"never attempt to recover packets", DEFAULT_PASSTHROUGH,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPERTIES, g_object_class_install_properties (gobject_class, N_PROPERTIES,
klass_properties); klass_properties);

View file

@ -55,10 +55,12 @@ struct _GstRtpUlpFecDec {
RtpStorage *storage; RtpStorage *storage;
gsize packets_recovered; gsize packets_recovered;
gsize packets_unrecovered; gsize packets_unrecovered;
gboolean passthrough;
/* internal stuff */ /* internal stuff */
GstFlowReturn chain_return_val; GstFlowReturn chain_return_val;
gboolean unset_discont_flag; gboolean unset_discont_flag;
gboolean needs_discont;
gboolean have_caps_ssrc; gboolean have_caps_ssrc;
gboolean have_caps_pt; gboolean have_caps_pt;
guint32 caps_ssrc; guint32 caps_ssrc;