1 /* RTP muxer element for GStreamer
5 * Copyright (C) <2007> Nokia Corporation.
6 * Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
7 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
8 * 2000,2005 Wim Taymans <wim@fluendo.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
27 * SECTION:element-rtpmux
28 * @short_description: Muxer that takes one or several RTP streams
29 * and muxes them to a single rtp stream.
40 #include <gst/rtp/gstrtpbuffer.h>
41 #include <gstrtpmux.h>
44 GST_DEBUG_CATEGORY_STATIC (gst_rtp_mux_debug);
45 #define GST_CAT_DEFAULT gst_rtp_mux_debug
47 /* elementfactory information */
48 static const GstElementDetails gst_rtp_mux_details =
49 GST_ELEMENT_DETAILS ("RTP muxer",
51 "multiplex N rtp streams into one",
52 "Zeeshan Ali <first.last@nokia.com>");
58 PROP_TIMESTAMP_OFFSET,
64 #define DEFAULT_TIMESTAMP_OFFSET -1
65 #define DEFAULT_SEQNUM_OFFSET -1
66 #define DEFAULT_SSRC -1
67 #define DEFAULT_CLOCK_RATE 0
69 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
72 GST_STATIC_CAPS ("application/x-rtp")
75 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%d",
78 GST_STATIC_CAPS ("application/x-rtp")
81 static void gst_rtp_mux_base_init (gpointer g_class);
82 static void gst_rtp_mux_class_init (GstRTPMuxClass * klass);
83 static void gst_rtp_mux_init (GstRTPMux * rtp_mux);
85 static void gst_rtp_mux_finalize (GObject * object);
87 static GstPad *gst_rtp_mux_request_new_pad (GstElement * element,
88 GstPadTemplate * templ, const gchar * name);
89 static GstFlowReturn gst_rtp_mux_chain (GstPad * pad,
91 static gboolean gst_rtp_mux_setcaps (GstPad *pad, GstCaps *caps);
93 static GstStateChangeReturn gst_rtp_mux_change_state (GstElement *
94 element, GstStateChange transition);
96 static void gst_rtp_mux_set_property (GObject * object, guint prop_id,
97 const GValue * value, GParamSpec * pspec);
98 static void gst_rtp_mux_get_property (GObject * object, guint prop_id,
99 GValue * value, GParamSpec * pspec);
101 static GstElementClass *parent_class = NULL;
104 gst_rtp_mux_get_type (void)
106 static GType rtp_mux_type = 0;
109 static const GTypeInfo rtp_mux_info = {
110 sizeof (GstRTPMuxClass),
111 gst_rtp_mux_base_init,
113 (GClassInitFunc) gst_rtp_mux_class_init,
118 (GInstanceInitFunc) gst_rtp_mux_init,
122 g_type_register_static (GST_TYPE_ELEMENT, "GstRTPMux",
129 gst_rtp_mux_base_init (gpointer g_class)
131 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
133 gst_element_class_add_pad_template (element_class,
134 gst_static_pad_template_get (&src_factory));
135 gst_element_class_add_pad_template (element_class,
136 gst_static_pad_template_get (&sink_factory));
138 gst_element_class_set_details (element_class, &gst_rtp_mux_details);
142 gst_rtp_mux_class_init (GstRTPMuxClass * klass)
144 GObjectClass *gobject_class;
145 GstElementClass *gstelement_class;
147 gobject_class = (GObjectClass *) klass;
148 gstelement_class = (GstElementClass *) klass;
150 parent_class = g_type_class_peek_parent (klass);
152 gobject_class->finalize = gst_rtp_mux_finalize;
153 gobject_class->get_property = gst_rtp_mux_get_property;
154 gobject_class->set_property = gst_rtp_mux_set_property;
156 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CLOCK_RATE,
157 g_param_spec_uint ("clock-rate", "clockrate",
158 "The clock-rate of the RTP streams",
159 0, G_MAXUINT, DEFAULT_CLOCK_RATE, G_PARAM_READWRITE));
160 g_object_class_install_property (G_OBJECT_CLASS (klass),
161 PROP_TIMESTAMP_OFFSET, g_param_spec_int ("timestamp-offset",
163 "Offset to add to all outgoing timestamps (-1 = random)", -1,
164 G_MAXINT, DEFAULT_TIMESTAMP_OFFSET, G_PARAM_READWRITE));
165 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET,
166 g_param_spec_int ("seqnum-offset", "Sequence number Offset",
167 "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXINT,
168 DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE));
169 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM,
170 g_param_spec_uint ("seqnum", "Sequence number",
171 "The RTP sequence number of the last processed packet",
172 0, G_MAXUINT, 0, G_PARAM_READABLE));
173 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
174 g_param_spec_uint ("ssrc", "SSRC",
175 "The SSRC of the packets (-1 == random)",
176 0, G_MAXUINT, DEFAULT_SSRC, G_PARAM_READWRITE));
178 gstelement_class->request_new_pad = gst_rtp_mux_request_new_pad;
179 gstelement_class->change_state = gst_rtp_mux_change_state;
181 klass->chain_func = gst_rtp_mux_chain;
184 static gboolean gst_rtp_mux_src_event (GstPad * pad,
190 gboolean result = FALSE;
191 gboolean done = FALSE;
193 rtp_mux = gst_pad_get_parent_element (pad);
194 g_return_val_if_fail (rtp_mux != NULL, FALSE);
196 iter = gst_element_iterate_sink_pads (rtp_mux);
199 switch (gst_iterator_next (iter, (gpointer) &sinkpad)) {
200 case GST_ITERATOR_OK:
201 gst_event_ref (event);
202 result |= gst_pad_push_event (sinkpad, event);
203 gst_object_unref (sinkpad);
205 case GST_ITERATOR_RESYNC:
206 gst_iterator_resync (iter);
208 case GST_ITERATOR_ERROR:
209 GST_WARNING_OBJECT (rtp_mux, "Error iterating sinkpads");
210 case GST_ITERATOR_DONE:
216 gst_event_unref (event);
222 gst_rtp_mux_init (GstRTPMux * rtp_mux)
224 GstElementClass *klass = GST_ELEMENT_GET_CLASS (rtp_mux);
227 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
229 gst_pad_set_event_function (rtp_mux->srcpad, gst_rtp_mux_src_event);
230 gst_element_add_pad (GST_ELEMENT (rtp_mux), rtp_mux->srcpad);
232 rtp_mux->ssrc = DEFAULT_SSRC;
233 rtp_mux->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
234 rtp_mux->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
235 rtp_mux->clock_rate = DEFAULT_CLOCK_RATE;
239 gst_rtp_mux_finalize (GObject * object)
243 rtp_mux = GST_RTP_MUX (object);
245 G_OBJECT_CLASS (parent_class)->finalize (object);
249 gst_rtp_mux_create_sinkpad (GstRTPMux * rtp_mux, GstPadTemplate * templ)
251 GstPad *newpad = NULL;
252 GstPadTemplate * class_templ;
254 class_templ = gst_element_class_get_pad_template (
255 GST_ELEMENT_GET_CLASS (rtp_mux), "sink_%d");
257 if (templ == class_templ) {
260 /* create new pad with the name */
261 name = g_strdup_printf ("sink_%02d", rtp_mux->numpads);
262 newpad = gst_pad_new_from_template (templ, name);
267 GST_WARNING_OBJECT (rtp_mux, "this is not our template!\n");
274 gst_rtp_mux_setup_sinkpad (GstRTPMux * rtp_mux, GstPad * sinkpad)
276 GstRTPMuxClass *klass;
278 klass = GST_RTP_MUX_GET_CLASS (rtp_mux);
280 /* setup some pad functions */
281 gst_pad_set_setcaps_function (sinkpad, gst_rtp_mux_setcaps);
282 if (klass->chain_func)
283 gst_pad_set_chain_function (sinkpad, klass->chain_func);
284 if (klass->sink_event_func)
285 gst_pad_set_event_function (sinkpad, klass->sink_event_func);
287 /* dd the pad to the element */
288 gst_element_add_pad (GST_ELEMENT (rtp_mux), sinkpad);
292 gst_rtp_mux_request_new_pad (GstElement * element,
293 GstPadTemplate * templ, const gchar * req_name)
298 g_return_val_if_fail (templ != NULL, NULL);
299 g_return_val_if_fail (GST_IS_RTP_MUX (element), NULL);
301 rtp_mux = GST_RTP_MUX (element);
303 if (templ->direction != GST_PAD_SINK) {
304 GST_WARNING_OBJECT (rtp_mux, "request pad that is not a SINK pad");
308 newpad = gst_rtp_mux_create_sinkpad (rtp_mux, templ);
310 gst_rtp_mux_setup_sinkpad (rtp_mux, newpad);
312 GST_WARNING_OBJECT (rtp_mux, "failed to create request pad");
318 gst_rtp_mux_get_buffer_ts_base (GstRTPMux * rtp_mux, GstBuffer * buffer)
321 GstStructure *structure;
325 caps = gst_buffer_get_caps (buffer);
326 g_return_val_if_fail (caps != NULL, 0);
328 structure = gst_caps_get_structure (caps, 0);
329 g_return_val_if_fail (structure != NULL, 0);
331 value = gst_structure_get_value (structure, "clock-base");
334 ts_base = g_value_get_uint (value);
338 gst_caps_unref (caps);
340 GST_DEBUG_OBJECT (rtp_mux, "sink's ts-base: %u", ts_base);
344 /* Put our own clock-base on the buffer */
346 gst_rtp_mux_readjust_rtp_timestamp (GstRTPMux * rtp_mux, GstBuffer * buffer)
349 guint32 sink_ts_base;
351 sink_ts_base = gst_rtp_mux_get_buffer_ts_base (rtp_mux, buffer);
352 ts = gst_rtp_buffer_get_timestamp (buffer) - sink_ts_base + rtp_mux->ts_base;
353 GST_DEBUG_OBJECT (rtp_mux, "Re-adjusting RTP ts %u to %u",
354 gst_rtp_buffer_get_timestamp (buffer), ts);
355 gst_rtp_buffer_set_timestamp (buffer, ts);
359 gst_rtp_mux_chain (GstPad * pad, GstBuffer * buffer)
364 rtp_mux = GST_RTP_MUX (gst_pad_get_parent (pad));
367 GST_LOG_OBJECT (rtp_mux, "setting RTP seqnum %d", rtp_mux->seqnum);
368 gst_rtp_buffer_set_seq (buffer, rtp_mux->seqnum);
369 gst_rtp_buffer_set_ssrc (buffer, rtp_mux->current_ssrc);
370 gst_rtp_mux_readjust_rtp_timestamp (rtp_mux, buffer);
371 GST_DEBUG_OBJECT (rtp_mux, "Pushing packet size %d, seq=%d, ts=%u",
372 GST_BUFFER_SIZE (buffer), rtp_mux->seqnum - 1);
374 ret = gst_pad_push (rtp_mux->srcpad, buffer);
376 gst_object_unref (rtp_mux);
381 gst_rtp_mux_set_clock_rate (GstRTPMux *rtp_mux, gint clock_rate)
385 if (rtp_mux->clock_rate == 0) {
386 rtp_mux->clock_rate = clock_rate;
390 else if (rtp_mux->clock_rate != clock_rate) {
391 GST_WARNING_OBJECT (rtp_mux, "Clock-rate already set to: %u",
392 rtp_mux->clock_rate);
400 gst_rtp_mux_setcaps (GstPad *pad, GstCaps *caps)
403 GstStructure *structure;
407 rtp_mux = GST_RTP_MUX (gst_pad_get_parent (pad));
409 structure = gst_caps_get_structure (caps, 0);
410 if (gst_structure_get_int (structure, "clock-rate", &clock_rate)) {
411 ret = gst_rtp_mux_set_clock_rate (rtp_mux, clock_rate);
415 GST_DEBUG_OBJECT (rtp_mux,
416 "seting caps %" GST_PTR_FORMAT " on src pad..", caps);
417 ret = gst_pad_set_caps (rtp_mux->srcpad, caps);
420 gst_object_unref (rtp_mux);
426 gst_rtp_mux_get_property (GObject * object,
427 guint prop_id, GValue * value, GParamSpec * pspec)
431 rtp_mux = GST_RTP_MUX (object);
434 case PROP_CLOCK_RATE:
435 g_value_set_uint (value, rtp_mux->clock_rate);
437 case PROP_TIMESTAMP_OFFSET:
438 g_value_set_int (value, rtp_mux->ts_offset);
440 case PROP_SEQNUM_OFFSET:
441 g_value_set_int (value, rtp_mux->seqnum_offset);
444 g_value_set_uint (value, rtp_mux->seqnum);
447 g_value_set_uint (value, rtp_mux->ssrc);
450 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
456 gst_rtp_mux_set_property (GObject * object,
457 guint prop_id, const GValue * value, GParamSpec * pspec)
461 rtp_mux = GST_RTP_MUX (object);
464 case PROP_CLOCK_RATE:
465 rtp_mux->clock_rate = g_value_get_uint (value);
467 case PROP_TIMESTAMP_OFFSET:
468 rtp_mux->ts_offset = g_value_get_int (value);
470 case PROP_SEQNUM_OFFSET:
471 rtp_mux->seqnum_offset = g_value_get_int (value);
474 rtp_mux->ssrc = g_value_get_uint (value);
477 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
483 gst_rtp_mux_ready_to_paused (GstRTPMux * rtp_mux)
485 if (rtp_mux->ssrc == -1)
486 rtp_mux->current_ssrc = g_random_int ();
488 rtp_mux->current_ssrc = rtp_mux->ssrc;
490 if (rtp_mux->seqnum_offset == -1)
491 rtp_mux->seqnum_base = g_random_int_range (0, G_MAXUINT16);
493 rtp_mux->seqnum_base = rtp_mux->seqnum_offset;
494 rtp_mux->seqnum = rtp_mux->seqnum_base;
496 if (rtp_mux->ts_offset == -1)
497 rtp_mux->ts_base = g_random_int ();
499 rtp_mux->ts_base = rtp_mux->ts_offset;
500 GST_DEBUG_OBJECT (rtp_mux, "set clock-base to %u", rtp_mux->ts_base);
503 static GstStateChangeReturn
504 gst_rtp_mux_change_state (GstElement * element, GstStateChange transition)
508 rtp_mux = GST_RTP_MUX (element);
510 switch (transition) {
511 case GST_STATE_CHANGE_NULL_TO_READY:
513 case GST_STATE_CHANGE_READY_TO_PAUSED:
514 gst_rtp_mux_ready_to_paused (rtp_mux);
516 case GST_STATE_CHANGE_PAUSED_TO_READY:
522 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
526 gst_rtp_mux_plugin_init (GstPlugin * plugin)
528 GST_DEBUG_CATEGORY_INIT (gst_rtp_mux_debug, "rtpmux", 0,
531 return gst_element_register (plugin, "rtpmux", GST_RANK_NONE,