4 * Copyright (C) 2005 Nokia Corporation.
5 * @author Kai Vehmanen <kai.vehmanen@nokia.com>
7 * Loosely based on GStreamer gstdecodebin
8 * Copyright (C) <2004> 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-gstrtpptdemux
28 * @short_description: separate RTP payloads based on the payload type
32 * gstrtpptdemux acts as a demuxer for RTP packets based on the payload type of the
33 * packets. Its main purpose is to allow an application to easily receive and
34 * decode an RTP stream with multiple payload types.
37 * For each payload type that is detected, a new pad will be created and the
38 * ::new-payload-type signal will be emitted. When the payload for the RTP
39 * stream changes, the ::payload-type-change signal will be emitted.
42 * The element will try to set complete and unique application/x-rtp caps on the
43 * outgoing buffers and pads based on the result of the ::request-pt-map signal.
45 * <title>Example pipelines</title>
48 * gst-launch udpsrc caps="application/x-rtp" ! gstrtpptdemux ! fakesink
50 * Takes an RTP stream and send the RTP packets with the first detected payload
51 * type to fakesink, discarding the other payload types.
55 * Last reviewed on 2007-05-28 (0.10.5)
60 * Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>
64 * - works with the test_rtpdemux.c tool
67 * - is emitting a signal enough, or should we
68 * use GstEvent to notify downstream elements
69 * of the new packet... no?
72 * - emits event both for new PTs, and whenever
82 #include <gst/rtp/gstrtpbuffer.h>
84 #include "gstrtpbin-marshal.h"
85 #include "gstrtpptdemux.h"
87 /* generic templates */
88 static GstStaticPadTemplate rtp_pt_demux_sink_template =
89 GST_STATIC_PAD_TEMPLATE ("sink",
92 GST_STATIC_CAPS ("application/x-rtp")
95 static GstStaticPadTemplate rtp_pt_demux_src_template =
96 GST_STATIC_PAD_TEMPLATE ("src_%d",
99 GST_STATIC_CAPS ("application/x-rtp, " "payload = (int) [ 0, 255 ]")
102 GST_DEBUG_CATEGORY_STATIC (gst_rtp_pt_demux_debug);
103 #define GST_CAT_DEFAULT gst_rtp_pt_demux_debug
106 * Item for storing GstPad<->pt pairs.
108 struct _GstRtpPtDemuxPad
110 GstPad *pad; /**< pointer to the actual pad */
111 gint pt; /**< RTP payload-type attached to pad */
117 SIGNAL_REQUEST_PT_MAP,
118 SIGNAL_NEW_PAYLOAD_TYPE,
119 SIGNAL_PAYLOAD_TYPE_CHANGE,
124 GST_BOILERPLATE (GstRtpPtDemux, gst_rtp_pt_demux, GstElement, GST_TYPE_ELEMENT);
126 static void gst_rtp_pt_demux_finalize (GObject * object);
128 static void gst_rtp_pt_demux_release (GstElement * element);
129 static gboolean gst_rtp_pt_demux_setup (GstElement * element);
131 static GstFlowReturn gst_rtp_pt_demux_chain (GstPad * pad, GstBuffer * buf);
132 static GstStateChangeReturn gst_rtp_pt_demux_change_state (GstElement * element,
133 GstStateChange transition);
134 static void gst_rtp_pt_demux_clear_pt_map (GstRtpPtDemux * rtpdemux);
136 static GstPad *find_pad_for_pt (GstRtpPtDemux * rtpdemux, guint8 pt);
138 static guint gst_rtp_pt_demux_signals[LAST_SIGNAL] = { 0 };
140 static GstElementDetails gst_rtp_pt_demux_details = {
143 "Parses codec streams transmitted in the same RTP session",
144 "Kai Vehmanen <kai.vehmanen@nokia.com>"
148 gst_rtp_pt_demux_base_init (gpointer g_class)
150 GstElementClass *gstelement_klass = GST_ELEMENT_CLASS (g_class);
152 gst_element_class_add_pad_template (gstelement_klass,
153 gst_static_pad_template_get (&rtp_pt_demux_sink_template));
154 gst_element_class_add_pad_template (gstelement_klass,
155 gst_static_pad_template_get (&rtp_pt_demux_src_template));
157 gst_element_class_set_details (gstelement_klass, &gst_rtp_pt_demux_details);
161 gst_rtp_pt_demux_class_init (GstRtpPtDemuxClass * klass)
163 GObjectClass *gobject_klass;
164 GstElementClass *gstelement_klass;
166 gobject_klass = (GObjectClass *) klass;
167 gstelement_klass = (GstElementClass *) klass;
170 * GstRtpPtDemux::request-pt-map:
171 * @demux: the object which received the signal
172 * @pt: the payload type
174 * Request the payload type as #GstCaps for @pt.
176 gst_rtp_pt_demux_signals[SIGNAL_REQUEST_PT_MAP] =
177 g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
178 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass, request_pt_map),
179 NULL, NULL, gst_rtp_bin_marshal_BOXED__UINT, GST_TYPE_CAPS, 1,
183 * GstRtpPtDemux::new-payload-type:
184 * @demux: the object which received the signal
185 * @pt: the payload type
186 * @pad: the pad with the new payload
188 * Emited when a new payload type pad has been created in @demux.
190 gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE] =
191 g_signal_new ("new-payload-type", G_TYPE_FROM_CLASS (klass),
192 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass, new_payload_type),
193 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_OBJECT, G_TYPE_NONE, 2,
194 G_TYPE_UINT, GST_TYPE_PAD);
197 * GstRtpPtDemux::payload-type-change:
198 * @demux: the object which received the signal
199 * @pt: the new payload type
201 * Emited when the payload type changed.
203 gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE] =
204 g_signal_new ("payload-type-change", G_TYPE_FROM_CLASS (klass),
205 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass,
206 payload_type_change), NULL, NULL, g_cclosure_marshal_VOID__UINT,
207 G_TYPE_NONE, 1, G_TYPE_UINT);
210 * GstRtpPtDemux::clear-pt-map:
211 * @demux: the object which received the signal
213 * The application can call this signal to instruct the element to discard the
214 * currently cached payload type map.
216 gst_rtp_pt_demux_signals[SIGNAL_CLEAR_PT_MAP] =
217 g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
218 G_SIGNAL_ACTION | G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass,
219 clear_pt_map), NULL, NULL, g_cclosure_marshal_VOID__VOID,
220 G_TYPE_NONE, 0, G_TYPE_NONE);
222 gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_finalize);
224 gstelement_klass->change_state =
225 GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_change_state);
227 klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_clear_pt_map);
229 GST_DEBUG_CATEGORY_INIT (gst_rtp_pt_demux_debug,
230 "rtpptdemux", 0, "RTP codec demuxer");
234 gst_rtp_pt_demux_init (GstRtpPtDemux * ptdemux, GstRtpPtDemuxClass * g_class)
236 GstElementClass *klass = GST_ELEMENT_GET_CLASS (ptdemux);
239 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
241 g_assert (ptdemux->sink != NULL);
243 gst_pad_set_chain_function (ptdemux->sink, gst_rtp_pt_demux_chain);
245 gst_element_add_pad (GST_ELEMENT (ptdemux), ptdemux->sink);
249 gst_rtp_pt_demux_finalize (GObject * object)
251 gst_rtp_pt_demux_release (GST_ELEMENT (object));
253 G_OBJECT_CLASS (parent_class)->finalize (object);
257 gst_rtp_pt_demux_clear_pt_map (GstRtpPtDemux * rtpdemux)
259 /* FIXME, do something */
263 gst_rtp_pt_demux_chain (GstPad * pad, GstBuffer * buf)
265 GstFlowReturn ret = GST_FLOW_OK;
266 GstRtpPtDemux *rtpdemux;
267 GstElement *element = GST_ELEMENT (GST_OBJECT_PARENT (pad));
271 rtpdemux = GST_RTP_PT_DEMUX (GST_OBJECT_PARENT (pad));
273 if (!gst_rtp_buffer_validate (buf))
276 pt = gst_rtp_buffer_get_payload_type (buf);
278 GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt);
280 srcpad = find_pad_for_pt (rtpdemux, pt);
281 if (srcpad == NULL) {
282 /* new PT, create a src pad */
283 GstElementClass *klass;
284 GstPadTemplate *templ;
287 GstRtpPtDemuxPad *rtpdemuxpad;
289 GValue args[2] = { {0}
294 klass = GST_ELEMENT_GET_CLASS (rtpdemux);
295 templ = gst_element_class_get_pad_template (klass, "src_%d");
296 padname = g_strdup_printf ("src_%d", pt);
297 srcpad = gst_pad_new_from_template (templ, padname);
298 gst_pad_use_fixed_caps (srcpad);
301 /* figure out the caps */
302 g_value_init (&args[0], GST_TYPE_ELEMENT);
303 g_value_set_object (&args[0], rtpdemux);
304 g_value_init (&args[1], G_TYPE_UINT);
305 g_value_set_uint (&args[1], pt);
307 g_value_init (&ret, GST_TYPE_CAPS);
308 g_value_set_boxed (&ret, NULL);
310 g_signal_emitv (args, gst_rtp_pt_demux_signals[SIGNAL_REQUEST_PT_MAP], 0,
313 caps = g_value_get_boxed (&ret);
315 caps = GST_PAD_CAPS (rtpdemux->sink);
319 caps = gst_caps_make_writable (caps);
320 gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
321 gst_pad_set_caps (srcpad, caps);
323 GST_DEBUG ("Adding pt=%d to the list.", pt);
324 rtpdemuxpad = g_new0 (GstRtpPtDemuxPad, 1);
325 rtpdemuxpad->pt = pt;
326 rtpdemuxpad->pad = srcpad;
327 rtpdemux->srcpads = g_slist_append (rtpdemux->srcpads, rtpdemuxpad);
329 gst_pad_set_active (srcpad, TRUE);
330 gst_element_add_pad (element, srcpad);
332 GST_DEBUG ("emitting new-payload_type for pt %d", pt);
333 g_signal_emit (G_OBJECT (rtpdemux),
334 gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad);
337 if (pt != rtpdemux->last_pt) {
340 /* our own signal with an extra flag that this is the only pad */
341 rtpdemux->last_pt = pt;
342 GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt);
343 g_signal_emit (G_OBJECT (rtpdemux),
344 gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt);
347 gst_buffer_set_caps (buf, GST_PAD_CAPS (srcpad));
351 ret = gst_pad_push (srcpad, GST_BUFFER (buf));
358 /* this is fatal and should be filtered earlier */
359 GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
360 ("Dropping invalid RTP payload"));
361 gst_buffer_unref (buf);
362 return GST_FLOW_ERROR;
366 GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
367 ("Could not get caps for payload"));
368 gst_buffer_unref (buf);
369 return GST_FLOW_ERROR;
374 find_pad_for_pt (GstRtpPtDemux * rtpdemux, guint8 pt)
376 GstPad *respad = NULL;
377 GSList *item = rtpdemux->srcpads;
379 for (; item; item = g_slist_next (item)) {
380 GstRtpPtDemuxPad *pad = item->data;
392 * Reserves resources for the object.
395 gst_rtp_pt_demux_setup (GstElement * element)
397 GstRtpPtDemux *ptdemux = GST_RTP_PT_DEMUX (element);
401 ptdemux->srcpads = NULL;
402 ptdemux->last_pt = 0xFFFF;
409 * Free resources for the object.
412 gst_rtp_pt_demux_release (GstElement * element)
414 GstRtpPtDemux *ptdemux = GST_RTP_PT_DEMUX (element);
417 /* note: GstElement's dispose() will handle the pads */
418 g_slist_free (ptdemux->srcpads);
419 ptdemux->srcpads = NULL;
423 static GstStateChangeReturn
424 gst_rtp_pt_demux_change_state (GstElement * element, GstStateChange transition)
426 GstStateChangeReturn ret;
427 GstRtpPtDemux *ptdemux;
429 ptdemux = GST_RTP_PT_DEMUX (element);
431 switch (transition) {
432 case GST_STATE_CHANGE_NULL_TO_READY:
433 if (gst_rtp_pt_demux_setup (element) != TRUE)
434 ret = GST_STATE_CHANGE_FAILURE;
436 case GST_STATE_CHANGE_READY_TO_PAUSED:
437 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
442 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
444 switch (transition) {
445 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
446 case GST_STATE_CHANGE_PAUSED_TO_READY:
448 case GST_STATE_CHANGE_READY_TO_NULL:
449 gst_rtp_pt_demux_release (element);