39706e8c150593da4b94944b514551b40c94fd95
[platform/upstream/gstreamer.git] / gst / playback / gststreamselector.c
1 /* GStreamer
2  * Copyright (C) 2003 Julien Moutte <julien@moutte.net>
3  * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
4  * Copyright (C) 2005 Jan Schmidt <thaytan@mad.scientist.com>
5  * Copyright (C) 2007 Wim Taymans <wim.taymans@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <string.h>
28
29 #include "gststreamselector.h"
30
31 GST_DEBUG_CATEGORY_STATIC (stream_selector_debug);
32 #define GST_CAT_DEFAULT stream_selector_debug
33
34 static GstStaticPadTemplate gst_stream_selector_sink_factory =
35 GST_STATIC_PAD_TEMPLATE ("sink_%u",
36     GST_PAD_SINK,
37     GST_PAD_REQUEST,
38     GST_STATIC_CAPS_ANY);
39
40 static GstStaticPadTemplate gst_stream_selector_src_factory =
41 GST_STATIC_PAD_TEMPLATE ("src",
42     GST_PAD_SRC,
43     GST_PAD_ALWAYS,
44     GST_STATIC_CAPS_ANY);
45
46 enum
47 {
48   PROP_0,
49   PROP_N_PADS,
50   PROP_ACTIVE_PAD,
51   PROP_LAST
52 };
53
54 static gboolean gst_stream_selector_is_active_sinkpad (GstStreamSelector * sel,
55     GstPad * pad);
56 static GstPad *gst_stream_selector_activate_sinkpad (GstStreamSelector * sel,
57     GstPad * pad);
58 static GstPad *gst_stream_selector_get_linked_pad (GstPad * pad,
59     gboolean strict);
60
61 #define GST_TYPE_SELECTOR_PAD \
62   (gst_selector_pad_get_type())
63 #define GST_SELECTOR_PAD(obj) \
64   (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SELECTOR_PAD, GstSelectorPad))
65 #define GST_SELECTOR_PAD_CLASS(klass) \
66   (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SELECTOR_PAD, GstSelectorPadClass))
67 #define GST_IS_SELECTOR_PAD(obj) \
68   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SELECTOR_PAD))
69 #define GST_IS_SELECTOR_PAD_CLASS(klass) \
70   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SELECTOR_PAD))
71 #define GST_SELECTOR_PAD_CAST(obj) \
72   ((GstSelectorPad *)(obj))
73
74 typedef struct _GstSelectorPad GstSelectorPad;
75 typedef struct _GstSelectorPadClass GstSelectorPadClass;
76
77 struct _GstSelectorPad
78 {
79   GstPad parent;
80
81   gboolean active;
82   gboolean eos;
83   gboolean segment_pending;
84   GstSegment segment;
85   GstTagList *tags;
86 };
87
88 struct _GstSelectorPadClass
89 {
90   GstPadClass parent;
91 };
92
93 static void gst_selector_pad_finalize (GObject * object);
94
95 static void gst_selector_pad_get_property (GObject * object,
96     guint prop_id, GValue * value, GParamSpec * pspec);
97
98 static void gst_selector_pad_reset (GstSelectorPad * pad);
99 static gboolean gst_selector_pad_event (GstPad * pad, GstEvent * event);
100 static GstCaps *gst_selector_pad_getcaps (GstPad * pad, GstCaps * filter);
101 static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf);
102
103 enum
104 {
105   PROP_PAD_0,
106   PROP_PAD_TAGS,
107   PROP_PAD_ACTIVE,
108   PROP_PAD_LAST
109 };
110
111 GType gst_selector_pad_get_type (void);
112 G_DEFINE_TYPE (GstSelectorPad, gst_selector_pad, GST_TYPE_PAD);
113
114 static void
115 gst_selector_pad_class_init (GstSelectorPadClass * klass)
116 {
117   GObjectClass *gobject_class;
118
119   gobject_class = (GObjectClass *) klass;
120
121   gobject_class->finalize = gst_selector_pad_finalize;
122   gobject_class->get_property = gst_selector_pad_get_property;
123
124   g_object_class_install_property (gobject_class, PROP_PAD_TAGS,
125       g_param_spec_boxed ("tags", "Tags",
126           "The currently active tags on the pad", GST_TYPE_TAG_LIST,
127           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
128
129   g_object_class_install_property (gobject_class, PROP_PAD_ACTIVE,
130       g_param_spec_boolean ("active", "Active",
131           "If the pad is currently active", FALSE,
132           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
133 }
134
135 static void
136 gst_selector_pad_init (GstSelectorPad * pad)
137 {
138   gst_selector_pad_reset (pad);
139 }
140
141 static void
142 gst_selector_pad_finalize (GObject * object)
143 {
144   GstSelectorPad *pad;
145
146   pad = GST_SELECTOR_PAD_CAST (object);
147
148   if (pad->tags)
149     gst_tag_list_free (pad->tags);
150
151   G_OBJECT_CLASS (gst_selector_pad_parent_class)->finalize (object);
152 }
153
154 static void
155 gst_selector_pad_get_property (GObject * object,
156     guint prop_id, GValue * value, GParamSpec * pspec)
157 {
158   GstSelectorPad *pad;
159
160   pad = GST_SELECTOR_PAD (object);
161
162   switch (prop_id) {
163     case PROP_PAD_TAGS:
164       GST_OBJECT_LOCK (object);
165       g_value_set_boxed (value, pad->tags);
166       GST_OBJECT_UNLOCK (object);
167       break;
168     case PROP_PAD_ACTIVE:
169     {
170       GstStreamSelector *sel;
171
172       sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
173       g_value_set_boolean (value, gst_stream_selector_is_active_sinkpad (sel,
174               GST_PAD_CAST (pad)));
175       gst_object_unref (sel);
176       break;
177     }
178     default:
179       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
180       break;
181   }
182 }
183
184 static void
185 gst_selector_pad_reset (GstSelectorPad * pad)
186 {
187   pad->active = FALSE;
188   pad->eos = FALSE;
189   gst_segment_init (&pad->segment, GST_FORMAT_UNDEFINED);
190 }
191
192 static gboolean
193 gst_selector_pad_event (GstPad * pad, GstEvent * event)
194 {
195   gboolean res = TRUE;
196   gboolean forward = TRUE;
197   GstStreamSelector *sel;
198   GstSelectorPad *selpad;
199   GstPad *active_sinkpad;
200
201   sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
202   selpad = GST_SELECTOR_PAD_CAST (pad);
203
204   /* only forward if we are dealing with the active sinkpad */
205   active_sinkpad = gst_stream_selector_activate_sinkpad (sel, pad);
206   forward = (active_sinkpad == pad);
207
208   switch (GST_EVENT_TYPE (event)) {
209     case GST_EVENT_FLUSH_STOP:
210       gst_selector_pad_reset (selpad);
211       break;
212     case GST_EVENT_SEGMENT:
213     {
214       gst_event_copy_segment (event, &selpad->segment);
215
216       GST_DEBUG_OBJECT (selpad, "configured SEGMENT %" GST_SEGMENT_FORMAT,
217           &selpad->segment);
218       /* if we are not going to forward the segment, mark the segment as
219        * pending */
220       if (!forward)
221         selpad->segment_pending = TRUE;
222       break;
223     }
224     case GST_EVENT_TAG:
225     {
226       GstTagList *tags;
227
228       GST_OBJECT_LOCK (selpad);
229       if (selpad->tags)
230         gst_tag_list_free (selpad->tags);
231       gst_event_parse_tag (event, &tags);
232       if (tags)
233         tags = gst_tag_list_copy (tags);
234       selpad->tags = tags;
235       GST_DEBUG_OBJECT (sel, "received tags %" GST_PTR_FORMAT, selpad->tags);
236       GST_OBJECT_UNLOCK (selpad);
237       break;
238     }
239     case GST_EVENT_EOS:
240       selpad->eos = TRUE;
241       break;
242     default:
243       break;
244   }
245   if (forward)
246     res = gst_pad_push_event (sel->srcpad, event);
247   else
248     gst_event_unref (event);
249
250   gst_object_unref (sel);
251
252   return res;
253 }
254
255 static GstCaps *
256 gst_selector_pad_getcaps (GstPad * pad, GstCaps * filter)
257 {
258   GstStreamSelector *sel;
259   GstCaps *caps;
260
261   sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
262
263   GST_DEBUG_OBJECT (sel, "Getting caps of srcpad peer");
264   caps = gst_pad_peer_get_caps (sel->srcpad, filter);
265   if (caps == NULL)
266     caps = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
267
268   gst_object_unref (sel);
269
270   return caps;
271 }
272
273 static GstFlowReturn
274 gst_selector_pad_chain (GstPad * pad, GstBuffer * buf)
275 {
276   GstStreamSelector *sel;
277   GstFlowReturn res;
278   GstPad *active_sinkpad;
279   GstSelectorPad *selpad;
280   GstClockTime timestamp;
281   GstSegment *seg;
282
283   sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
284   selpad = GST_SELECTOR_PAD_CAST (pad);
285   seg = &selpad->segment;
286
287   active_sinkpad = gst_stream_selector_activate_sinkpad (sel, pad);
288
289   timestamp = GST_BUFFER_TIMESTAMP (buf);
290   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
291     GST_DEBUG_OBJECT (sel, "received timestamp %" GST_TIME_FORMAT,
292         GST_TIME_ARGS (timestamp));
293     seg->position = timestamp;
294   }
295
296   /* Ignore buffers from pads except the selected one */
297   if (pad != active_sinkpad)
298     goto ignore;
299
300   /* if we have a pending segment, push it out now */
301   if (selpad->segment_pending) {
302     gst_pad_push_event (sel->srcpad, gst_event_new_segment (seg));
303     selpad->segment_pending = FALSE;
304   }
305
306   /* forward */
307   GST_DEBUG_OBJECT (sel, "Forwarding buffer %p from pad %s:%s", buf,
308       GST_DEBUG_PAD_NAME (pad));
309   res = gst_pad_push (sel->srcpad, buf);
310 done:
311   gst_object_unref (sel);
312   return res;
313   /* dropped buffers */
314 ignore:
315   {
316     GST_DEBUG_OBJECT (sel, "Ignoring buffer %p from pad %s:%s",
317         buf, GST_DEBUG_PAD_NAME (pad));
318     gst_buffer_unref (buf);
319     res = GST_FLOW_NOT_LINKED;
320     goto done;
321   }
322 }
323
324 static void gst_stream_selector_dispose (GObject * object);
325
326 static void gst_stream_selector_set_property (GObject * object,
327     guint prop_id, const GValue * value, GParamSpec * pspec);
328 static void gst_stream_selector_get_property (GObject * object,
329     guint prop_id, GValue * value, GParamSpec * pspec);
330
331 static GstPad *gst_stream_selector_request_new_pad (GstElement * element,
332     GstPadTemplate * templ, const gchar * unused, const GstCaps * caps);
333 static void gst_stream_selector_release_pad (GstElement * element,
334     GstPad * pad);
335 static GstIterator *gst_stream_selector_pad_iterate_linked_pads (GstPad * pad);
336 static GstCaps *gst_stream_selector_getcaps (GstPad * pad, GstCaps * filter);
337
338 #define gst_stream_selector_parent_class parent_class
339 G_DEFINE_TYPE (GstStreamSelector, gst_stream_selector, GST_TYPE_ELEMENT);
340
341 static void
342 gst_stream_selector_class_init (GstStreamSelectorClass * klass)
343 {
344   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
345   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
346
347   parent_class = g_type_class_peek_parent (klass);
348
349   gobject_class->dispose = gst_stream_selector_dispose;
350
351   gobject_class->set_property = gst_stream_selector_set_property;
352   gobject_class->get_property = gst_stream_selector_get_property;
353
354   g_object_class_install_property (gobject_class, PROP_N_PADS,
355       g_param_spec_uint ("n-pads", "Number of Pads",
356           "The number of sink pads", 0, G_MAXUINT, 0,
357           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
358   g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
359       g_param_spec_object ("active-pad", "Active Pad",
360           "The currently active sink pad", GST_TYPE_PAD,
361           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
362
363   gstelement_class->request_new_pad = gst_stream_selector_request_new_pad;
364   gstelement_class->release_pad = gst_stream_selector_release_pad;
365
366   gst_element_class_set_details_simple (gstelement_class,
367       "StreamSelector", "Generic",
368       "N-to-1 input stream_selectoring",
369       "Julien Moutte <julien@moutte.net>, "
370       "Jan Schmidt <thaytan@mad.scientist.com>, "
371       "Wim Taymans <wim.taymans@gmail.com>");
372
373   gst_element_class_add_pad_template (gstelement_class,
374       gst_static_pad_template_get (&gst_stream_selector_sink_factory));
375   gst_element_class_add_pad_template (gstelement_class,
376       gst_static_pad_template_get (&gst_stream_selector_src_factory));
377
378   GST_DEBUG_CATEGORY_INIT (stream_selector_debug,
379       "streamselector", 0, "A stream-selector element");
380 }
381
382 static void
383 gst_stream_selector_init (GstStreamSelector * sel)
384 {
385   sel->srcpad = gst_pad_new ("src", GST_PAD_SRC);
386   gst_pad_set_iterate_internal_links_function (sel->srcpad,
387       GST_DEBUG_FUNCPTR (gst_stream_selector_pad_iterate_linked_pads));
388   gst_pad_set_getcaps_function (sel->srcpad,
389       GST_DEBUG_FUNCPTR (gst_stream_selector_getcaps));
390   gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
391   /* sinkpad management */
392   sel->padcount = 0;
393   sel->active_sinkpad = NULL;
394   gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED);
395 }
396
397 static void
398 gst_stream_selector_dispose (GObject * object)
399 {
400   GstStreamSelector *sel = GST_STREAM_SELECTOR (object);
401
402   if (sel->active_sinkpad) {
403     gst_object_unref (sel->active_sinkpad);
404     sel->active_sinkpad = NULL;
405   }
406
407   G_OBJECT_CLASS (parent_class)->dispose (object);
408 }
409
410 static void
411 gst_stream_selector_set_property (GObject * object, guint prop_id,
412     const GValue * value, GParamSpec * pspec)
413 {
414   GstStreamSelector *sel = GST_STREAM_SELECTOR (object);
415
416   switch (prop_id) {
417     case PROP_ACTIVE_PAD:
418     {
419       GstPad *pad = NULL;
420       GstPad **active_pad_p;
421
422       pad = g_value_get_object (value);
423
424       GST_OBJECT_LOCK (object);
425       if (pad != sel->active_sinkpad) {
426         GstSelectorPad *selpad;
427
428         selpad = GST_SELECTOR_PAD_CAST (pad);
429         /* we can only activate pads that have data received */
430         if (selpad && !selpad->active) {
431           GST_DEBUG_OBJECT (sel, "No data received on pad %" GST_PTR_FORMAT,
432               pad);
433         } else {
434           active_pad_p = &sel->active_sinkpad;
435           gst_object_replace ((GstObject **) active_pad_p,
436               GST_OBJECT_CAST (pad));
437           GST_DEBUG_OBJECT (sel, "New active pad is %" GST_PTR_FORMAT,
438               sel->active_sinkpad);
439         }
440       }
441       GST_OBJECT_UNLOCK (object);
442       break;
443     }
444     default:
445       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
446       break;
447   }
448 }
449
450 static void
451 gst_stream_selector_get_property (GObject * object, guint prop_id,
452     GValue * value, GParamSpec * pspec)
453 {
454   GstStreamSelector *sel = GST_STREAM_SELECTOR (object);
455
456   switch (prop_id) {
457     case PROP_N_PADS:
458       GST_OBJECT_LOCK (object);
459       g_value_set_uint (value, sel->n_pads);
460       GST_OBJECT_UNLOCK (object);
461       break;
462     case PROP_ACTIVE_PAD:{
463       GST_OBJECT_LOCK (object);
464       g_value_set_object (value, sel->active_sinkpad);
465       GST_OBJECT_UNLOCK (object);
466       break;
467     }
468     default:
469       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
470       break;
471   }
472 }
473
474 static GstPad *
475 gst_stream_selector_get_linked_pad (GstPad * pad, gboolean strict)
476 {
477   GstStreamSelector *sel;
478   GstPad *otherpad = NULL;
479
480   sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
481
482   GST_OBJECT_LOCK (sel);
483   if (pad == sel->srcpad)
484     otherpad = sel->active_sinkpad;
485   else if (pad == sel->active_sinkpad || !strict)
486     otherpad = sel->srcpad;
487   if (otherpad)
488     gst_object_ref (otherpad);
489   GST_OBJECT_UNLOCK (sel);
490   gst_object_unref (sel);
491   return otherpad;
492 }
493
494 static GstCaps *
495 gst_stream_selector_getcaps (GstPad * pad, GstCaps * filter)
496 {
497   GstPad *otherpad;
498   GstObject *parent;
499   GstCaps *caps;
500
501   otherpad = gst_stream_selector_get_linked_pad (pad, FALSE);
502   parent = gst_object_get_parent (GST_OBJECT (pad));
503   if (!otherpad) {
504     GST_DEBUG_OBJECT (parent,
505         "Pad %s:%s not linked, returning ANY", GST_DEBUG_PAD_NAME (pad));
506     caps = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
507   } else {
508     GST_DEBUG_OBJECT (parent,
509         "Pad %s:%s is linked (to %s:%s), returning peer caps",
510         GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (otherpad));
511     /* if the peer has caps, use those. If the pad is not linked, this function
512      * returns NULL and we return ANY */
513     if (!(caps = gst_pad_peer_get_caps (otherpad, filter)))
514       caps = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
515     gst_object_unref (otherpad);
516   }
517
518   gst_object_unref (parent);
519   return caps;
520 }
521
522 /* check if the pad is the active sinkpad */
523 static gboolean
524 gst_stream_selector_is_active_sinkpad (GstStreamSelector * sel, GstPad * pad)
525 {
526   gboolean res;
527
528   GST_OBJECT_LOCK (sel);
529   res = (pad == sel->active_sinkpad);
530   GST_OBJECT_UNLOCK (sel);
531
532   return res;
533 }
534
535 /* Get or create the active sinkpad */
536 static GstPad *
537 gst_stream_selector_activate_sinkpad (GstStreamSelector * sel, GstPad * pad)
538 {
539   GstPad *active_sinkpad;
540   GstSelectorPad *selpad;
541
542   selpad = GST_SELECTOR_PAD_CAST (pad);
543
544   GST_OBJECT_LOCK (sel);
545   selpad->active = TRUE;
546   active_sinkpad = sel->active_sinkpad;
547   if (active_sinkpad == NULL) {
548     /* first pad we get an alloc on becomes the activated pad by default */
549     active_sinkpad = sel->active_sinkpad = gst_object_ref (pad);
550     GST_DEBUG_OBJECT (sel, "Activating pad %s:%s", GST_DEBUG_PAD_NAME (pad));
551   }
552   GST_OBJECT_UNLOCK (sel);
553
554   return active_sinkpad;
555 }
556
557 static GstIterator *
558 gst_stream_selector_pad_iterate_linked_pads (GstPad * pad)
559 {
560   GstStreamSelector *sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
561   GValue value = { 0, };
562   GstPad *otherpad;
563   GstIterator *ret = NULL;
564
565   otherpad = gst_stream_selector_get_linked_pad (pad, TRUE);
566   if (otherpad) {
567     g_value_init (&value, GST_TYPE_PAD);
568     g_value_set_object (&value, otherpad);
569     ret = gst_iterator_new_single (GST_TYPE_PAD, &value);
570     g_value_unset (&value);
571     gst_object_unref (otherpad);
572   }
573   gst_object_unref (sel);
574
575   return ret;
576 }
577
578 static GstPad *
579 gst_stream_selector_request_new_pad (GstElement * element,
580     GstPadTemplate * templ, const gchar * unused, const GstCaps * caps)
581 {
582   GstStreamSelector *sel;
583   gchar *name = NULL;
584   GstPad *sinkpad = NULL;
585
586   sel = GST_STREAM_SELECTOR (element);
587   g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
588   GST_LOG_OBJECT (sel, "Creating new pad %d", sel->padcount);
589   GST_OBJECT_LOCK (sel);
590   name = g_strdup_printf ("sink_%u", sel->padcount++);
591   sinkpad = g_object_new (GST_TYPE_SELECTOR_PAD,
592       "name", name, "direction", templ->direction, "template", templ, NULL);
593   g_free (name);
594   sel->n_pads++;
595   GST_OBJECT_UNLOCK (sel);
596
597   gst_pad_set_event_function (sinkpad,
598       GST_DEBUG_FUNCPTR (gst_selector_pad_event));
599   gst_pad_set_getcaps_function (sinkpad,
600       GST_DEBUG_FUNCPTR (gst_selector_pad_getcaps));
601   gst_pad_set_chain_function (sinkpad,
602       GST_DEBUG_FUNCPTR (gst_selector_pad_chain));
603   gst_pad_set_iterate_internal_links_function (sinkpad,
604       GST_DEBUG_FUNCPTR (gst_stream_selector_pad_iterate_linked_pads));
605
606   gst_pad_set_active (sinkpad, TRUE);
607   gst_element_add_pad (GST_ELEMENT (sel), sinkpad);
608   return sinkpad;
609 }
610
611 static void
612 gst_stream_selector_release_pad (GstElement * element, GstPad * pad)
613 {
614   GstStreamSelector *sel;
615
616   sel = GST_STREAM_SELECTOR (element);
617   GST_LOG_OBJECT (sel, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
618
619   GST_OBJECT_LOCK (sel);
620   /* if the pad was the active pad, makes us select a new one */
621   if (sel->active_sinkpad == pad) {
622     GST_DEBUG_OBJECT (sel, "Deactivating pad %s:%s", GST_DEBUG_PAD_NAME (pad));
623     sel->active_sinkpad = NULL;
624   }
625   sel->n_pads--;
626   GST_OBJECT_UNLOCK (sel);
627
628   gst_pad_set_active (pad, FALSE);
629   gst_element_remove_pad (GST_ELEMENT (sel), pad);
630 }