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.
28 * Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>
33 * - works with the test_rtpdemux.c tool
36 * - is emitting a signal enough, or should we
37 * use GstEvent to notify downstream elements
38 * of the new packet... no?
41 * - emits event both for new PTs, and whenever
51 #include <gst/rtp/gstrtpbuffer.h>
53 #include "gstrtpbin-marshal.h"
54 #include "gstrtpptdemux.h"
56 /* generic templates */
57 static GstStaticPadTemplate rtp_pt_demux_sink_template =
58 GST_STATIC_PAD_TEMPLATE ("sink",
61 GST_STATIC_CAPS ("application/x-rtp")
64 static GstStaticPadTemplate rtp_pt_demux_src_template =
65 GST_STATIC_PAD_TEMPLATE ("src_%d",
68 GST_STATIC_CAPS ("application/x-rtp, " "payload = (int) [ 0, 255 ]")
71 GST_DEBUG_CATEGORY_STATIC (gst_rtp_pt_demux_debug);
72 #define GST_CAT_DEFAULT gst_rtp_pt_demux_debug
75 * Item for storing GstPad<->pt pairs.
77 struct _GstRTPPtDemuxPad
79 GstPad *pad; /**< pointer to the actual pad */
80 gint pt; /**< RTP payload-type attached to pad */
86 SIGNAL_REQUEST_PT_MAP,
87 SIGNAL_NEW_PAYLOAD_TYPE,
88 SIGNAL_PAYLOAD_TYPE_CHANGE,
92 GST_BOILERPLATE (GstRTPPtDemux, gst_rtp_pt_demux, GstElement, GST_TYPE_ELEMENT);
94 static void gst_rtp_pt_demux_finalize (GObject * object);
96 static void gst_rtp_pt_demux_release (GstElement * element);
97 static gboolean gst_rtp_pt_demux_setup (GstElement * element);
99 static GstFlowReturn gst_rtp_pt_demux_chain (GstPad * pad, GstBuffer * buf);
100 static GstStateChangeReturn gst_rtp_pt_demux_change_state (GstElement * element,
101 GstStateChange transition);
103 static GstPad *find_pad_for_pt (GstRTPPtDemux * rtpdemux, guint8 pt);
105 static guint gst_rtp_pt_demux_signals[LAST_SIGNAL] = { 0 };
107 static GstElementDetails gst_rtp_pt_demux_details = {
109 /* XXX: what's the correct hierarchy? */
110 "Codec/Demux/Network",
111 "Parses codec streams transmitted in the same RTP session",
112 "Kai Vehmanen <kai.vehmanen@nokia.com>"
116 gst_rtp_pt_demux_base_init (gpointer g_class)
118 GstElementClass *gstelement_klass = GST_ELEMENT_CLASS (g_class);
120 gst_element_class_add_pad_template (gstelement_klass,
121 gst_static_pad_template_get (&rtp_pt_demux_sink_template));
122 gst_element_class_add_pad_template (gstelement_klass,
123 gst_static_pad_template_get (&rtp_pt_demux_src_template));
125 gst_element_class_set_details (gstelement_klass, &gst_rtp_pt_demux_details);
129 gst_rtp_pt_demux_class_init (GstRTPPtDemuxClass * klass)
131 GObjectClass *gobject_klass;
132 GstElementClass *gstelement_klass;
134 gobject_klass = (GObjectClass *) klass;
135 gstelement_klass = (GstElementClass *) klass;
138 * GstRTPPtDemux::request-pt-map:
139 * @demux: the object which received the signal
140 * @pt: the payload type
142 * Request the payload type as #GstCaps for @pt.
144 gst_rtp_pt_demux_signals[SIGNAL_REQUEST_PT_MAP] =
145 g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
146 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPPtDemuxClass, request_pt_map),
147 NULL, NULL, gst_rtp_bin_marshal_BOXED__UINT, GST_TYPE_CAPS, 1,
151 * GstRTPPtDemux::new-payload-type
152 * @demux: the object which received the signal
153 * @pt: the payload type
154 * @pad: the pad with the new payload
156 * Emited when a new payload type pad has been created in @demux.
158 gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE] =
159 g_signal_new ("new-payload-type", G_TYPE_FROM_CLASS (klass),
160 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPPtDemuxClass, new_payload_type),
161 NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_OBJECT, G_TYPE_NONE, 2,
162 G_TYPE_UINT, GST_TYPE_PAD);
165 * GstRTPPtDemux::payload-type-change
166 * @demux: the object which received the signal
167 * @pt: the new payload type
169 * Emited when the payload type changed.
171 gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE] =
172 g_signal_new ("payload-type-change", G_TYPE_FROM_CLASS (klass),
173 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPPtDemuxClass,
174 payload_type_change), NULL, NULL, g_cclosure_marshal_VOID__UINT,
175 G_TYPE_NONE, 1, G_TYPE_UINT);
177 gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_finalize);
179 gstelement_klass->change_state =
180 GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_change_state);
182 GST_DEBUG_CATEGORY_INIT (gst_rtp_pt_demux_debug,
183 "rtpptdemux", 0, "RTP codec demuxer");
188 gst_rtp_pt_demux_init (GstRTPPtDemux * ptdemux, GstRTPPtDemuxClass * g_class)
190 GstElementClass *klass = GST_ELEMENT_GET_CLASS (ptdemux);
193 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
195 g_assert (ptdemux->sink != NULL);
197 gst_pad_set_chain_function (ptdemux->sink, gst_rtp_pt_demux_chain);
199 gst_element_add_pad (GST_ELEMENT (ptdemux), ptdemux->sink);
203 gst_rtp_pt_demux_finalize (GObject * object)
205 gst_rtp_pt_demux_release (GST_ELEMENT (object));
207 G_OBJECT_CLASS (parent_class)->finalize (object);
211 gst_rtp_pt_demux_chain (GstPad * pad, GstBuffer * buf)
213 GstFlowReturn ret = GST_FLOW_OK;
214 GstRTPPtDemux *rtpdemux;
215 GstElement *element = GST_ELEMENT (GST_OBJECT_PARENT (pad));
219 rtpdemux = GST_RTP_PT_DEMUX (GST_OBJECT_PARENT (pad));
221 if (!gst_rtp_buffer_validate (buf))
224 pt = gst_rtp_buffer_get_payload_type (buf);
226 GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt);
228 srcpad = find_pad_for_pt (rtpdemux, pt);
229 if (srcpad == NULL) {
230 /* new PT, create a src pad */
231 GstElementClass *klass;
232 GstPadTemplate *templ;
235 GstRTPPtDemuxPad *rtpdemuxpad;
237 GValue args[2] = { {0}
242 klass = GST_ELEMENT_GET_CLASS (rtpdemux);
243 templ = gst_element_class_get_pad_template (klass, "src_%d");
244 padname = g_strdup_printf ("src_%d", pt);
245 srcpad = gst_pad_new_from_template (templ, padname);
248 /* figure out the caps */
249 g_value_init (&args[0], GST_TYPE_ELEMENT);
250 g_value_set_object (&args[0], rtpdemux);
251 g_value_init (&args[1], G_TYPE_UINT);
252 g_value_set_uint (&args[1], pt);
254 g_value_init (&ret, GST_TYPE_CAPS);
255 g_value_set_boxed (&ret, NULL);
257 g_signal_emitv (args, gst_rtp_pt_demux_signals[SIGNAL_REQUEST_PT_MAP], 0,
260 caps = g_value_get_boxed (&ret);
264 caps = gst_caps_make_writable (caps);
265 gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
266 gst_pad_set_caps (srcpad, caps);
268 GST_DEBUG ("Adding pt=%d to the list.", pt);
269 rtpdemuxpad = g_new0 (GstRTPPtDemuxPad, 1);
270 rtpdemuxpad->pt = pt;
271 rtpdemuxpad->pad = srcpad;
272 rtpdemux->srcpads = g_slist_append (rtpdemux->srcpads, rtpdemuxpad);
274 gst_pad_set_active (srcpad, TRUE);
275 gst_element_add_pad (element, srcpad);
277 GST_DEBUG ("emitting new-payload_type for pt %d", pt);
278 g_signal_emit (G_OBJECT (rtpdemux),
279 gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad);
282 if (pt != rtpdemux->last_pt) {
285 /* our own signal with an extra flag that this is the only pad */
286 rtpdemux->last_pt = pt;
287 GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt);
288 g_signal_emit (G_OBJECT (rtpdemux),
289 gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt);
292 gst_buffer_set_caps (buf, GST_PAD_CAPS (srcpad));
296 ret = gst_pad_push (srcpad, GST_BUFFER (buf));
303 /* this is fatal and should be filtered earlier */
304 GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
305 ("Dropping invalid RTP payload"));
306 gst_buffer_unref (buf);
307 return GST_FLOW_ERROR;
311 GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
312 ("Could not get caps for payload"));
313 gst_buffer_unref (buf);
314 return GST_FLOW_ERROR;
319 find_pad_for_pt (GstRTPPtDemux * rtpdemux, guint8 pt)
321 GstPad *respad = NULL;
322 GSList *item = rtpdemux->srcpads;
324 for (; item; item = g_slist_next (item)) {
325 GstRTPPtDemuxPad *pad = item->data;
337 * Reserves resources for the object.
340 gst_rtp_pt_demux_setup (GstElement * element)
342 GstRTPPtDemux *ptdemux = GST_RTP_PT_DEMUX (element);
346 ptdemux->srcpads = NULL;
347 ptdemux->last_pt = 0xFFFF;
354 * Free resources for the object.
357 gst_rtp_pt_demux_release (GstElement * element)
359 GstRTPPtDemux *ptdemux = GST_RTP_PT_DEMUX (element);
362 /* note: GstElement's dispose() will handle the pads */
363 g_slist_free (ptdemux->srcpads);
364 ptdemux->srcpads = NULL;
368 static GstStateChangeReturn
369 gst_rtp_pt_demux_change_state (GstElement * element, GstStateChange transition)
371 GstStateChangeReturn ret;
372 GstRTPPtDemux *ptdemux;
374 ptdemux = GST_RTP_PT_DEMUX (element);
376 switch (transition) {
377 case GST_STATE_CHANGE_NULL_TO_READY:
378 if (gst_rtp_pt_demux_setup (element) != TRUE)
379 ret = GST_STATE_CHANGE_FAILURE;
381 case GST_STATE_CHANGE_READY_TO_PAUSED:
382 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
387 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
389 switch (transition) {
390 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
391 case GST_STATE_CHANGE_PAUSED_TO_READY:
393 case GST_STATE_CHANGE_READY_TO_NULL:
394 gst_rtp_pt_demux_release (element);