mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
gstrtpmux: allow the ssrc-property to decide ssrc on outgoing buffers
By not doing this, the muxer is not effectively a rtpmuxer, rather a funnel, since it should be a single stream that exists the muxer. If not specified, take the first ssrc seen on a sinkpad, allowing upstream to decide ssrc in "passthrough" with only one sinkpad. Also, let downstream ssrc overrule internal configured one We hence has the following order for determining the ssrc used by rtpmux: 0. Suggestion from GstRTPCollision event 1. Downstream caps 2. ssrc-Property 3. (First) upstream caps containing ssrc 4. Randomly generated https://bugzilla.gnome.org/show_bug.cgi?id=752694
This commit is contained in:
parent
41a82b9706
commit
d5e26ab909
3 changed files with 333 additions and 39 deletions
|
@ -158,7 +158,8 @@ gst_rtp_mux_class_init (GstRTPMuxClass * klass)
|
||||||
g_param_spec_uint ("ssrc", "SSRC",
|
g_param_spec_uint ("ssrc", "SSRC",
|
||||||
"The SSRC of the packets (-1 == random)",
|
"The SSRC of the packets (-1 == random)",
|
||||||
0, G_MAXUINT, DEFAULT_SSRC,
|
0, G_MAXUINT, DEFAULT_SSRC,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE |
|
||||||
|
G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
gstelement_class->request_new_pad =
|
gstelement_class->request_new_pad =
|
||||||
GST_DEBUG_FUNCPTR (gst_rtp_mux_request_new_pad);
|
GST_DEBUG_FUNCPTR (gst_rtp_mux_request_new_pad);
|
||||||
|
@ -207,6 +208,51 @@ gst_rtp_mux_src_event_real (GstRTPMux * rtp_mux, GstEvent * event)
|
||||||
gboolean result = FALSE;
|
gboolean result = FALSE;
|
||||||
gboolean done = FALSE;
|
gboolean done = FALSE;
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_CUSTOM_UPSTREAM:
|
||||||
|
{
|
||||||
|
const GstStructure *s = gst_event_get_structure (event);
|
||||||
|
|
||||||
|
if (gst_structure_has_name (s, "GstRTPCollision")) {
|
||||||
|
guint ssrc = 0;
|
||||||
|
|
||||||
|
if (!gst_structure_get_uint (s, "ssrc", &ssrc))
|
||||||
|
ssrc = -1;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (rtp_mux, "collided ssrc: %" G_GUINT32_FORMAT, ssrc);
|
||||||
|
|
||||||
|
/* choose another ssrc for our stream */
|
||||||
|
GST_OBJECT_LOCK (rtp_mux);
|
||||||
|
if (ssrc == rtp_mux->current_ssrc) {
|
||||||
|
GstCaps *caps;
|
||||||
|
guint suggested_ssrc = 0;
|
||||||
|
guint32 new_ssrc;
|
||||||
|
|
||||||
|
if (gst_structure_get_uint (s, "suggested-ssrc", &suggested_ssrc))
|
||||||
|
rtp_mux->current_ssrc = suggested_ssrc;
|
||||||
|
|
||||||
|
while (ssrc == rtp_mux->current_ssrc)
|
||||||
|
rtp_mux->current_ssrc = g_random_int ();
|
||||||
|
|
||||||
|
new_ssrc = rtp_mux->current_ssrc;
|
||||||
|
GST_OBJECT_UNLOCK (rtp_mux);
|
||||||
|
|
||||||
|
caps = gst_pad_get_current_caps (rtp_mux->srcpad);
|
||||||
|
caps = gst_caps_make_writable (caps);
|
||||||
|
gst_caps_set_simple (caps, "ssrc", G_TYPE_UINT, new_ssrc, NULL);
|
||||||
|
gst_pad_set_caps (rtp_mux->srcpad, caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
} else {
|
||||||
|
GST_OBJECT_UNLOCK (rtp_mux);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
iter = gst_element_iterate_sink_pads (GST_ELEMENT (rtp_mux));
|
iter = gst_element_iterate_sink_pads (GST_ELEMENT (rtp_mux));
|
||||||
|
|
||||||
while (!done) {
|
while (!done) {
|
||||||
|
@ -249,6 +295,7 @@ gst_rtp_mux_init (GstRTPMux * rtp_mux)
|
||||||
gst_element_add_pad (GST_ELEMENT (rtp_mux), rtp_mux->srcpad);
|
gst_element_add_pad (GST_ELEMENT (rtp_mux), rtp_mux->srcpad);
|
||||||
|
|
||||||
rtp_mux->ssrc = DEFAULT_SSRC;
|
rtp_mux->ssrc = DEFAULT_SSRC;
|
||||||
|
rtp_mux->current_ssrc = DEFAULT_SSRC;
|
||||||
rtp_mux->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
|
rtp_mux->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
|
||||||
rtp_mux->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
|
rtp_mux->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
|
||||||
|
|
||||||
|
@ -414,6 +461,17 @@ gst_rtp_mux_chain_list (GstPad * pad, GstObject * parent,
|
||||||
|
|
||||||
rtp_mux = GST_RTP_MUX (parent);
|
rtp_mux = GST_RTP_MUX (parent);
|
||||||
|
|
||||||
|
if (gst_pad_check_reconfigure (rtp_mux->srcpad)) {
|
||||||
|
GstCaps *current_caps = gst_pad_get_current_caps (pad);
|
||||||
|
|
||||||
|
if (!gst_rtp_mux_setcaps (pad, rtp_mux, current_caps)) {
|
||||||
|
ret = GST_FLOW_NOT_NEGOTIATED;
|
||||||
|
gst_buffer_list_unref (bufferlist);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
gst_caps_unref (current_caps);
|
||||||
|
}
|
||||||
|
|
||||||
GST_OBJECT_LOCK (rtp_mux);
|
GST_OBJECT_LOCK (rtp_mux);
|
||||||
|
|
||||||
padpriv = gst_pad_get_element_private (pad);
|
padpriv = gst_pad_get_element_private (pad);
|
||||||
|
@ -472,7 +530,18 @@ gst_rtp_mux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
||||||
gboolean changed = FALSE;
|
gboolean changed = FALSE;
|
||||||
GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
|
GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
|
||||||
|
|
||||||
rtp_mux = GST_RTP_MUX (GST_OBJECT_PARENT (pad));
|
rtp_mux = GST_RTP_MUX (parent);
|
||||||
|
|
||||||
|
if (gst_pad_check_reconfigure (rtp_mux->srcpad)) {
|
||||||
|
GstCaps *current_caps = gst_pad_get_current_caps (pad);
|
||||||
|
|
||||||
|
if (!gst_rtp_mux_setcaps (pad, rtp_mux, current_caps)) {
|
||||||
|
ret = GST_FLOW_NOT_NEGOTIATED;
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
gst_caps_unref (current_caps);
|
||||||
|
}
|
||||||
|
|
||||||
GST_OBJECT_LOCK (rtp_mux);
|
GST_OBJECT_LOCK (rtp_mux);
|
||||||
padpriv = gst_pad_get_element_private (pad);
|
padpriv = gst_pad_get_element_private (pad);
|
||||||
|
@ -523,6 +592,7 @@ gst_rtp_mux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
||||||
ret = gst_pad_push (rtp_mux->srcpad, buffer);
|
ret = gst_pad_push (rtp_mux->srcpad, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,6 +602,34 @@ gst_rtp_mux_setcaps (GstPad * pad, GstRTPMux * rtp_mux, GstCaps * caps)
|
||||||
GstStructure *structure;
|
GstStructure *structure;
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
GstRTPMuxPadPrivate *padpriv;
|
GstRTPMuxPadPrivate *padpriv;
|
||||||
|
GstCaps *peercaps;
|
||||||
|
|
||||||
|
if (!gst_caps_is_fixed (caps))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
peercaps = gst_pad_peer_query_caps (rtp_mux->srcpad, NULL);
|
||||||
|
if (peercaps) {
|
||||||
|
GstCaps *tcaps, *othercaps;;
|
||||||
|
tcaps = gst_pad_get_pad_template_caps (pad);
|
||||||
|
othercaps = gst_caps_intersect_full (peercaps, tcaps,
|
||||||
|
GST_CAPS_INTERSECT_FIRST);
|
||||||
|
|
||||||
|
if (gst_caps_get_size (othercaps) > 0) {
|
||||||
|
structure = gst_caps_get_structure (othercaps, 0);
|
||||||
|
GST_OBJECT_LOCK (rtp_mux);
|
||||||
|
if (gst_structure_get_uint (structure, "ssrc", &rtp_mux->current_ssrc)) {
|
||||||
|
GST_DEBUG_OBJECT (pad, "Use downstream ssrc: %x",
|
||||||
|
rtp_mux->current_ssrc);
|
||||||
|
rtp_mux->have_ssrc = TRUE;
|
||||||
|
}
|
||||||
|
GST_OBJECT_UNLOCK (rtp_mux);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_caps_unref (othercaps);
|
||||||
|
|
||||||
|
gst_caps_unref (peercaps);
|
||||||
|
gst_caps_unref (tcaps);
|
||||||
|
}
|
||||||
|
|
||||||
structure = gst_caps_get_structure (caps, 0);
|
structure = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
|
@ -545,13 +643,25 @@ gst_rtp_mux_setcaps (GstPad * pad, GstRTPMux * rtp_mux, GstCaps * caps)
|
||||||
&padpriv->timestamp_offset)) {
|
&padpriv->timestamp_offset)) {
|
||||||
padpriv->have_timestamp_offset = TRUE;
|
padpriv->have_timestamp_offset = TRUE;
|
||||||
}
|
}
|
||||||
GST_OBJECT_UNLOCK (rtp_mux);
|
|
||||||
|
|
||||||
caps = gst_caps_copy (caps);
|
caps = gst_caps_copy (caps);
|
||||||
|
|
||||||
|
/* if we don't have a specified ssrc, first try to take one from the caps,
|
||||||
|
and if that fails, generate one */
|
||||||
|
if (!rtp_mux->have_ssrc) {
|
||||||
|
if (rtp_mux->ssrc == DEFAULT_SSRC) {
|
||||||
|
if (!gst_structure_get_uint (structure, "ssrc", &rtp_mux->current_ssrc))
|
||||||
|
rtp_mux->current_ssrc = g_random_int ();
|
||||||
|
rtp_mux->have_ssrc = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gst_caps_set_simple (caps,
|
gst_caps_set_simple (caps,
|
||||||
"timestamp-offset", G_TYPE_UINT, rtp_mux->ts_base,
|
"timestamp-offset", G_TYPE_UINT, rtp_mux->ts_base,
|
||||||
"seqnum-offset", G_TYPE_UINT, rtp_mux->seqnum_base, NULL);
|
"seqnum-offset", G_TYPE_UINT, rtp_mux->seqnum_base,
|
||||||
|
"ssrc", G_TYPE_UINT, rtp_mux->current_ssrc, NULL);
|
||||||
|
|
||||||
|
GST_OBJECT_UNLOCK (rtp_mux);
|
||||||
|
|
||||||
if (rtp_mux->send_stream_start) {
|
if (rtp_mux->send_stream_start) {
|
||||||
gchar s_id[32];
|
gchar s_id[32];
|
||||||
|
@ -567,7 +677,6 @@ gst_rtp_mux_setcaps (GstPad * pad, GstRTPMux * rtp_mux, GstCaps * caps)
|
||||||
"setting caps %" GST_PTR_FORMAT " on src pad..", caps);
|
"setting caps %" GST_PTR_FORMAT " on src pad..", caps);
|
||||||
ret = gst_pad_set_caps (rtp_mux->srcpad, caps);
|
ret = gst_pad_set_caps (rtp_mux->srcpad, caps);
|
||||||
|
|
||||||
gst_structure_get_uint (structure, "ssrc", &rtp_mux->current_ssrc);
|
|
||||||
|
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
@ -630,9 +739,8 @@ gst_rtp_mux_getcaps (GstPad * pad, GstRTPMux * mux, GstCaps * filter)
|
||||||
GstCaps *peercaps;
|
GstCaps *peercaps;
|
||||||
GstCaps *othercaps;
|
GstCaps *othercaps;
|
||||||
GstCaps *tcaps;
|
GstCaps *tcaps;
|
||||||
GstCaps *other_filtered;
|
|
||||||
|
|
||||||
peercaps = gst_pad_peer_query_caps (mux->srcpad, filter);
|
peercaps = gst_pad_peer_query_caps (mux->srcpad, NULL);
|
||||||
|
|
||||||
if (peercaps) {
|
if (peercaps) {
|
||||||
tcaps = gst_pad_get_pad_template_caps (pad);
|
tcaps = gst_pad_get_pad_template_caps (pad);
|
||||||
|
@ -649,21 +757,20 @@ gst_rtp_mux_getcaps (GstPad * pad, GstRTPMux * mux, GstCaps * filter)
|
||||||
}
|
}
|
||||||
gst_caps_unref (tcaps);
|
gst_caps_unref (tcaps);
|
||||||
|
|
||||||
clear_caps (othercaps, FALSE);
|
GST_LOG_OBJECT (pad, "Intersected srcpad-peercaps and template caps: %"
|
||||||
|
GST_PTR_FORMAT, othercaps);
|
||||||
|
|
||||||
other_filtered = gst_caps_copy (othercaps);
|
clear_caps (othercaps, TRUE);
|
||||||
clear_caps (other_filtered, TRUE);
|
|
||||||
|
|
||||||
g_value_init (&v, GST_TYPE_CAPS);
|
g_value_init (&v, GST_TYPE_CAPS);
|
||||||
|
|
||||||
iter = gst_element_iterate_sink_pads (GST_ELEMENT (mux));
|
iter = gst_element_iterate_sink_pads (GST_ELEMENT (mux));
|
||||||
do {
|
do {
|
||||||
gst_value_set_caps (&v, other_filtered);
|
gst_value_set_caps (&v, othercaps);
|
||||||
res = gst_iterator_fold (iter, same_clock_rate_fold, &v, pad);
|
res = gst_iterator_fold (iter, same_clock_rate_fold, &v, pad);
|
||||||
gst_iterator_resync (iter);
|
gst_iterator_resync (iter);
|
||||||
} while (res == GST_ITERATOR_RESYNC);
|
} while (res == GST_ITERATOR_RESYNC);
|
||||||
gst_iterator_free (iter);
|
gst_iterator_free (iter);
|
||||||
gst_caps_unref (other_filtered);
|
|
||||||
|
|
||||||
caps = gst_caps_intersect ((GstCaps *) gst_value_get_caps (&v), othercaps);
|
caps = gst_caps_intersect ((GstCaps *) gst_value_get_caps (&v), othercaps);
|
||||||
|
|
||||||
|
@ -691,8 +798,12 @@ gst_rtp_mux_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
||||||
GstCaps *filter, *caps;
|
GstCaps *filter, *caps;
|
||||||
|
|
||||||
gst_query_parse_caps (query, &filter);
|
gst_query_parse_caps (query, &filter);
|
||||||
|
GST_LOG_OBJECT (pad, "Received caps-query with filter-caps: %"
|
||||||
|
GST_PTR_FORMAT, filter);
|
||||||
caps = gst_rtp_mux_getcaps (pad, mux, filter);
|
caps = gst_rtp_mux_getcaps (pad, mux, filter);
|
||||||
gst_query_set_caps_result (query, caps);
|
gst_query_set_caps_result (query, caps);
|
||||||
|
GST_LOG_OBJECT (mux, "Answering caps-query with caps: %"
|
||||||
|
GST_PTR_FORMAT, caps);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
break;
|
break;
|
||||||
|
@ -703,11 +814,8 @@ gst_rtp_mux_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtp_mux_get_property (GObject * object,
|
gst_rtp_mux_get_property (GObject * object,
|
||||||
guint prop_id, GValue * value, GParamSpec * pspec)
|
guint prop_id, GValue * value, GParamSpec * pspec)
|
||||||
|
@ -716,6 +824,7 @@ gst_rtp_mux_get_property (GObject * object,
|
||||||
|
|
||||||
rtp_mux = GST_RTP_MUX (object);
|
rtp_mux = GST_RTP_MUX (object);
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (rtp_mux);
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_TIMESTAMP_OFFSET:
|
case PROP_TIMESTAMP_OFFSET:
|
||||||
g_value_set_int (value, rtp_mux->ts_offset);
|
g_value_set_int (value, rtp_mux->ts_offset);
|
||||||
|
@ -724,9 +833,7 @@ gst_rtp_mux_get_property (GObject * object,
|
||||||
g_value_set_int (value, rtp_mux->seqnum_offset);
|
g_value_set_int (value, rtp_mux->seqnum_offset);
|
||||||
break;
|
break;
|
||||||
case PROP_SEQNUM:
|
case PROP_SEQNUM:
|
||||||
GST_OBJECT_LOCK (rtp_mux);
|
|
||||||
g_value_set_uint (value, rtp_mux->seqnum);
|
g_value_set_uint (value, rtp_mux->seqnum);
|
||||||
GST_OBJECT_UNLOCK (rtp_mux);
|
|
||||||
break;
|
break;
|
||||||
case PROP_SSRC:
|
case PROP_SSRC:
|
||||||
g_value_set_uint (value, rtp_mux->ssrc);
|
g_value_set_uint (value, rtp_mux->ssrc);
|
||||||
|
@ -735,6 +842,7 @@ gst_rtp_mux_get_property (GObject * object,
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
GST_OBJECT_UNLOCK (rtp_mux);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -753,7 +861,11 @@ gst_rtp_mux_set_property (GObject * object,
|
||||||
rtp_mux->seqnum_offset = g_value_get_int (value);
|
rtp_mux->seqnum_offset = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
case PROP_SSRC:
|
case PROP_SSRC:
|
||||||
|
GST_OBJECT_LOCK (rtp_mux);
|
||||||
rtp_mux->ssrc = g_value_get_uint (value);
|
rtp_mux->ssrc = g_value_get_uint (value);
|
||||||
|
rtp_mux->current_ssrc = rtp_mux->ssrc;
|
||||||
|
rtp_mux->have_ssrc = TRUE;
|
||||||
|
GST_OBJECT_UNLOCK (rtp_mux);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
@ -774,6 +886,8 @@ gst_rtp_mux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
|
|
||||||
gst_event_parse_caps (event, &caps);
|
gst_event_parse_caps (event, &caps);
|
||||||
|
GST_LOG_OBJECT (pad, "Received caps-event with caps: %"
|
||||||
|
GST_PTR_FORMAT, caps);
|
||||||
ret = gst_rtp_mux_setcaps (pad, mux, caps);
|
ret = gst_rtp_mux_setcaps (pad, mux, caps);
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -823,11 +937,6 @@ gst_rtp_mux_ready_to_paused (GstRTPMux * rtp_mux)
|
||||||
g_clear_object (&rtp_mux->last_pad);
|
g_clear_object (&rtp_mux->last_pad);
|
||||||
rtp_mux->send_stream_start = TRUE;
|
rtp_mux->send_stream_start = TRUE;
|
||||||
|
|
||||||
if (rtp_mux->ssrc == -1)
|
|
||||||
rtp_mux->current_ssrc = g_random_int ();
|
|
||||||
else
|
|
||||||
rtp_mux->current_ssrc = rtp_mux->ssrc;
|
|
||||||
|
|
||||||
if (rtp_mux->seqnum_offset == -1)
|
if (rtp_mux->seqnum_offset == -1)
|
||||||
rtp_mux->seqnum_base = g_random_int_range (0, G_MAXUINT16);
|
rtp_mux->seqnum_base = g_random_int_range (0, G_MAXUINT16);
|
||||||
else
|
else
|
||||||
|
@ -841,6 +950,13 @@ gst_rtp_mux_ready_to_paused (GstRTPMux * rtp_mux)
|
||||||
|
|
||||||
rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
|
rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
|
if (rtp_mux->ssrc == DEFAULT_SSRC) {
|
||||||
|
rtp_mux->have_ssrc = FALSE;
|
||||||
|
} else {
|
||||||
|
rtp_mux->current_ssrc = rtp_mux->ssrc;
|
||||||
|
rtp_mux->have_ssrc = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (rtp_mux, "set timestamp-offset to %u", rtp_mux->ts_base);
|
GST_DEBUG_OBJECT (rtp_mux, "set timestamp-offset to %u", rtp_mux->ts_base);
|
||||||
|
|
||||||
GST_OBJECT_UNLOCK (rtp_mux);
|
GST_OBJECT_UNLOCK (rtp_mux);
|
||||||
|
|
|
@ -71,6 +71,7 @@ struct _GstRTPMux
|
||||||
guint16 seqnum; /* protected by object lock */
|
guint16 seqnum; /* protected by object lock */
|
||||||
guint ssrc;
|
guint ssrc;
|
||||||
guint current_ssrc;
|
guint current_ssrc;
|
||||||
|
gboolean have_ssrc;
|
||||||
|
|
||||||
GstPad *last_pad; /* protected by object lock */
|
GstPad *last_pad; /* protected by object lock */
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,15 @@ query_func (GstPad * pad, GstObject * noparent, GstQuery * query)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstCaps *
|
||||||
|
remove_ssrc_from_caps (GstCaps * caps)
|
||||||
|
{
|
||||||
|
GstCaps *copy = gst_caps_copy (caps);
|
||||||
|
GstStructure *s = gst_caps_get_structure (copy, 0);
|
||||||
|
gst_structure_remove_field (s, "ssrc");
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
event_func (GstPad * pad, GstObject * noparent, GstEvent * event)
|
event_func (GstPad * pad, GstObject * noparent, GstEvent * event)
|
||||||
{
|
{
|
||||||
|
@ -69,12 +78,20 @@ event_func (GstPad * pad, GstObject * noparent, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
GstCaps **caps2 = g_object_get_data (G_OBJECT (pad), "caps");
|
GstCaps **caps2 = g_object_get_data (G_OBJECT (pad), "caps");
|
||||||
|
GstCaps *caps_no_ssrc;
|
||||||
|
GstCaps *caps2_no_ssrc;
|
||||||
|
|
||||||
gst_event_parse_caps (event, &caps);
|
gst_event_parse_caps (event, &caps);
|
||||||
|
caps_no_ssrc = remove_ssrc_from_caps (caps);
|
||||||
|
caps2_no_ssrc = remove_ssrc_from_caps (*caps2);
|
||||||
|
|
||||||
fail_unless (caps2 != NULL && *caps2 != NULL);
|
fail_unless (caps2 != NULL && *caps2 != NULL);
|
||||||
fail_unless (gst_caps_is_fixed (caps));
|
fail_unless (gst_caps_is_fixed (caps));
|
||||||
fail_unless (gst_caps_is_fixed (*caps2));
|
fail_unless (gst_caps_is_fixed (*caps2));
|
||||||
fail_unless (gst_caps_is_equal_fixed (caps, *caps2));
|
|
||||||
|
fail_unless (gst_caps_is_equal_fixed (caps_no_ssrc, caps2_no_ssrc));
|
||||||
|
gst_caps_unref (caps_no_ssrc);
|
||||||
|
gst_caps_unref (caps2_no_ssrc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -137,7 +154,6 @@ test_basic (const gchar * elem_name, const gchar * sink2, int count,
|
||||||
|
|
||||||
gst_caps_set_simple (src2caps, "clock-rate", G_TYPE_INT, 3, NULL);
|
gst_caps_set_simple (src2caps, "clock-rate", G_TYPE_INT, 3, NULL);
|
||||||
caps = gst_pad_peer_query_caps (src1, NULL);
|
caps = gst_pad_peer_query_caps (src1, NULL);
|
||||||
fail_unless (gst_caps_is_equal (caps, sinkcaps));
|
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
g_object_set (rtpmux, "seqnum-offset", 100, "timestamp-offset", 1000,
|
g_object_set (rtpmux, "seqnum-offset", 100, "timestamp-offset", 1000,
|
||||||
|
@ -231,10 +247,10 @@ basic_check_cb (GstPad * pad, int i)
|
||||||
fail_unless (buffers && g_list_length (buffers) == 1);
|
fail_unless (buffers && g_list_length (buffers) == 1);
|
||||||
|
|
||||||
gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
|
gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
|
||||||
fail_unless (gst_rtp_buffer_get_ssrc (&rtpbuffer) == 66);
|
fail_unless_equals_int (66, gst_rtp_buffer_get_ssrc (&rtpbuffer));
|
||||||
fail_unless (gst_rtp_buffer_get_timestamp (&rtpbuffer) ==
|
fail_unless_equals_int64 (200 - 57 + 1000 + i,
|
||||||
200 - 57 + 1000 + i);
|
gst_rtp_buffer_get_timestamp (&rtpbuffer));
|
||||||
fail_unless (gst_rtp_buffer_get_seq (&rtpbuffer) == 100 + 1 + i);
|
fail_unless_equals_int (100 + 1 + i, gst_rtp_buffer_get_seq (&rtpbuffer));
|
||||||
gst_rtp_buffer_unmap (&rtpbuffer);
|
gst_rtp_buffer_unmap (&rtpbuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,10 +281,10 @@ lock_check_cb (GstPad * pad, int i)
|
||||||
|
|
||||||
fail_unless (buffers && g_list_length (buffers) == 1);
|
fail_unless (buffers && g_list_length (buffers) == 1);
|
||||||
gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
|
gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
|
||||||
fail_unless (gst_rtp_buffer_get_ssrc (&rtpbuffer) == 66);
|
fail_unless_equals_int (66, gst_rtp_buffer_get_ssrc (&rtpbuffer));
|
||||||
fail_unless (gst_rtp_buffer_get_timestamp (&rtpbuffer) ==
|
fail_unless_equals_int64 (200 - 57 + 1000 + i,
|
||||||
200 - 57 + 1000 + i);
|
gst_rtp_buffer_get_timestamp (&rtpbuffer));
|
||||||
fail_unless (gst_rtp_buffer_get_seq (&rtpbuffer) == 100 + 1 + i);
|
fail_unless_equals_int (100 + 1 + i, gst_rtp_buffer_get_seq (&rtpbuffer));
|
||||||
gst_rtp_buffer_unmap (&rtpbuffer);
|
gst_rtp_buffer_unmap (&rtpbuffer);
|
||||||
|
|
||||||
inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
|
inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
|
||||||
|
@ -325,16 +341,63 @@ generate_test_buffer (guint seq_num, guint ssrc)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_START_TEST (test_rtpmux_ssrc)
|
static guint32
|
||||||
|
_rtp_buffer_get_ssrc (GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstHarness * h = gst_harness_new_with_padnames ("rtpdtmfmux", NULL, "src");
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
||||||
GstHarness * h0 = gst_harness_new_with_element (
|
guint32 ret;
|
||||||
h->element, "sink_0", NULL);
|
g_assert (gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp));
|
||||||
GstHarness * h1 = gst_harness_new_with_element (
|
ret = gst_rtp_buffer_get_ssrc (&rtp);
|
||||||
h->element, "sink_1", NULL);
|
gst_rtp_buffer_unmap (&rtp);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_START_TEST (test_rtpmux_ssrc_property)
|
||||||
|
{
|
||||||
|
GstHarness *h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
|
||||||
|
GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
|
||||||
|
GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
|
||||||
|
GstBuffer *buf0;
|
||||||
|
GstBuffer *buf1;
|
||||||
|
|
||||||
|
/* set ssrc to 111111 */
|
||||||
g_object_set (h->element, "ssrc", 111111, NULL);
|
g_object_set (h->element, "ssrc", 111111, NULL);
|
||||||
|
|
||||||
|
/* both sinkpads have their own idea of what the ssrc should be */
|
||||||
|
gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
|
||||||
|
gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
|
||||||
|
|
||||||
|
/* push on both sinkpads with different ssrc */
|
||||||
|
fail_unless_equals_int (GST_FLOW_OK,
|
||||||
|
gst_harness_push (h0, generate_test_buffer (0, 222222)));
|
||||||
|
fail_unless_equals_int (GST_FLOW_OK,
|
||||||
|
gst_harness_push (h1, generate_test_buffer (0, 333333)));
|
||||||
|
|
||||||
|
buf0 = gst_harness_pull (h);
|
||||||
|
buf1 = gst_harness_pull (h);
|
||||||
|
|
||||||
|
/* we expect the ssrc to be what we specified in the property */
|
||||||
|
fail_unless_equals_int (111111, _rtp_buffer_get_ssrc (buf0));
|
||||||
|
fail_unless_equals_int (111111, _rtp_buffer_get_ssrc (buf1));
|
||||||
|
|
||||||
|
gst_buffer_unref (buf0);
|
||||||
|
gst_buffer_unref (buf1);
|
||||||
|
|
||||||
|
gst_harness_teardown (h0);
|
||||||
|
gst_harness_teardown (h1);
|
||||||
|
gst_harness_teardown (h);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (test_rtpmux_ssrc_property_not_set)
|
||||||
|
{
|
||||||
|
GstHarness *h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
|
||||||
|
GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
|
||||||
|
GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
|
||||||
|
GstBuffer *buf0;
|
||||||
|
GstBuffer *buf1;
|
||||||
|
|
||||||
gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
|
gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
|
||||||
gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
|
gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
|
||||||
|
|
||||||
|
@ -343,10 +406,121 @@ GST_START_TEST (test_rtpmux_ssrc)
|
||||||
fail_unless_equals_int (GST_FLOW_OK,
|
fail_unless_equals_int (GST_FLOW_OK,
|
||||||
gst_harness_push (h1, generate_test_buffer (0, 333333)));
|
gst_harness_push (h1, generate_test_buffer (0, 333333)));
|
||||||
|
|
||||||
|
buf0 = gst_harness_pull (h);
|
||||||
|
buf1 = gst_harness_pull (h);
|
||||||
|
|
||||||
|
/* we expect the ssrc to be the first ssrc that came in */
|
||||||
|
fail_unless_equals_int (222222, _rtp_buffer_get_ssrc (buf0));
|
||||||
|
fail_unless_equals_int (222222, _rtp_buffer_get_ssrc (buf1));
|
||||||
|
|
||||||
|
gst_buffer_unref (buf0);
|
||||||
|
gst_buffer_unref (buf1);
|
||||||
|
|
||||||
gst_harness_teardown (h0);
|
gst_harness_teardown (h0);
|
||||||
gst_harness_teardown (h1);
|
gst_harness_teardown (h1);
|
||||||
gst_harness_teardown (h);
|
gst_harness_teardown (h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (test_rtpmux_ssrc_downstream_can_overrule)
|
||||||
|
{
|
||||||
|
GstHarness *h = gst_harness_new_with_padnames ("rtpmux", NULL, "src");
|
||||||
|
GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
|
||||||
|
GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
|
||||||
|
GstBuffer *buf0;
|
||||||
|
GstBuffer *buf1;
|
||||||
|
|
||||||
|
/* downstream is specifying 444444 as ssrc */
|
||||||
|
gst_harness_set_sink_caps_str (h, "application/x-rtp, ssrc=(uint)444444");
|
||||||
|
|
||||||
|
/* rtpmux ssrc is set to 111111 */
|
||||||
|
g_object_set (h->element, "ssrc", 111111, NULL);
|
||||||
|
|
||||||
|
/* while upstream ssrc is 222222 and 333333 */
|
||||||
|
gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
|
||||||
|
gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
|
||||||
|
|
||||||
|
fail_unless_equals_int (GST_FLOW_OK,
|
||||||
|
gst_harness_push (h0, generate_test_buffer (0, 222222)));
|
||||||
|
fail_unless_equals_int (GST_FLOW_OK,
|
||||||
|
gst_harness_push (h1, generate_test_buffer (0, 333333)));
|
||||||
|
|
||||||
|
buf0 = gst_harness_pull (h);
|
||||||
|
buf1 = gst_harness_pull (h);
|
||||||
|
|
||||||
|
/* we expect the ssrc to be downstream ssrc */
|
||||||
|
fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf0));
|
||||||
|
fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf1));
|
||||||
|
|
||||||
|
gst_buffer_unref (buf0);
|
||||||
|
gst_buffer_unref (buf1);
|
||||||
|
|
||||||
|
gst_harness_teardown (h0);
|
||||||
|
gst_harness_teardown (h1);
|
||||||
|
gst_harness_teardown (h);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (test_rtpmux_ssrc_downstream_dynamic)
|
||||||
|
{
|
||||||
|
GstHarness *h = gst_harness_new_parse ("rtpmux ! capsfilter");
|
||||||
|
GstElement *rtpmux = gst_harness_find_element (h, "rtpmux");
|
||||||
|
GstElement *capsfilter = gst_harness_find_element (h, "capsfilter");
|
||||||
|
|
||||||
|
GstHarness *h0 = gst_harness_new_with_element (rtpmux, "sink_0", NULL);
|
||||||
|
GstHarness *h1 = gst_harness_new_with_element (rtpmux, "sink_1", NULL);
|
||||||
|
GstCaps *caps;
|
||||||
|
GstBuffer *buf0;
|
||||||
|
GstBuffer *buf1;
|
||||||
|
|
||||||
|
gst_harness_play (h);
|
||||||
|
|
||||||
|
caps = gst_caps_from_string ("application/x-rtp, ssrc=(uint)444444");
|
||||||
|
g_object_set (capsfilter, "caps", caps, NULL);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
/* while upstream ssrc is 222222 and 333333 */
|
||||||
|
gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)222222");
|
||||||
|
gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)333333");
|
||||||
|
|
||||||
|
fail_unless_equals_int (GST_FLOW_OK,
|
||||||
|
gst_harness_push (h0, generate_test_buffer (0, 222222)));
|
||||||
|
fail_unless_equals_int (GST_FLOW_OK,
|
||||||
|
gst_harness_push (h1, generate_test_buffer (0, 333333)));
|
||||||
|
|
||||||
|
/* we expect the ssrc to be downstream ssrc (444444) */
|
||||||
|
buf0 = gst_harness_pull (h);
|
||||||
|
buf1 = gst_harness_pull (h);
|
||||||
|
fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf0));
|
||||||
|
fail_unless_equals_int (444444, _rtp_buffer_get_ssrc (buf1));
|
||||||
|
gst_buffer_unref (buf0);
|
||||||
|
gst_buffer_unref (buf1);
|
||||||
|
|
||||||
|
caps = gst_caps_from_string ("application/x-rtp, ssrc=(uint)555555");
|
||||||
|
g_object_set (capsfilter, "caps", caps, NULL);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
fail_unless_equals_int (GST_FLOW_OK,
|
||||||
|
gst_harness_push (h0, generate_test_buffer (0, 222222)));
|
||||||
|
fail_unless_equals_int (GST_FLOW_OK,
|
||||||
|
gst_harness_push (h1, generate_test_buffer (0, 333333)));
|
||||||
|
|
||||||
|
/* we expect the ssrc to be the new downstream ssrc (555555) */
|
||||||
|
buf0 = gst_harness_pull (h);
|
||||||
|
buf1 = gst_harness_pull (h);
|
||||||
|
fail_unless_equals_int (555555, _rtp_buffer_get_ssrc (buf0));
|
||||||
|
fail_unless_equals_int (555555, _rtp_buffer_get_ssrc (buf1));
|
||||||
|
gst_buffer_unref (buf0);
|
||||||
|
gst_buffer_unref (buf1);
|
||||||
|
|
||||||
|
gst_object_unref (rtpmux);
|
||||||
|
gst_harness_teardown (h0);
|
||||||
|
gst_harness_teardown (h1);
|
||||||
|
gst_harness_teardown (h);
|
||||||
|
}
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
static Suite *
|
static Suite *
|
||||||
|
@ -358,7 +532,10 @@ rtpmux_suite (void)
|
||||||
tc_chain = tcase_create ("rtpmux_basic");
|
tc_chain = tcase_create ("rtpmux_basic");
|
||||||
suite_add_tcase (s, tc_chain);
|
suite_add_tcase (s, tc_chain);
|
||||||
tcase_add_test (tc_chain, test_rtpmux_basic);
|
tcase_add_test (tc_chain, test_rtpmux_basic);
|
||||||
tcase_add_test (tc_chain, test_rtpmux_ssrc);
|
tcase_add_test (tc_chain, test_rtpmux_ssrc_property);
|
||||||
|
tcase_add_test (tc_chain, test_rtpmux_ssrc_property_not_set);
|
||||||
|
tcase_add_test (tc_chain, test_rtpmux_ssrc_downstream_can_overrule);
|
||||||
|
tcase_add_test (tc_chain, test_rtpmux_ssrc_downstream_dynamic);
|
||||||
|
|
||||||
tc_chain = tcase_create ("rtpdtmfmux_basic");
|
tc_chain = tcase_create ("rtpdtmfmux_basic");
|
||||||
tcase_add_test (tc_chain, test_rtpdtmfmux_basic);
|
tcase_add_test (tc_chain, test_rtpdtmfmux_basic);
|
||||||
|
|
Loading…
Reference in a new issue