Document stuff.
[platform/upstream/gst-plugins-good.git] / gst / rtpmanager / gstrtpssrcdemux.c
1 /* GStreamer
2  * Copyright (C) <2007> Wim Taymans <wim@fluendo.com>
3  *
4  * RTP SSRC demuxer
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:element-rtpssrcdemux
24  * @short_description: separate RTP payloads based on the SSRC
25  *
26  * <refsect2>
27  * <para>
28  * rtpssrcdemux acts as a demuxer for RTP packets based on the SSRC of the
29  * packets. Its main purpose is to allow an application to easily receive and
30  * decode an RTP stream with multiple SSRCs.
31  * </para>
32  * <para>
33  * For each SSRC that is detected, a new pad will be created and the
34  * ::new-ssrc-pad signal will be emitted. 
35  * </para>
36  * <title>Example pipelines</title>
37  * <para>
38  * <programlisting>
39  * gst-launch udpsrc caps="application/x-rtp" ! rtpssrcdemux ! fakesink
40  * </programlisting>
41  * Takes an RTP stream and send the RTP packets with the first detected SSRC
42  * to fakesink, discarding the other SSRCs.
43  * </para>
44  * </refsect2>
45  *
46  * Last reviewed on 2007-05-23 (0.10.6)
47  */
48
49 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif
52
53 #include <string.h>
54 #include <gst/rtp/gstrtpbuffer.h>
55
56 #include "gstrtpbin-marshal.h"
57 #include "gstrtpssrcdemux.h"
58
59 GST_DEBUG_CATEGORY_STATIC (gst_rtp_ssrc_demux_debug);
60 #define GST_CAT_DEFAULT gst_rtp_ssrc_demux_debug
61
62 /* generic templates */
63 static GstStaticPadTemplate rtp_ssrc_demux_sink_template =
64 GST_STATIC_PAD_TEMPLATE ("sink",
65     GST_PAD_SINK,
66     GST_PAD_ALWAYS,
67     GST_STATIC_CAPS ("application/x-rtp")
68     );
69
70 static GstStaticPadTemplate rtp_ssrc_demux_src_template =
71 GST_STATIC_PAD_TEMPLATE ("src_%d",
72     GST_PAD_SRC,
73     GST_PAD_SOMETIMES,
74     GST_STATIC_CAPS ("application/x-rtp")
75     );
76
77 static GstElementDetails gst_rtp_ssrc_demux_details = {
78   "RTP SSRC Demux",
79   "Demux/Network/RTP",
80   "Splits RTP streams based on the SSRC",
81   "Wim Taymans <wim@fluendo.com>"
82 };
83
84 /* signals */
85 enum
86 {
87   SIGNAL_NEW_SSRC_PAD,
88   LAST_SIGNAL
89 };
90
91 GST_BOILERPLATE (GstRTPSsrcDemux, gst_rtp_ssrc_demux, GstElement,
92     GST_TYPE_ELEMENT);
93
94
95 /* GObject vmethods */
96 static void gst_rtp_ssrc_demux_finalize (GObject * object);
97
98 /* GstElement vmethods */
99 static GstStateChangeReturn gst_rtp_ssrc_demux_change_state (GstElement *
100     element, GstStateChange transition);
101
102 /* sinkpad stuff */
103 static GstFlowReturn gst_rtp_ssrc_demux_chain (GstPad * pad, GstBuffer * buf);
104 static gboolean gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstEvent * event);
105
106 /* srcpad stuff */
107 static gboolean gst_rtp_ssrc_demux_src_event (GstPad * pad, GstEvent * event);
108
109 static guint gst_rtp_ssrc_demux_signals[LAST_SIGNAL] = { 0 };
110
111 /**
112  * Item for storing GstPad <-> SSRC pairs.
113  */
114 struct _GstRTPSsrcDemuxPad
115 {
116   GstPad *pad;
117   guint32 ssrc;
118   GstCaps *caps;
119 };
120
121 /* find a src pad for a given SSRC, returns NULL if the SSRC was not found
122  */
123 static GstPad *
124 find_rtp_pad_for_ssrc (GstRTPSsrcDemux * demux, guint32 ssrc)
125 {
126   GSList *walk;
127
128   for (walk = demux->rtp_srcpads; walk; walk = g_slist_next (walk)) {
129     GstRTPSsrcDemuxPad *pad = (GstRTPSsrcDemuxPad *) walk->data;
130
131     if (pad->ssrc == ssrc)
132       return pad->pad;
133   }
134   return NULL;
135 }
136
137 static GstPad *
138 create_rtp_pad_for_ssrc (GstRTPSsrcDemux * demux, guint32 ssrc)
139 {
140   GstPad *result;
141   GstElementClass *klass;
142   GstPadTemplate *templ;
143   gchar *padname;
144   GstRTPSsrcDemuxPad *demuxpad;
145
146   klass = GST_ELEMENT_GET_CLASS (demux);
147   templ = gst_element_class_get_pad_template (klass, "src_%d");
148   padname = g_strdup_printf ("src_%d", ssrc);
149   result = gst_pad_new_from_template (templ, padname);
150   g_free (padname);
151
152   /* wrap in structure and add to list */
153   demuxpad = g_new0 (GstRTPSsrcDemuxPad, 1);
154   demuxpad->ssrc = ssrc;
155   demuxpad->pad = result;
156   demux->rtp_srcpads = g_slist_prepend (demux->rtp_srcpads, demuxpad);
157
158   /* copy caps from input */
159   gst_pad_set_caps (result, GST_PAD_CAPS (demux->rtp_sink));
160
161   gst_pad_set_event_function (result, gst_rtp_ssrc_demux_src_event);
162   gst_pad_set_active (result, TRUE);
163   gst_element_add_pad (GST_ELEMENT_CAST (demux), result);
164
165   g_signal_emit (G_OBJECT (demux),
166       gst_rtp_ssrc_demux_signals[SIGNAL_NEW_SSRC_PAD], 0, ssrc, result);
167
168   return result;
169 }
170
171 static void
172 gst_rtp_ssrc_demux_base_init (gpointer g_class)
173 {
174   GstElementClass *gstelement_klass = GST_ELEMENT_CLASS (g_class);
175
176   gst_element_class_add_pad_template (gstelement_klass,
177       gst_static_pad_template_get (&rtp_ssrc_demux_sink_template));
178   gst_element_class_add_pad_template (gstelement_klass,
179       gst_static_pad_template_get (&rtp_ssrc_demux_src_template));
180
181   gst_element_class_set_details (gstelement_klass, &gst_rtp_ssrc_demux_details);
182 }
183
184 static void
185 gst_rtp_ssrc_demux_class_init (GstRTPSsrcDemuxClass * klass)
186 {
187   GObjectClass *gobject_klass;
188   GstElementClass *gstelement_klass;
189
190   gobject_klass = (GObjectClass *) klass;
191   gstelement_klass = (GstElementClass *) klass;
192
193   gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_finalize);
194
195   /**
196    * GstRTPSsrcDemux::new-ssrc-pad:
197    * @demux: the object which received the signal
198    * @ssrc: the SSRC of the pad
199    * @pad: the new pad.
200    *
201    * Emited when a new SSRC pad has been created.
202    */
203   gst_rtp_ssrc_demux_signals[SIGNAL_NEW_SSRC_PAD] =
204       g_signal_new ("new-ssrc-pad",
205       G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
206       G_STRUCT_OFFSET (GstRTPSsrcDemuxClass, new_ssrc_pad),
207       NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_OBJECT,
208       G_TYPE_NONE, 2, G_TYPE_UINT, GST_TYPE_PAD);
209
210   gstelement_klass->change_state =
211       GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_change_state);
212
213   GST_DEBUG_CATEGORY_INIT (gst_rtp_ssrc_demux_debug,
214       "rtpssrcdemux", 0, "RTP SSRC demuxer");
215 }
216
217 static void
218 gst_rtp_ssrc_demux_init (GstRTPSsrcDemux * demux,
219     GstRTPSsrcDemuxClass * g_class)
220 {
221   GstElementClass *klass = GST_ELEMENT_GET_CLASS (demux);
222
223   demux->rtp_sink =
224       gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
225           "sink"), "sink");
226   gst_pad_set_chain_function (demux->rtp_sink, gst_rtp_ssrc_demux_chain);
227   gst_pad_set_event_function (demux->rtp_sink, gst_rtp_ssrc_demux_sink_event);
228   gst_element_add_pad (GST_ELEMENT_CAST (demux), demux->rtp_sink);
229 }
230
231 static void
232 gst_rtp_ssrc_demux_finalize (GObject * object)
233 {
234   GstRTPSsrcDemux *demux;
235
236   demux = GST_RTP_SSRC_DEMUX (object);
237
238   G_OBJECT_CLASS (parent_class)->finalize (object);
239 }
240
241 static gboolean
242 gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstEvent * event)
243 {
244   GstRTPSsrcDemux *demux;
245   gboolean res = FALSE;
246
247   demux = GST_RTP_SSRC_DEMUX (gst_pad_get_parent (pad));
248
249   switch (GST_EVENT_TYPE (event)) {
250     case GST_EVENT_NEWSEGMENT:
251     default:
252       res = gst_pad_event_default (pad, event);
253       break;
254   }
255
256   gst_object_unref (demux);
257   return res;
258 }
259
260 static GstFlowReturn
261 gst_rtp_ssrc_demux_chain (GstPad * pad, GstBuffer * buf)
262 {
263   GstFlowReturn ret;
264   GstRTPSsrcDemux *demux;
265   guint32 ssrc;
266   GstPad *srcpad;
267
268   demux = GST_RTP_SSRC_DEMUX (GST_OBJECT_PARENT (pad));
269
270   if (!gst_rtp_buffer_validate (buf))
271     goto invalid_payload;
272
273   ssrc = gst_rtp_buffer_get_ssrc (buf);
274
275   GST_DEBUG_OBJECT (demux, "received buffer of SSRC %08x", ssrc);
276
277   srcpad = find_rtp_pad_for_ssrc (demux, ssrc);
278   if (srcpad == NULL) {
279     GST_DEBUG_OBJECT (demux, "creating pad for SSRC %08x", ssrc);
280     srcpad = create_rtp_pad_for_ssrc (demux, ssrc);
281     if (!srcpad)
282       goto create_failed;
283   }
284
285   /* push to srcpad */
286   ret = gst_pad_push (srcpad, buf);
287
288   return ret;
289
290   /* ERRORS */
291 invalid_payload:
292   {
293     /* this is fatal and should be filtered earlier */
294     GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
295         ("Dropping invalid RTP payload"));
296     gst_buffer_unref (buf);
297     return GST_FLOW_ERROR;
298   }
299 create_failed:
300   {
301     /* this is not fatal yet */
302     GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
303         ("Could not create new pad"));
304     gst_buffer_unref (buf);
305     return GST_FLOW_ERROR;
306   }
307 }
308
309 static gboolean
310 gst_rtp_ssrc_demux_src_event (GstPad * pad, GstEvent * event)
311 {
312   GstRTPSsrcDemux *demux;
313   gboolean res = FALSE;
314
315   demux = GST_RTP_SSRC_DEMUX (gst_pad_get_parent (pad));
316
317   switch (GST_EVENT_TYPE (event)) {
318     case GST_EVENT_SEEK:
319     default:
320       res = gst_pad_event_default (pad, event);
321       break;
322   }
323   gst_object_unref (demux);
324   return res;
325 }
326
327 static GstStateChangeReturn
328 gst_rtp_ssrc_demux_change_state (GstElement * element,
329     GstStateChange transition)
330 {
331   GstStateChangeReturn ret;
332   GstRTPSsrcDemux *demux;
333
334   demux = GST_RTP_SSRC_DEMUX (element);
335
336   switch (transition) {
337     case GST_STATE_CHANGE_NULL_TO_READY:
338     case GST_STATE_CHANGE_READY_TO_PAUSED:
339     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
340     default:
341       break;
342   }
343
344   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
345
346   switch (transition) {
347     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
348     case GST_STATE_CHANGE_PAUSED_TO_READY:
349     case GST_STATE_CHANGE_READY_TO_NULL:
350     default:
351       break;
352   }
353   return ret;
354 }