Move stereo plugin from -bad
[platform/upstream/gst-plugins-good.git] / gst / rtpmanager / gstrtpptdemux.c
1 /* 
2  * RTP Demux element
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  * @author Kai Vehmanen <kai.vehmanen@nokia.com>
6  *
7  * Loosely based on GStreamer gstdecodebin
8  * Copyright (C) <2004> Wim Taymans <wim.taymans@gmail.com>
9  *
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.
14  *
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.
19  *
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., 51 Franklin St, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25
26 /**
27  * SECTION:element-rtpptdemux
28  *
29  * rtpptdemux acts as a demuxer for RTP packets based on the payload type of
30  * the packets. Its main purpose is to allow an application to easily receive
31  * and decode an RTP stream with multiple payload types.
32  * 
33  * For each payload type that is detected, a new pad will be created and the
34  * #GstRtpPtDemux::new-payload-type signal will be emitted. When the payload for
35  * the RTP stream changes, the #GstRtpPtDemux::payload-type-change signal will be
36  * emitted.
37  * 
38  * The element will try to set complete and unique application/x-rtp caps
39  * on the output pads based on the result of the #GstRtpPtDemux::request-pt-map
40  * signal.
41  * 
42  * <refsect2>
43  * <title>Example pipelines</title>
44  * |[
45  * gst-launch-1.0 udpsrc caps="application/x-rtp" ! rtpptdemux ! fakesink
46  * ]| Takes an RTP stream and send the RTP packets with the first detected
47  * payload type to fakesink, discarding the other payload types.
48  * </refsect2>
49  */
50
51 /*
52  * Contributors:
53  * Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>
54  */
55 /*
56  * Status:
57  *  - works with the test_rtpdemux.c tool
58  *
59  * Check:
60  *  - is emitting a signal enough, or should we
61  *    use GstEvent to notify downstream elements
62  *    of the new packet... no?
63  *
64  * Notes:
65  *  - emits event both for new PTs, and whenever
66  *    a PT is changed
67  */
68
69 #ifdef HAVE_CONFIG_H
70 #include "config.h"
71 #endif
72
73 #include <string.h>
74 #include <gst/gst.h>
75 #include <gst/rtp/gstrtpbuffer.h>
76
77 #include "gstrtpptdemux.h"
78
79 /* generic templates */
80 static GstStaticPadTemplate rtp_pt_demux_sink_template =
81 GST_STATIC_PAD_TEMPLATE ("sink",
82     GST_PAD_SINK,
83     GST_PAD_ALWAYS,
84     GST_STATIC_CAPS ("application/x-rtp")
85     );
86
87 static GstStaticPadTemplate rtp_pt_demux_src_template =
88 GST_STATIC_PAD_TEMPLATE ("src_%u",
89     GST_PAD_SRC,
90     GST_PAD_SOMETIMES,
91     GST_STATIC_CAPS ("application/x-rtp, " "payload = (int) [ 0, 255 ]")
92     );
93
94 GST_DEBUG_CATEGORY_STATIC (gst_rtp_pt_demux_debug);
95 #define GST_CAT_DEFAULT gst_rtp_pt_demux_debug
96
97 /*
98  * Item for storing GstPad<->pt pairs.
99  */
100 struct _GstRtpPtDemuxPad
101 {
102   GstPad *pad;        /**< pointer to the actual pad */
103   gint pt;             /**< RTP payload-type attached to pad */
104   gboolean newcaps;
105 };
106
107 /* signals */
108 enum
109 {
110   SIGNAL_REQUEST_PT_MAP,
111   SIGNAL_NEW_PAYLOAD_TYPE,
112   SIGNAL_PAYLOAD_TYPE_CHANGE,
113   SIGNAL_CLEAR_PT_MAP,
114   LAST_SIGNAL
115 };
116
117 enum
118 {
119   PROP_0,
120   PROP_IGNORED_PTS,
121 };
122
123 #define gst_rtp_pt_demux_parent_class parent_class
124 G_DEFINE_TYPE (GstRtpPtDemux, gst_rtp_pt_demux, GST_TYPE_ELEMENT);
125
126 static void gst_rtp_pt_demux_finalize (GObject * object);
127
128 static void gst_rtp_pt_demux_release (GstRtpPtDemux * ptdemux);
129 static gboolean gst_rtp_pt_demux_setup (GstRtpPtDemux * ptdemux);
130
131 static gboolean gst_rtp_pt_demux_sink_event (GstPad * pad, GstObject * parent,
132     GstEvent * event);
133 static GstFlowReturn gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent,
134     GstBuffer * buf);
135 static GstStateChangeReturn gst_rtp_pt_demux_change_state (GstElement * element,
136     GstStateChange transition);
137 static void gst_rtp_pt_demux_clear_pt_map (GstRtpPtDemux * rtpdemux);
138
139 static GstPad *find_pad_for_pt (GstRtpPtDemux * rtpdemux, guint8 pt);
140
141 static gboolean gst_rtp_pt_demux_src_event (GstPad * pad, GstObject * parent,
142     GstEvent * event);
143
144
145 static guint gst_rtp_pt_demux_signals[LAST_SIGNAL] = { 0 };
146
147 static void
148 gst_rtp_pt_demux_set_property (GObject * object, guint prop_id,
149     const GValue * value, GParamSpec * pspec)
150 {
151   GstRtpPtDemux *rtpptdemux = GST_RTP_PT_DEMUX (object);
152
153   switch (prop_id) {
154     case PROP_IGNORED_PTS:
155       g_value_copy (value, &rtpptdemux->ignored_pts);
156       break;
157     default:
158       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
159       break;
160   }
161 }
162
163 static void
164 gst_rtp_pt_demux_get_property (GObject * object, guint prop_id,
165     GValue * value, GParamSpec * pspec)
166 {
167   GstRtpPtDemux *rtpptdemux = GST_RTP_PT_DEMUX (object);
168
169   switch (prop_id) {
170     case PROP_IGNORED_PTS:
171       g_value_copy (&rtpptdemux->ignored_pts, value);
172       break;
173     default:
174       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
175       break;
176   }
177 }
178
179 static void
180 gst_rtp_pt_demux_class_init (GstRtpPtDemuxClass * klass)
181 {
182   GObjectClass *gobject_klass;
183   GstElementClass *gstelement_klass;
184
185   gobject_klass = (GObjectClass *) klass;
186   gstelement_klass = (GstElementClass *) klass;
187
188   /**
189    * GstRtpPtDemux::request-pt-map:
190    * @demux: the object which received the signal
191    * @pt: the payload type
192    *
193    * Request the payload type as #GstCaps for @pt.
194    */
195   gst_rtp_pt_demux_signals[SIGNAL_REQUEST_PT_MAP] =
196       g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
197       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass, request_pt_map),
198       NULL, NULL, g_cclosure_marshal_generic, GST_TYPE_CAPS, 1, G_TYPE_UINT);
199
200   /**
201    * GstRtpPtDemux::new-payload-type:
202    * @demux: the object which received the signal
203    * @pt: the payload type
204    * @pad: the pad with the new payload
205    *
206    * Emited when a new payload type pad has been created in @demux.
207    */
208   gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE] =
209       g_signal_new ("new-payload-type", G_TYPE_FROM_CLASS (klass),
210       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass, new_payload_type),
211       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
212       GST_TYPE_PAD);
213
214   /**
215    * GstRtpPtDemux::payload-type-change:
216    * @demux: the object which received the signal
217    * @pt: the new payload type
218    *
219    * Emited when the payload type changed.
220    */
221   gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE] =
222       g_signal_new ("payload-type-change", G_TYPE_FROM_CLASS (klass),
223       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass,
224           payload_type_change), NULL, NULL, g_cclosure_marshal_VOID__UINT,
225       G_TYPE_NONE, 1, G_TYPE_UINT);
226
227   /**
228    * GstRtpPtDemux::clear-pt-map:
229    * @demux: the object which received the signal
230    *
231    * The application can call this signal to instruct the element to discard the
232    * currently cached payload type map.
233    */
234   gst_rtp_pt_demux_signals[SIGNAL_CLEAR_PT_MAP] =
235       g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
236       G_SIGNAL_ACTION | G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass,
237           clear_pt_map), NULL, NULL, g_cclosure_marshal_VOID__VOID,
238       G_TYPE_NONE, 0, G_TYPE_NONE);
239
240   gobject_klass->set_property = gst_rtp_pt_demux_set_property;
241   gobject_klass->get_property = gst_rtp_pt_demux_get_property;
242
243   /**
244    * GstRtpPtDemux:ignored-payload-types:
245    *
246    * If specified, packets with an ignored payload type will be dropped,
247    * instead of causing a new pad to be exposed for these to be pushed on.
248    *
249    * This is for example useful to drop FEC protection packets, as they
250    * need to go through the #GstRtpJitterBuffer, but cease to be useful
251    * past that point, #GstRtpBin will make use of this property for that
252    * purpose.
253    *
254    * Since: 1.14
255    */
256   g_object_class_install_property (gobject_klass, PROP_IGNORED_PTS,
257       gst_param_spec_array ("ignored-payload-types",
258           "Ignored payload types",
259           "Packets with these payload types will be dropped",
260           g_param_spec_int ("payload-types", "payload-types", "Payload types",
261               0, G_MAXINT, 0,
262               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
263           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
264
265   gobject_klass->finalize = gst_rtp_pt_demux_finalize;
266
267   gstelement_klass->change_state =
268       GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_change_state);
269
270   klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_clear_pt_map);
271
272   gst_element_class_add_static_pad_template (gstelement_klass,
273       &rtp_pt_demux_sink_template);
274   gst_element_class_add_static_pad_template (gstelement_klass,
275       &rtp_pt_demux_src_template);
276
277   gst_element_class_set_static_metadata (gstelement_klass, "RTP Demux",
278       "Demux/Network/RTP",
279       "Parses codec streams transmitted in the same RTP session",
280       "Kai Vehmanen <kai.vehmanen@nokia.com>");
281
282   GST_DEBUG_CATEGORY_INIT (gst_rtp_pt_demux_debug,
283       "rtpptdemux", 0, "RTP codec demuxer");
284 }
285
286 static void
287 gst_rtp_pt_demux_init (GstRtpPtDemux * ptdemux)
288 {
289   GstElementClass *klass = GST_ELEMENT_GET_CLASS (ptdemux);
290
291   ptdemux->sink =
292       gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
293           "sink"), "sink");
294   g_assert (ptdemux->sink != NULL);
295
296   gst_pad_set_chain_function (ptdemux->sink, gst_rtp_pt_demux_chain);
297   gst_pad_set_event_function (ptdemux->sink, gst_rtp_pt_demux_sink_event);
298
299   gst_element_add_pad (GST_ELEMENT (ptdemux), ptdemux->sink);
300
301   g_value_init (&ptdemux->ignored_pts, GST_TYPE_ARRAY);
302 }
303
304 static void
305 gst_rtp_pt_demux_finalize (GObject * object)
306 {
307   gst_rtp_pt_demux_release (GST_RTP_PT_DEMUX (object));
308
309   g_value_unset (&GST_RTP_PT_DEMUX (object)->ignored_pts);
310
311   G_OBJECT_CLASS (parent_class)->finalize (object);
312 }
313
314 static GstCaps *
315 gst_rtp_pt_demux_get_caps (GstRtpPtDemux * rtpdemux, guint pt)
316 {
317   GstCaps *caps;
318   GValue ret = { 0 };
319   GValue args[2] = { {0}, {0} };
320   GstCaps *sink_caps;
321
322   /* figure out the caps */
323   g_value_init (&args[0], GST_TYPE_ELEMENT);
324   g_value_set_object (&args[0], rtpdemux);
325   g_value_init (&args[1], G_TYPE_UINT);
326   g_value_set_uint (&args[1], pt);
327
328   g_value_init (&ret, GST_TYPE_CAPS);
329   g_value_set_boxed (&ret, NULL);
330
331   g_signal_emitv (args, gst_rtp_pt_demux_signals[SIGNAL_REQUEST_PT_MAP], 0,
332       &ret);
333
334   g_value_unset (&args[0]);
335   g_value_unset (&args[1]);
336   caps = g_value_dup_boxed (&ret);
337   g_value_unset (&ret);
338
339   sink_caps = gst_pad_get_current_caps (rtpdemux->sink);
340
341   if (sink_caps) {
342     if (caps == NULL) {
343       caps = gst_caps_ref (sink_caps);
344     } else {
345       GstStructure *s1;
346       GstStructure *s2;
347       guint ssrc;
348
349       caps = gst_caps_make_writable (caps);
350       s1 = gst_caps_get_structure (sink_caps, 0);
351       s2 = gst_caps_get_structure (caps, 0);
352
353       gst_structure_get_uint (s1, "ssrc", &ssrc);
354       gst_structure_set (s2, "ssrc", G_TYPE_UINT, ssrc, NULL);
355     }
356
357     gst_caps_unref (sink_caps);
358   }
359
360   GST_DEBUG ("pt %d, got caps %" GST_PTR_FORMAT, pt, caps);
361
362   return caps;
363 }
364
365 static void
366 gst_rtp_pt_demux_clear_pt_map (GstRtpPtDemux * rtpdemux)
367 {
368   GSList *walk;
369
370   GST_OBJECT_LOCK (rtpdemux);
371   GST_DEBUG ("clearing pt map");
372   for (walk = rtpdemux->srcpads; walk; walk = g_slist_next (walk)) {
373     GstRtpPtDemuxPad *pad = walk->data;
374
375     pad->newcaps = TRUE;
376   }
377   GST_OBJECT_UNLOCK (rtpdemux);
378 }
379
380 static gboolean
381 need_caps_for_pt (GstRtpPtDemux * rtpdemux, guint8 pt)
382 {
383   GSList *walk;
384   gboolean ret = FALSE;
385
386   GST_OBJECT_LOCK (rtpdemux);
387   for (walk = rtpdemux->srcpads; walk; walk = g_slist_next (walk)) {
388     GstRtpPtDemuxPad *pad = walk->data;
389
390     if (pad->pt == pt) {
391       ret = pad->newcaps;
392     }
393   }
394   GST_OBJECT_UNLOCK (rtpdemux);
395
396   return ret;
397 }
398
399
400 static void
401 clear_newcaps_for_pt (GstRtpPtDemux * rtpdemux, guint8 pt)
402 {
403   GSList *walk;
404
405   GST_OBJECT_LOCK (rtpdemux);
406   for (walk = rtpdemux->srcpads; walk; walk = g_slist_next (walk)) {
407     GstRtpPtDemuxPad *pad = walk->data;
408
409     if (pad->pt == pt) {
410       pad->newcaps = FALSE;
411       break;
412     }
413   }
414   GST_OBJECT_UNLOCK (rtpdemux);
415 }
416
417 static gboolean
418 forward_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
419 {
420   GstPad *srcpad = GST_PAD_CAST (user_data);
421
422   /* Stream start and caps have already been pushed */
423   if (GST_EVENT_TYPE (*event) >= GST_EVENT_SEGMENT)
424     gst_pad_push_event (srcpad, gst_event_ref (*event));
425
426   return TRUE;
427 }
428
429 static gboolean
430 gst_rtp_pt_demux_pt_is_ignored (GstRtpPtDemux * ptdemux, guint8 pt)
431 {
432   gboolean ret = FALSE;
433   guint i;
434
435   for (i = 0; i < gst_value_array_get_size (&ptdemux->ignored_pts); i++) {
436     const GValue *tmp = gst_value_array_get_value (&ptdemux->ignored_pts, i);
437
438     if (g_value_get_int (tmp) == pt) {
439       ret = TRUE;
440       break;
441     }
442   }
443
444   return ret;
445 }
446
447 static GstFlowReturn
448 gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
449 {
450   GstFlowReturn ret = GST_FLOW_OK;
451   GstRtpPtDemux *rtpdemux;
452   guint8 pt;
453   GstPad *srcpad;
454   GstCaps *caps;
455   GstRTPBuffer rtp = { NULL };
456
457   rtpdemux = GST_RTP_PT_DEMUX (parent);
458
459   if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp))
460     goto invalid_buffer;
461
462   pt = gst_rtp_buffer_get_payload_type (&rtp);
463   gst_rtp_buffer_unmap (&rtp);
464
465   if (gst_rtp_pt_demux_pt_is_ignored (rtpdemux, pt))
466     goto ignored;
467
468   GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt);
469
470   srcpad = find_pad_for_pt (rtpdemux, pt);
471   if (srcpad == NULL) {
472     /* new PT, create a src pad */
473     GstRtpPtDemuxPad *rtpdemuxpad;
474     GstElementClass *klass;
475     GstPadTemplate *templ;
476     gchar *padname;
477
478     caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
479     if (!caps)
480       goto no_caps;
481
482     if (gst_rtp_pt_demux_pt_is_ignored (rtpdemux, pt))
483       goto ignored;
484
485     klass = GST_ELEMENT_GET_CLASS (rtpdemux);
486     templ = gst_element_class_get_pad_template (klass, "src_%u");
487     padname = g_strdup_printf ("src_%u", pt);
488     srcpad = gst_pad_new_from_template (templ, padname);
489     gst_pad_use_fixed_caps (srcpad);
490     g_free (padname);
491     gst_pad_set_event_function (srcpad, gst_rtp_pt_demux_src_event);
492
493     GST_DEBUG ("Adding pt=%d to the list.", pt);
494     rtpdemuxpad = g_slice_new0 (GstRtpPtDemuxPad);
495     rtpdemuxpad->pt = pt;
496     rtpdemuxpad->newcaps = FALSE;
497     rtpdemuxpad->pad = srcpad;
498     gst_object_ref (srcpad);
499     GST_OBJECT_LOCK (rtpdemux);
500     rtpdemux->srcpads = g_slist_append (rtpdemux->srcpads, rtpdemuxpad);
501     GST_OBJECT_UNLOCK (rtpdemux);
502
503     gst_pad_set_active (srcpad, TRUE);
504
505
506     /* First push the stream-start event, it must always come first */
507     gst_pad_push_event (srcpad,
508         gst_pad_get_sticky_event (rtpdemux->sink, GST_EVENT_STREAM_START, 0));
509
510     /* Then caps event is sent */
511     caps = gst_caps_make_writable (caps);
512     gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
513     gst_pad_set_caps (srcpad, caps);
514     gst_caps_unref (caps);
515
516     /* First sticky events on sink pad are forwarded to the new src pad */
517     gst_pad_sticky_events_foreach (rtpdemux->sink, forward_sticky_events,
518         srcpad);
519
520     gst_element_add_pad (GST_ELEMENT_CAST (rtpdemux), srcpad);
521
522     GST_DEBUG ("emitting new-payload-type for pt %d", pt);
523     g_signal_emit (G_OBJECT (rtpdemux),
524         gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad);
525   }
526
527   if (pt != rtpdemux->last_pt) {
528     gint emit_pt = pt;
529
530     /* our own signal with an extra flag that this is the only pad */
531     rtpdemux->last_pt = pt;
532     GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt);
533     g_signal_emit (G_OBJECT (rtpdemux),
534         gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt);
535   }
536
537   while (need_caps_for_pt (rtpdemux, pt)) {
538     GST_DEBUG ("need new caps for %d", pt);
539     caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
540     if (!caps)
541       goto no_caps;
542
543     clear_newcaps_for_pt (rtpdemux, pt);
544
545     caps = gst_caps_make_writable (caps);
546     gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
547     gst_pad_set_caps (srcpad, caps);
548     gst_caps_unref (caps);
549   }
550
551   /* push to srcpad */
552   ret = gst_pad_push (srcpad, buf);
553
554   gst_object_unref (srcpad);
555
556   return ret;
557
558 ignored:
559   {
560     GST_DEBUG_OBJECT (rtpdemux, "Dropped buffer for pt %d", pt);
561     gst_buffer_unref (buf);
562     return GST_FLOW_OK;
563   }
564
565   /* ERRORS */
566 invalid_buffer:
567   {
568     /* this should not be fatal */
569     GST_ELEMENT_WARNING (rtpdemux, STREAM, DEMUX, (NULL),
570         ("Dropping invalid RTP payload"));
571     gst_buffer_unref (buf);
572     return GST_FLOW_ERROR;
573   }
574 no_caps:
575   {
576     GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
577         ("Could not get caps for payload"));
578     gst_buffer_unref (buf);
579     if (srcpad)
580       gst_object_unref (srcpad);
581     return GST_FLOW_ERROR;
582   }
583 }
584
585 static GstPad *
586 find_pad_for_pt (GstRtpPtDemux * rtpdemux, guint8 pt)
587 {
588   GstPad *respad = NULL;
589   GSList *walk;
590
591   GST_OBJECT_LOCK (rtpdemux);
592   for (walk = rtpdemux->srcpads; walk; walk = g_slist_next (walk)) {
593     GstRtpPtDemuxPad *pad = walk->data;
594
595     if (pad->pt == pt) {
596       respad = gst_object_ref (pad->pad);
597       break;
598     }
599   }
600   GST_OBJECT_UNLOCK (rtpdemux);
601
602   return respad;
603 }
604
605 static gboolean
606 gst_rtp_pt_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
607 {
608   GstRtpPtDemux *rtpdemux;
609   gboolean res = FALSE;
610
611   rtpdemux = GST_RTP_PT_DEMUX (parent);
612
613   switch (GST_EVENT_TYPE (event)) {
614     case GST_EVENT_CAPS:
615     {
616       gst_rtp_pt_demux_clear_pt_map (rtpdemux);
617       /* don't forward the event, we cleared the ptmap and on the next buffer we
618        * will add the pt to the caps and push a new caps event */
619       gst_event_unref (event);
620       res = TRUE;
621       break;
622     }
623     case GST_EVENT_CUSTOM_DOWNSTREAM:
624     {
625       const GstStructure *s;
626
627       s = gst_event_get_structure (event);
628
629       if (gst_structure_has_name (s, "GstRTPPacketLost")) {
630         GstPad *srcpad = find_pad_for_pt (rtpdemux, rtpdemux->last_pt);
631
632         if (srcpad) {
633           res = gst_pad_push_event (srcpad, event);
634           gst_object_unref (srcpad);
635         } else {
636           gst_event_unref (event);
637         }
638
639       } else {
640         res = gst_pad_event_default (pad, parent, event);
641       }
642       break;
643     }
644     default:
645       res = gst_pad_event_default (pad, parent, event);
646       break;
647   }
648
649   return res;
650 }
651
652
653 static gboolean
654 gst_rtp_pt_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
655 {
656   GstRtpPtDemux *demux;
657   const GstStructure *s;
658
659   demux = GST_RTP_PT_DEMUX (parent);
660
661   switch (GST_EVENT_TYPE (event)) {
662     case GST_EVENT_CUSTOM_UPSTREAM:
663     case GST_EVENT_CUSTOM_BOTH:
664     case GST_EVENT_CUSTOM_BOTH_OOB:
665       s = gst_event_get_structure (event);
666       if (s && !gst_structure_has_field (s, "payload")) {
667         GSList *walk;
668
669         GST_OBJECT_LOCK (demux);
670         for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
671           GstRtpPtDemuxPad *dpad = (GstRtpPtDemuxPad *) walk->data;
672
673           if (dpad->pad == pad) {
674             GstStructure *ws;
675
676             event =
677                 GST_EVENT_CAST (gst_mini_object_make_writable
678                 (GST_MINI_OBJECT_CAST (event)));
679             ws = gst_event_writable_structure (event);
680             gst_structure_set (ws, "payload", G_TYPE_UINT, dpad->pt, NULL);
681             break;
682           }
683         }
684         GST_OBJECT_UNLOCK (demux);
685       }
686       break;
687     default:
688       break;
689   }
690
691   return gst_pad_event_default (pad, parent, event);
692 }
693
694 /*
695  * Reserves resources for the object.
696  */
697 static gboolean
698 gst_rtp_pt_demux_setup (GstRtpPtDemux * ptdemux)
699 {
700   ptdemux->srcpads = NULL;
701   ptdemux->last_pt = 0xFFFF;
702
703   return TRUE;
704 }
705
706 /*
707  * Free resources for the object.
708  */
709 static void
710 gst_rtp_pt_demux_release (GstRtpPtDemux * ptdemux)
711 {
712   GSList *tmppads;
713   GSList *walk;
714
715   GST_OBJECT_LOCK (ptdemux);
716   tmppads = ptdemux->srcpads;
717   ptdemux->srcpads = NULL;
718   GST_OBJECT_UNLOCK (ptdemux);
719
720   for (walk = tmppads; walk; walk = g_slist_next (walk)) {
721     GstRtpPtDemuxPad *pad = walk->data;
722
723     gst_pad_set_active (pad->pad, FALSE);
724     gst_element_remove_pad (GST_ELEMENT_CAST (ptdemux), pad->pad);
725     g_slice_free (GstRtpPtDemuxPad, pad);
726   }
727   g_slist_free (tmppads);
728 }
729
730 static GstStateChangeReturn
731 gst_rtp_pt_demux_change_state (GstElement * element, GstStateChange transition)
732 {
733   GstStateChangeReturn ret;
734   GstRtpPtDemux *ptdemux;
735
736   ptdemux = GST_RTP_PT_DEMUX (element);
737
738   switch (transition) {
739     case GST_STATE_CHANGE_NULL_TO_READY:
740       if (gst_rtp_pt_demux_setup (ptdemux) != TRUE)
741         ret = GST_STATE_CHANGE_FAILURE;
742       break;
743     case GST_STATE_CHANGE_READY_TO_PAUSED:
744     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
745     default:
746       break;
747   }
748
749   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
750
751   switch (transition) {
752     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
753     case GST_STATE_CHANGE_PAUSED_TO_READY:
754       break;
755     case GST_STATE_CHANGE_READY_TO_NULL:
756       gst_rtp_pt_demux_release (ptdemux);
757       break;
758     default:
759       break;
760   }
761
762   return ret;
763 }