/**
* SECTION:element-rtpmux
+ * @title: rtpmux
* @see_also: rtpdtmfmux
*
* The rtp muxer takes multiple RTP streams having the same clock-rate and
* muxes into a single stream with a single SSRC.
*
- * <refsect2>
- * <title>Example pipelines</title>
+ * ## Example pipelines
* |[
* gst-launch-1.0 rtpmux name=mux ! udpsink host=127.0.0.1 port=8888 \
* alsasrc ! alawenc ! rtppcmapay ! \
* In this example, an audio stream is captured from ALSA and another is
* generated, both are encoded into different payload types and muxed together
* so they can be sent on the same port.
- * </refsect2>
+ *
*/
#ifdef HAVE_CONFIG_H
gstelement_class = (GstElementClass *) klass;
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&src_factory));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&sink_factory));
+ gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
+ gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
gst_element_class_set_static_metadata (gstelement_class, "RTP muxer",
"Codec/Muxer",
if (!gst_structure_get_uint (s, "ssrc", &ssrc))
ssrc = -1;
- GST_DEBUG_OBJECT (rtp_mux, "collided ssrc: %" G_GUINT32_FORMAT, ssrc);
+ GST_DEBUG_OBJECT (rtp_mux, "collided ssrc: %x", ssrc);
/* choose another ssrc for our stream */
GST_OBJECT_LOCK (rtp_mux);
rtp_mux->current_ssrc = g_random_int ();
new_ssrc = rtp_mux->current_ssrc;
+ GST_INFO_OBJECT (rtp_mux, "New ssrc after collision %x (was: %x)",
+ new_ssrc, ssrc);
GST_OBJECT_UNLOCK (rtp_mux);
caps = gst_pad_get_current_caps (rtp_mux->srcpad);
rtp_mux->ssrc = DEFAULT_SSRC;
rtp_mux->current_ssrc = DEFAULT_SSRC;
- rtp_mux->ssrc_random = TRUE;
rtp_mux->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
rtp_mux->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
gst_rtp_buffer_set_ssrc (rtpbuffer, rtp_mux->current_ssrc);
gst_rtp_mux_readjust_rtp_timestamp_locked (rtp_mux, padpriv, rtpbuffer);
GST_LOG_OBJECT (rtp_mux,
- "Pushing packet size %" G_GSIZE_FORMAT ", seq=%d, ts=%u",
+ "Pushing packet size %" G_GSIZE_FORMAT ", seq=%d, ts=%u, ssrc=%x",
rtpbuffer->map[0].size, rtp_mux->seqnum,
- gst_rtp_buffer_get_timestamp (rtpbuffer));
+ gst_rtp_buffer_get_timestamp (rtpbuffer), rtp_mux->current_ssrc);
if (padpriv) {
- if (padpriv->segment.format == GST_FORMAT_TIME)
+ if (padpriv->segment.format == GST_FORMAT_TIME) {
GST_BUFFER_PTS (rtpbuffer->buffer) =
gst_segment_to_running_time (&padpriv->segment, GST_FORMAT_TIME,
GST_BUFFER_PTS (rtpbuffer->buffer));
+ GST_BUFFER_DTS (rtpbuffer->buffer) =
+ gst_segment_to_running_time (&padpriv->segment, GST_FORMAT_TIME,
+ GST_BUFFER_DTS (rtpbuffer->buffer));
+ }
}
return TRUE;
return TRUE;
}
+static gboolean resend_events (GstPad * pad, GstEvent ** event,
+ gpointer user_data);
+
static GstFlowReturn
gst_rtp_mux_chain_list (GstPad * pad, GstObject * parent,
GstBufferList * bufferlist)
GstRTPMux *rtp_mux;
GstFlowReturn ret;
GstRTPMuxPadPrivate *padpriv;
+ gboolean changed = FALSE;
struct BufferListData bd;
rtp_mux = GST_RTP_MUX (parent);
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_pad_mark_reconfigure (rtp_mux->srcpad);
+ if (GST_PAD_IS_FLUSHING (rtp_mux->srcpad))
+ ret = GST_FLOW_FLUSHING;
+ else
+ ret = GST_FLOW_NOT_NEGOTIATED;
gst_buffer_list_unref (bufferlist);
goto out;
}
bufferlist = gst_buffer_list_make_writable (bufferlist);
gst_buffer_list_foreach (bufferlist, process_list_item, &bd);
+ if (!bd.drop && pad != rtp_mux->last_pad) {
+ changed = TRUE;
+ g_clear_object (&rtp_mux->last_pad);
+ rtp_mux->last_pad = g_object_ref (pad);
+ }
+
GST_OBJECT_UNLOCK (rtp_mux);
+ if (changed)
+ gst_pad_sticky_events_foreach (pad, resend_events, rtp_mux);
+
if (bd.drop) {
gst_buffer_list_unref (bufferlist);
ret = GST_FLOW_OK;
gst_event_parse_caps (*event, &caps);
gst_rtp_mux_setcaps (pad, rtp_mux, caps);
+ } else if (GST_EVENT_TYPE (*event) == GST_EVENT_SEGMENT) {
+ GstSegment new_segment;
+ gst_segment_init (&new_segment, GST_FORMAT_TIME);
+ gst_pad_push_event (rtp_mux->srcpad, gst_event_new_segment (&new_segment));
} else {
gst_pad_push_event (rtp_mux->srcpad, gst_event_ref (*event));
}
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_pad_mark_reconfigure (rtp_mux->srcpad);
+ if (GST_PAD_IS_FLUSHING (rtp_mux->srcpad))
+ ret = GST_FLOW_FLUSHING;
+ else
+ ret = GST_FLOW_NOT_NEGOTIATED;
gst_buffer_unref (buffer);
goto out;
}
GstRTPMuxPadPrivate *padpriv;
GstCaps *peercaps;
+ if (caps == NULL)
+ return FALSE;
+
if (!gst_caps_is_fixed (caps))
return FALSE;
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);
+ GST_INFO_OBJECT (pad, "Use downstream ssrc: %x", rtp_mux->current_ssrc);
rtp_mux->have_ssrc = TRUE;
}
+ if (gst_structure_get_uint (structure,
+ "timestamp-offset", &rtp_mux->ts_base)) {
+ GST_INFO_OBJECT (pad, "Use downstream timestamp-offset: %u",
+ rtp_mux->ts_base);
+ }
GST_OBJECT_UNLOCK (rtp_mux);
}
/* 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_random) {
- if (!gst_structure_get_uint (structure, "ssrc", &rtp_mux->current_ssrc))
+ if (rtp_mux->ssrc == DEFAULT_SSRC) {
+ if (rtp_mux->current_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_INFO_OBJECT (rtp_mux, "Set random ssrc %x", rtp_mux->current_ssrc);
+ }
}
+ } else {
+ rtp_mux->current_ssrc = rtp_mux->ssrc;
+ GST_INFO_OBJECT (rtp_mux, "Set ssrc %x", rtp_mux->current_ssrc);
}
gst_caps_set_simple (caps,
GstCaps *peercaps;
GstCaps *othercaps;
GstCaps *tcaps;
+ const GstStructure *structure;
peercaps = gst_pad_peer_query_caps (mux->srcpad, NULL);
GST_LOG_OBJECT (pad, "Intersected srcpad-peercaps and template caps: %"
GST_PTR_FORMAT, othercaps);
+ structure = gst_caps_get_structure (othercaps, 0);
+ if (mux->ssrc == DEFAULT_SSRC) {
+ if (gst_structure_get_uint (structure, "ssrc", &mux->current_ssrc))
+ GST_DEBUG_OBJECT (pad, "Use downstream ssrc: %x", mux->current_ssrc);
+ }
+
clear_caps (othercaps, TRUE);
g_value_init (&v, GST_TYPE_CAPS);
rtp_mux->ssrc = g_value_get_uint (value);
rtp_mux->current_ssrc = rtp_mux->ssrc;
rtp_mux->have_ssrc = TRUE;
- rtp_mux->ssrc_random = FALSE;
+ GST_DEBUG_OBJECT (rtp_mux, "ssrc prop set to %x", rtp_mux->ssrc);
GST_OBJECT_UNLOCK (rtp_mux);
break;
default:
gboolean is_pad;
gboolean ret;
+ GST_OBJECT_LOCK (mux);
+ is_pad = (pad == mux->last_pad);
+ GST_OBJECT_UNLOCK (mux);
+
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
{
gst_event_copy_segment (event, &padpriv->segment);
}
GST_OBJECT_UNLOCK (mux);
+
+ if (is_pad) {
+ GstSegment new_segment;
+ gst_segment_init (&new_segment, GST_FORMAT_TIME);
+ gst_event_unref (event);
+ event = gst_event_new_segment (&new_segment);
+ }
break;
}
default:
break;
}
- GST_OBJECT_LOCK (mux);
- is_pad = (pad == mux->last_pad);
- GST_OBJECT_UNLOCK (mux);
-
if (is_pad) {
return gst_pad_push_event (mux->srcpad, event);
} else {
rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
- if (rtp_mux->ssrc_random) {
- rtp_mux->have_ssrc = FALSE;
- } else {
+ if (rtp_mux->have_ssrc)
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);