mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 03:31:05 +00:00
rtpfunnel: also fallback to pad default handling for unknown ssrcs
If two (or more) rtpfunnel elements are cascaded, then only one will realistically have information on the particular ssrc that is in use for a particular input stream. As such, any key unit requests may never reach the corresponding encoder. This has been discovered by combining simulcast and BUNDLE with webrtcbin. simulcast uses one rtpfunnel, and BUNDLE uses another rtpfunnel. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7405>
This commit is contained in:
parent
e9ab880e66
commit
4802ad8eb6
3 changed files with 58 additions and 6 deletions
|
@ -18730,6 +18730,18 @@
|
||||||
"readable": true,
|
"readable": true,
|
||||||
"type": "gint",
|
"type": "gint",
|
||||||
"writable": true
|
"writable": true
|
||||||
|
},
|
||||||
|
"forward-unknown-ssrc": {
|
||||||
|
"blurb": "Whether to forward events or queries that reference unknown SSRCs",
|
||||||
|
"conditionally-available": false,
|
||||||
|
"construct": false,
|
||||||
|
"construct-only": false,
|
||||||
|
"controllable": false,
|
||||||
|
"default": "false",
|
||||||
|
"mutable": "null",
|
||||||
|
"readable": true,
|
||||||
|
"type": "gboolean",
|
||||||
|
"writable": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rank": "none"
|
"rank": "none"
|
||||||
|
|
|
@ -109,9 +109,11 @@ enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_COMMON_TS_OFFSET,
|
PROP_COMMON_TS_OFFSET,
|
||||||
|
PROP_FORWARD_UNKNOWN_SSRC,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_COMMON_TS_OFFSET -1
|
#define DEFAULT_COMMON_TS_OFFSET -1
|
||||||
|
#define DEFAULT_FORWARD_UNKNOWN_SSRC FALSE
|
||||||
|
|
||||||
struct _GstRtpFunnelClass
|
struct _GstRtpFunnelClass
|
||||||
{
|
{
|
||||||
|
@ -136,6 +138,7 @@ struct _GstRtpFunnel
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
gint common_ts_offset;
|
gint common_ts_offset;
|
||||||
|
gboolean forward_unknown_ssrcs;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RTP_CAPS "application/x-rtp"
|
#define RTP_CAPS "application/x-rtp"
|
||||||
|
@ -529,9 +532,10 @@ gst_rtp_funnel_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
GstPad *fpad;
|
GstPad *fpad;
|
||||||
guint ssrc;
|
guint ssrc;
|
||||||
if (s && gst_structure_get_uint (s, "ssrc", &ssrc)) {
|
if (s && gst_structure_get_uint (s, "ssrc", &ssrc)) {
|
||||||
handled = TRUE;
|
gboolean forward_unknown = FALSE;
|
||||||
|
|
||||||
GST_OBJECT_LOCK (funnel);
|
GST_OBJECT_LOCK (funnel);
|
||||||
|
forward_unknown = funnel->forward_unknown_ssrcs;
|
||||||
fpad = g_hash_table_lookup (funnel->ssrc_to_pad, GUINT_TO_POINTER (ssrc));
|
fpad = g_hash_table_lookup (funnel->ssrc_to_pad, GUINT_TO_POINTER (ssrc));
|
||||||
if (fpad)
|
if (fpad)
|
||||||
gst_object_ref (fpad);
|
gst_object_ref (fpad);
|
||||||
|
@ -542,8 +546,10 @@ gst_rtp_funnel_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
event, fpad);
|
event, fpad);
|
||||||
ret = gst_pad_push_event (fpad, event);
|
ret = gst_pad_push_event (fpad, event);
|
||||||
gst_object_unref (fpad);
|
gst_object_unref (fpad);
|
||||||
} else {
|
handled = TRUE;
|
||||||
|
} else if (!forward_unknown) {
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
|
handled = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -600,6 +606,11 @@ gst_rtp_funnel_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_COMMON_TS_OFFSET:
|
case PROP_COMMON_TS_OFFSET:
|
||||||
funnel->common_ts_offset = g_value_get_int (value);
|
funnel->common_ts_offset = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_FORWARD_UNKNOWN_SSRC:
|
||||||
|
GST_OBJECT_LOCK (funnel);
|
||||||
|
funnel->forward_unknown_ssrcs = g_value_get_boolean (value);
|
||||||
|
GST_OBJECT_UNLOCK (funnel);
|
||||||
|
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;
|
||||||
|
@ -616,6 +627,11 @@ gst_rtp_funnel_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
case PROP_COMMON_TS_OFFSET:
|
case PROP_COMMON_TS_OFFSET:
|
||||||
g_value_set_int (value, funnel->common_ts_offset);
|
g_value_set_int (value, funnel->common_ts_offset);
|
||||||
break;
|
break;
|
||||||
|
case PROP_FORWARD_UNKNOWN_SSRC:
|
||||||
|
GST_OBJECT_LOCK (funnel);
|
||||||
|
g_value_set_boolean (value, funnel->forward_unknown_ssrcs);
|
||||||
|
GST_OBJECT_UNLOCK (funnel);
|
||||||
|
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;
|
||||||
|
@ -706,6 +722,19 @@ gst_rtp_funnel_class_init (GstRtpFunnelClass * klass)
|
||||||
-1, G_MAXINT32, DEFAULT_COMMON_TS_OFFSET,
|
-1, G_MAXINT32, DEFAULT_COMMON_TS_OFFSET,
|
||||||
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rtpfunnel:forward-unknown-ssrc:
|
||||||
|
*
|
||||||
|
* Whether to forward events or queries that reference unknown SSRCs.
|
||||||
|
*
|
||||||
|
* Since: 1.26
|
||||||
|
*/
|
||||||
|
g_object_class_install_property (gobject_class, PROP_FORWARD_UNKNOWN_SSRC,
|
||||||
|
g_param_spec_boolean ("forward-unknown-ssrc", "Forward Unknown SSRC",
|
||||||
|
"Whether to forward events or queries that reference unknown SSRCs",
|
||||||
|
DEFAULT_FORWARD_UNKNOWN_SSRC,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_rtp_funnel_debug,
|
GST_DEBUG_CATEGORY_INIT (gst_rtp_funnel_debug,
|
||||||
"gstrtpfunnel", 0, "funnel element");
|
"gstrtpfunnel", 0, "funnel element");
|
||||||
}
|
}
|
||||||
|
@ -723,4 +752,5 @@ gst_rtp_funnel_init (GstRtpFunnel * funnel)
|
||||||
funnel->srccaps = gst_caps_new_empty_simple (RTP_CAPS);
|
funnel->srccaps = gst_caps_new_empty_simple (RTP_CAPS);
|
||||||
funnel->ssrc_to_pad = g_hash_table_new (NULL, NULL);
|
funnel->ssrc_to_pad = g_hash_table_new (NULL, NULL);
|
||||||
funnel->current_pad = NULL;
|
funnel->current_pad = NULL;
|
||||||
|
funnel->forward_unknown_ssrcs = DEFAULT_FORWARD_UNKNOWN_SSRC;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ GST_START_TEST (rtpfunnel_ssrc_demuxing)
|
||||||
fail_unless_equals_int (2, gst_harness_upstream_events_received (h0));
|
fail_unless_equals_int (2, gst_harness_upstream_events_received (h0));
|
||||||
fail_unless_equals_int (2, gst_harness_upstream_events_received (h1));
|
fail_unless_equals_int (2, gst_harness_upstream_events_received (h1));
|
||||||
|
|
||||||
/* unknown ssrc, we drop it */
|
/* unknown ssrc, we drop it by default */
|
||||||
gst_harness_push_upstream_event (h,
|
gst_harness_push_upstream_event (h,
|
||||||
gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
|
gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
|
||||||
gst_structure_new ("GstForceKeyUnit",
|
gst_structure_new ("GstForceKeyUnit",
|
||||||
|
@ -63,12 +63,22 @@ GST_START_TEST (rtpfunnel_ssrc_demuxing)
|
||||||
fail_unless_equals_int (2, gst_harness_upstream_events_received (h0));
|
fail_unless_equals_int (2, gst_harness_upstream_events_received (h0));
|
||||||
fail_unless_equals_int (2, gst_harness_upstream_events_received (h1));
|
fail_unless_equals_int (2, gst_harness_upstream_events_received (h1));
|
||||||
|
|
||||||
|
/* unknown ssrc, we forward if property says to */
|
||||||
|
g_object_set (h->element, "forward-unknown-ssrc", TRUE, NULL);
|
||||||
|
gst_harness_push_upstream_event (h,
|
||||||
|
gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
|
||||||
|
gst_structure_new ("GstForceKeyUnit",
|
||||||
|
"ssrc", G_TYPE_UINT, 666, NULL)));
|
||||||
|
fail_unless_equals_int (3, gst_harness_upstream_events_received (h0));
|
||||||
|
fail_unless_equals_int (3, gst_harness_upstream_events_received (h1));
|
||||||
|
g_object_set (h->element, "forward-unknown-ssrc", FALSE, NULL);
|
||||||
|
|
||||||
/* no ssrc, we send to all */
|
/* no ssrc, we send to all */
|
||||||
gst_harness_push_upstream_event (h,
|
gst_harness_push_upstream_event (h,
|
||||||
gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
|
gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
|
||||||
gst_structure_new_empty ("GstForceKeyUnit")));
|
gst_structure_new_empty ("GstForceKeyUnit")));
|
||||||
fail_unless_equals_int (3, gst_harness_upstream_events_received (h0));
|
fail_unless_equals_int (4, gst_harness_upstream_events_received (h0));
|
||||||
fail_unless_equals_int (3, gst_harness_upstream_events_received (h1));
|
fail_unless_equals_int (4, gst_harness_upstream_events_received (h1));
|
||||||
|
|
||||||
/* remove pad 0, and send an event referencing the now dead ssrc */
|
/* remove pad 0, and send an event referencing the now dead ssrc */
|
||||||
gst_harness_teardown (h0);
|
gst_harness_teardown (h0);
|
||||||
|
@ -76,7 +86,7 @@ GST_START_TEST (rtpfunnel_ssrc_demuxing)
|
||||||
gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
|
gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
|
||||||
gst_structure_new ("GstForceKeyUnit",
|
gst_structure_new ("GstForceKeyUnit",
|
||||||
"ssrc", G_TYPE_UINT, 123, NULL)));
|
"ssrc", G_TYPE_UINT, 123, NULL)));
|
||||||
fail_unless_equals_int (3, gst_harness_upstream_events_received (h1));
|
fail_unless_equals_int (4, gst_harness_upstream_events_received (h1));
|
||||||
|
|
||||||
gst_harness_teardown (h);
|
gst_harness_teardown (h);
|
||||||
gst_harness_teardown (h1);
|
gst_harness_teardown (h1);
|
||||||
|
|
Loading…
Reference in a new issue