inputselector: Use iterate internal links instead of deprecated get internal links
[platform/upstream/gstreamer.git] / plugins / elements / gstinputselector.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  * Copyright (C) 2007 Andy Wingo <wingo@pobox.com>
7  * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /**
26  * SECTION:element-input-selector
27  * @see_also: #GstOutputSelector
28  *
29  * Direct one out of N input streams to the output pad.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <string.h>
37
38 #include "gstinputselector.h"
39 #include "gstselector-marshal.h"
40
41 GST_DEBUG_CATEGORY_STATIC (input_selector_debug);
42 #define GST_CAT_DEFAULT input_selector_debug
43
44 static const GstElementDetails gst_input_selector_details =
45 GST_ELEMENT_DETAILS ("Input selector",
46     "Generic",
47     "N-to-1 input stream selectoring",
48     "Julien Moutte <julien@moutte.net>\n"
49     "Ronald S. Bultje <rbultje@ronald.bitfreak.net>\n"
50     "Jan Schmidt <thaytan@mad.scientist.com>\n"
51     "Wim Taymans <wim.taymans@gmail.com>");
52
53 static GstStaticPadTemplate gst_input_selector_sink_factory =
54 GST_STATIC_PAD_TEMPLATE ("sink%d",
55     GST_PAD_SINK,
56     GST_PAD_REQUEST,
57     GST_STATIC_CAPS_ANY);
58
59 static GstStaticPadTemplate gst_input_selector_src_factory =
60 GST_STATIC_PAD_TEMPLATE ("src",
61     GST_PAD_SRC,
62     GST_PAD_ALWAYS,
63     GST_STATIC_CAPS_ANY);
64
65 enum
66 {
67   PROP_0,
68   PROP_N_PADS,
69   PROP_ACTIVE_PAD,
70   PROP_SELECT_ALL,
71   PROP_LAST
72 };
73
74 #define DEFAULT_PAD_ALWAYS_OK   TRUE
75
76 enum
77 {
78   PROP_PAD_0,
79   PROP_PAD_RUNNING_TIME,
80   PROP_PAD_TAGS,
81   PROP_PAD_ACTIVE,
82   PROP_PAD_ALWAYS_OK,
83   PROP_PAD_LAST
84 };
85
86 enum
87 {
88   /* methods */
89   SIGNAL_BLOCK,
90   SIGNAL_SWITCH,
91   LAST_SIGNAL
92 };
93 static guint gst_input_selector_signals[LAST_SIGNAL] = { 0 };
94
95 static gboolean gst_input_selector_is_active_sinkpad (GstInputSelector * sel,
96     GstPad * pad);
97 static GstPad *gst_input_selector_activate_sinkpad (GstInputSelector * sel,
98     GstPad * pad);
99 static GstPad *gst_input_selector_get_linked_pad (GstPad * pad,
100     gboolean strict);
101 static gboolean gst_input_selector_check_eos (GstElement * selector);
102
103 #define GST_TYPE_SELECTOR_PAD \
104   (gst_selector_pad_get_type())
105 #define GST_SELECTOR_PAD(obj) \
106   (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SELECTOR_PAD, GstSelectorPad))
107 #define GST_SELECTOR_PAD_CLASS(klass) \
108   (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SELECTOR_PAD, GstSelectorPadClass))
109 #define GST_IS_SELECTOR_PAD(obj) \
110   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SELECTOR_PAD))
111 #define GST_IS_SELECTOR_PAD_CLASS(klass) \
112   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SELECTOR_PAD))
113 #define GST_SELECTOR_PAD_CAST(obj) \
114   ((GstSelectorPad *)(obj))
115
116 typedef struct _GstSelectorPad GstSelectorPad;
117 typedef struct _GstSelectorPadClass GstSelectorPadClass;
118
119 struct _GstSelectorPad
120 {
121   GstPad parent;
122
123   gboolean active;              /* when buffer have passed the pad */
124   gboolean eos;                 /* when EOS has been received */
125   gboolean discont;             /* after switching we create a discont */
126   gboolean always_ok;
127   GstSegment segment;           /* the current segment on the pad */
128   GstTagList *tags;             /* last tags received on the pad */
129
130   gboolean segment_pending;
131 };
132
133 struct _GstSelectorPadClass
134 {
135   GstPadClass parent;
136 };
137
138 static void gst_selector_pad_class_init (GstSelectorPadClass * klass);
139 static void gst_selector_pad_init (GstSelectorPad * pad);
140 static void gst_selector_pad_finalize (GObject * object);
141 static void gst_selector_pad_get_property (GObject * object,
142     guint prop_id, GValue * value, GParamSpec * pspec);
143 static void gst_selector_pad_set_property (GObject * object,
144     guint prop_id, const GValue * value, GParamSpec * pspec);
145
146 static GstPadClass *selector_pad_parent_class = NULL;
147
148 static gint64 gst_selector_pad_get_running_time (GstSelectorPad * pad);
149 static void gst_selector_pad_reset (GstSelectorPad * pad);
150 static gboolean gst_selector_pad_event (GstPad * pad, GstEvent * event);
151 static GstCaps *gst_selector_pad_getcaps (GstPad * pad);
152 static GstIterator *gst_selector_pad_iterate_linked_pads (GstPad * pad);
153 static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf);
154 static GstFlowReturn gst_selector_pad_bufferalloc (GstPad * pad,
155     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
156
157 static GType
158 gst_selector_pad_get_type (void)
159 {
160   static GType selector_pad_type = 0;
161
162   if (!selector_pad_type) {
163     static const GTypeInfo selector_pad_info = {
164       sizeof (GstSelectorPadClass),
165       NULL,
166       NULL,
167       (GClassInitFunc) gst_selector_pad_class_init,
168       NULL,
169       NULL,
170       sizeof (GstSelectorPad),
171       0,
172       (GInstanceInitFunc) gst_selector_pad_init,
173     };
174
175     selector_pad_type =
176         g_type_register_static (GST_TYPE_PAD, "GstSelectorPad",
177         &selector_pad_info, 0);
178   }
179   return selector_pad_type;
180 }
181
182 static void
183 gst_selector_pad_class_init (GstSelectorPadClass * klass)
184 {
185   GObjectClass *gobject_class;
186
187   gobject_class = (GObjectClass *) klass;
188
189   selector_pad_parent_class = g_type_class_peek_parent (klass);
190
191   gobject_class->finalize = gst_selector_pad_finalize;
192
193   gobject_class->get_property =
194       GST_DEBUG_FUNCPTR (gst_selector_pad_get_property);
195   gobject_class->set_property =
196       GST_DEBUG_FUNCPTR (gst_selector_pad_set_property);
197
198   g_object_class_install_property (gobject_class, PROP_PAD_RUNNING_TIME,
199       g_param_spec_int64 ("running-time", "Running time",
200           "Running time of stream on pad", 0, G_MAXINT64, 0, G_PARAM_READABLE));
201   g_object_class_install_property (gobject_class, PROP_PAD_TAGS,
202       g_param_spec_boxed ("tags", "Tags",
203           "The currently active tags on the pad", GST_TYPE_TAG_LIST,
204           G_PARAM_READABLE));
205   g_object_class_install_property (gobject_class, PROP_PAD_ACTIVE,
206       g_param_spec_boolean ("active", "Active",
207           "If the pad is currently active", FALSE, G_PARAM_READABLE));
208   g_object_class_install_property (gobject_class, PROP_PAD_ALWAYS_OK,
209       g_param_spec_boolean ("always-ok", "Always OK",
210           "Make an inactive pad return OK instead of NOT_LINKED",
211           DEFAULT_PAD_ALWAYS_OK, G_PARAM_READWRITE));
212 }
213
214 static void
215 gst_selector_pad_init (GstSelectorPad * pad)
216 {
217   pad->always_ok = DEFAULT_PAD_ALWAYS_OK;
218   gst_selector_pad_reset (pad);
219 }
220
221 static void
222 gst_selector_pad_finalize (GObject * object)
223 {
224   GstSelectorPad *pad;
225
226   pad = GST_SELECTOR_PAD_CAST (object);
227
228   if (pad->tags)
229     gst_tag_list_free (pad->tags);
230
231   G_OBJECT_CLASS (selector_pad_parent_class)->finalize (object);
232 }
233
234 static void
235 gst_selector_pad_set_property (GObject * object, guint prop_id,
236     const GValue * value, GParamSpec * pspec)
237 {
238   GstSelectorPad *spad = GST_SELECTOR_PAD_CAST (object);
239
240   switch (prop_id) {
241     case PROP_PAD_ALWAYS_OK:
242       GST_OBJECT_LOCK (object);
243       spad->always_ok = g_value_get_boolean (value);
244       GST_OBJECT_UNLOCK (object);
245       break;
246     default:
247       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
248       break;
249   }
250 }
251
252 static void
253 gst_selector_pad_get_property (GObject * object, guint prop_id,
254     GValue * value, GParamSpec * pspec)
255 {
256   GstSelectorPad *spad = GST_SELECTOR_PAD_CAST (object);
257
258   switch (prop_id) {
259     case PROP_PAD_RUNNING_TIME:
260       g_value_set_int64 (value, gst_selector_pad_get_running_time (spad));
261       break;
262     case PROP_PAD_TAGS:
263       GST_OBJECT_LOCK (object);
264       g_value_set_boxed (value, spad->tags);
265       GST_OBJECT_UNLOCK (object);
266       break;
267     case PROP_PAD_ACTIVE:
268     {
269       GstInputSelector *sel;
270
271       sel = GST_INPUT_SELECTOR (gst_pad_get_parent (spad));
272       g_value_set_boolean (value, gst_input_selector_is_active_sinkpad (sel,
273               GST_PAD_CAST (spad)));
274       gst_object_unref (sel);
275       break;
276     }
277     case PROP_PAD_ALWAYS_OK:
278       GST_OBJECT_LOCK (object);
279       g_value_set_boolean (value, spad->always_ok);
280       GST_OBJECT_UNLOCK (object);
281       break;
282     default:
283       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
284       break;
285   }
286 }
287
288 static gint64
289 gst_selector_pad_get_running_time (GstSelectorPad * pad)
290 {
291   gint64 ret = 0;
292
293   GST_OBJECT_LOCK (pad);
294   if (pad->active) {
295     gint64 last_stop = pad->segment.last_stop;
296
297     if (last_stop >= 0)
298       ret = gst_segment_to_running_time (&pad->segment, GST_FORMAT_TIME,
299           last_stop);
300   }
301   GST_OBJECT_UNLOCK (pad);
302
303   GST_DEBUG_OBJECT (pad, "running time: %" GST_TIME_FORMAT,
304       GST_TIME_ARGS (ret));
305
306   return ret;
307 }
308
309 static void
310 gst_selector_pad_reset (GstSelectorPad * pad)
311 {
312   GST_OBJECT_LOCK (pad);
313   pad->active = FALSE;
314   pad->eos = FALSE;
315   pad->segment_pending = FALSE;
316   pad->discont = FALSE;
317   gst_segment_init (&pad->segment, GST_FORMAT_UNDEFINED);
318   GST_OBJECT_UNLOCK (pad);
319 }
320
321 /* strictly get the linked pad from the sinkpad. If the pad is active we return
322  * the srcpad else we return NULL */
323 typedef struct
324 {
325   GstIterator parent;
326
327   GstPad *pad;
328   gboolean start;
329 } GstSelectorIterator;
330
331 static void
332 _iterate_free (GstIterator * it)
333 {
334   GstSelectorIterator *sit = (GstSelectorIterator *) it;
335
336   gst_object_unref (sit->pad);
337   g_free (it);
338 }
339
340 static GstIteratorResult
341 _iterate_next (GstIterator * it, gpointer * result)
342 {
343   GstSelectorIterator *sit = (GstSelectorIterator *) it;
344
345   if (sit->start) {
346     GstPad *res = gst_input_selector_get_linked_pad (sit->pad, TRUE);
347
348     *result = res;
349     sit->start = FALSE;
350     return GST_ITERATOR_OK;
351   }
352
353   *result = NULL;
354   return GST_ITERATOR_DONE;
355 }
356
357 static GstIteratorItem
358 _iterate_item (GstIterator * it, gpointer item)
359 {
360   return GST_ITERATOR_ITEM_PASS;
361 }
362
363 static void
364 _iterate_resync (GstIterator * it)
365 {
366   GstSelectorIterator *sit = (GstSelectorIterator *) it;
367
368   sit->start = TRUE;
369 }
370
371 static GstIterator *
372 gst_selector_pad_iterate_linked_pads (GstPad * pad)
373 {
374   GstInputSelector *sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
375   GstSelectorIterator *it = (GstSelectorIterator *)
376       gst_iterator_new (sizeof (GstSelectorIterator),
377       GST_TYPE_PAD,
378       sel->lock,
379       &GST_ELEMENT_CAST (sel)->pads_cookie,
380       _iterate_next, _iterate_item, _iterate_resync, _iterate_free);
381
382   it->pad = gst_object_ref (pad);
383   it->start = TRUE;
384
385   gst_object_unref (sel);
386
387   return (GstIterator *) it;
388 }
389
390 static gboolean
391 gst_selector_pad_event (GstPad * pad, GstEvent * event)
392 {
393   gboolean res = TRUE;
394   gboolean forward = TRUE;
395   GstInputSelector *sel;
396   GstSelectorPad *selpad;
397   GstPad *prev_active_sinkpad;
398   GstPad *active_sinkpad;
399
400   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
401   selpad = GST_SELECTOR_PAD_CAST (pad);
402
403   GST_INPUT_SELECTOR_LOCK (sel);
404   prev_active_sinkpad = sel->active_sinkpad;
405   active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
406
407   /* only forward if we are dealing with the active sinkpad or if select_all
408    * is enabled */
409   if (pad != active_sinkpad && !sel->select_all)
410     forward = FALSE;
411   GST_INPUT_SELECTOR_UNLOCK (sel);
412
413   if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad)
414     g_object_notify (G_OBJECT (sel), "active-pad");
415
416   switch (GST_EVENT_TYPE (event)) {
417     case GST_EVENT_FLUSH_START:
418       /* FIXME, flush out the waiter */
419       break;
420     case GST_EVENT_FLUSH_STOP:
421       GST_INPUT_SELECTOR_LOCK (sel);
422       gst_selector_pad_reset (selpad);
423       sel->pending_close = FALSE;
424       GST_INPUT_SELECTOR_UNLOCK (sel);
425       break;
426     case GST_EVENT_NEWSEGMENT:
427     {
428       gboolean update;
429       GstFormat format;
430       gdouble rate, arate;
431       gint64 start, stop, time;
432
433       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
434           &start, &stop, &time);
435
436       GST_DEBUG_OBJECT (pad,
437           "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
438           "format %d, "
439           "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
440           G_GINT64_FORMAT, update, rate, arate, format, start, stop, time);
441
442       GST_INPUT_SELECTOR_LOCK (sel);
443       GST_OBJECT_LOCK (selpad);
444       gst_segment_set_newsegment_full (&selpad->segment, update,
445           rate, arate, format, start, stop, time);
446       GST_OBJECT_UNLOCK (selpad);
447
448       /* If we aren't forwarding the event (because the pad is not the
449        * active_sinkpad, and select_all is not set, then set the flag on the
450        * that says a segment needs sending if/when that pad is activated.
451        * For all other cases, we send the event immediately, which makes
452        * sparse streams and other segment updates work correctly downstream.
453        */
454       if (!forward)
455         selpad->segment_pending = TRUE;
456
457       GST_INPUT_SELECTOR_UNLOCK (sel);
458       break;
459     }
460     case GST_EVENT_TAG:
461     {
462       GstTagList *tags, *oldtags, *newtags;
463
464       gst_event_parse_tag (event, &tags);
465
466       GST_OBJECT_LOCK (selpad);
467       oldtags = selpad->tags;
468
469       newtags = gst_tag_list_merge (oldtags, tags, GST_TAG_MERGE_REPLACE);
470       selpad->tags = newtags;
471       if (oldtags)
472         gst_tag_list_free (oldtags);
473       GST_DEBUG_OBJECT (pad, "received tags %" GST_PTR_FORMAT, newtags);
474       GST_OBJECT_UNLOCK (selpad);
475
476       g_object_notify (G_OBJECT (selpad), "tags");
477       break;
478     }
479     case GST_EVENT_EOS:
480       selpad->eos = TRUE;
481       GST_DEBUG_OBJECT (pad, "received EOS");
482       /* don't forward eos in select_all mode until all sink pads have eos */
483       if (sel->select_all && !gst_input_selector_check_eos (GST_ELEMENT (sel))) {
484         forward = FALSE;
485       }
486       break;
487     default:
488       break;
489   }
490   if (forward) {
491     GST_DEBUG_OBJECT (pad, "forwarding event");
492     res = gst_pad_push_event (sel->srcpad, event);
493   } else
494     gst_event_unref (event);
495
496   gst_object_unref (sel);
497
498   return res;
499 }
500
501 static GstCaps *
502 gst_selector_pad_getcaps (GstPad * pad)
503 {
504   GstInputSelector *sel;
505   GstCaps *caps;
506
507   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
508
509   GST_DEBUG_OBJECT (sel, "Getting caps of srcpad peer");
510   caps = gst_pad_peer_get_caps (sel->srcpad);
511   if (caps == NULL)
512     caps = gst_caps_new_any ();
513
514   gst_object_unref (sel);
515
516   return caps;
517 }
518
519 static GstFlowReturn
520 gst_selector_pad_bufferalloc (GstPad * pad, guint64 offset,
521     guint size, GstCaps * caps, GstBuffer ** buf)
522 {
523   GstInputSelector *sel;
524   GstFlowReturn result;
525   GstPad *active_sinkpad;
526   GstPad *prev_active_sinkpad;
527   GstSelectorPad *selpad;
528
529   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
530   selpad = GST_SELECTOR_PAD_CAST (pad);
531
532   GST_DEBUG_OBJECT (pad, "received alloc");
533
534   GST_INPUT_SELECTOR_LOCK (sel);
535   prev_active_sinkpad = sel->active_sinkpad;
536   active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
537
538   if (pad != active_sinkpad)
539     goto not_active;
540
541   GST_INPUT_SELECTOR_UNLOCK (sel);
542
543   if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad)
544     g_object_notify (G_OBJECT (sel), "active-pad");
545
546   result = gst_pad_alloc_buffer (sel->srcpad, offset, size, caps, buf);
547
548 done:
549   gst_object_unref (sel);
550
551   return result;
552
553   /* ERRORS */
554 not_active:
555   {
556     GST_INPUT_SELECTOR_UNLOCK (sel);
557
558     /* unselected pad, perform fallback alloc or return unlinked when
559      * asked */
560     GST_OBJECT_LOCK (selpad);
561     if (selpad->always_ok) {
562       GST_DEBUG_OBJECT (pad, "Not selected, performing fallback allocation");
563       *buf = NULL;
564       result = GST_FLOW_OK;
565     } else {
566       GST_DEBUG_OBJECT (pad, "Not selected, return NOT_LINKED");
567       result = GST_FLOW_NOT_LINKED;
568     }
569     GST_OBJECT_UNLOCK (selpad);
570
571     goto done;
572   }
573 }
574
575 /* must be called with the SELECTOR_LOCK, will block while the pad is blocked 
576  * or return TRUE when flushing */
577 static gboolean
578 gst_input_selector_wait (GstInputSelector * self, GstPad * pad)
579 {
580   while (self->blocked && !self->flushing) {
581     /* we can be unlocked here when we are shutting down (flushing) or when we
582      * get unblocked */
583     GST_INPUT_SELECTOR_WAIT (self);
584   }
585   return self->flushing;
586 }
587
588 static GstFlowReturn
589 gst_selector_pad_chain (GstPad * pad, GstBuffer * buf)
590 {
591   GstInputSelector *sel;
592   GstFlowReturn res;
593   GstPad *active_sinkpad;
594   GstPad *prev_active_sinkpad;
595   GstSelectorPad *selpad;
596   GstClockTime end_time, duration;
597   GstSegment *seg;
598   GstEvent *close_event = NULL, *start_event = NULL;
599
600   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
601   selpad = GST_SELECTOR_PAD_CAST (pad);
602   seg = &selpad->segment;
603
604   GST_INPUT_SELECTOR_LOCK (sel);
605   /* wait or check for flushing */
606   if (gst_input_selector_wait (sel, pad))
607     goto flushing;
608
609   GST_DEBUG_OBJECT (pad, "getting active pad");
610
611   prev_active_sinkpad = sel->active_sinkpad;
612   active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
613
614   /* update the segment on the srcpad */
615   end_time = GST_BUFFER_TIMESTAMP (buf);
616   if (GST_CLOCK_TIME_IS_VALID (end_time)) {
617     duration = GST_BUFFER_DURATION (buf);
618     if (GST_CLOCK_TIME_IS_VALID (duration))
619       end_time += duration;
620     GST_DEBUG_OBJECT (pad, "received end time %" GST_TIME_FORMAT,
621         GST_TIME_ARGS (end_time));
622
623     GST_OBJECT_LOCK (pad);
624     gst_segment_set_last_stop (seg, seg->format, end_time);
625     GST_OBJECT_UNLOCK (pad);
626   }
627
628   /* Ignore buffers from pads except the selected one */
629   if (pad != active_sinkpad)
630     goto ignore;
631
632   if (G_UNLIKELY (sel->pending_close)) {
633     GstSegment *cseg = &sel->segment;
634
635     GST_DEBUG_OBJECT (sel,
636         "pushing NEWSEGMENT update %d, rate %lf, applied rate %lf, "
637         "format %d, "
638         "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
639         G_GINT64_FORMAT, TRUE, cseg->rate, cseg->applied_rate, cseg->format,
640         cseg->start, cseg->stop, cseg->time);
641
642     /* create update segment */
643     close_event = gst_event_new_new_segment_full (TRUE, cseg->rate,
644         cseg->applied_rate, cseg->format, cseg->start, cseg->stop, cseg->time);
645
646     sel->pending_close = FALSE;
647   }
648   /* if we have a pending segment, push it out now */
649   if (G_UNLIKELY (selpad->segment_pending)) {
650     GST_DEBUG_OBJECT (pad,
651         "pushing NEWSEGMENT update %d, rate %lf, applied rate %lf, "
652         "format %d, "
653         "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
654         G_GINT64_FORMAT, FALSE, seg->rate, seg->applied_rate, seg->format,
655         seg->start, seg->stop, seg->time);
656
657     start_event = gst_event_new_new_segment_full (FALSE, seg->rate,
658         seg->applied_rate, seg->format, seg->start, seg->stop, seg->time);
659
660     selpad->segment_pending = FALSE;
661   }
662   GST_INPUT_SELECTOR_UNLOCK (sel);
663
664   if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad)
665     g_object_notify (G_OBJECT (sel), "active-pad");
666
667   if (close_event)
668     gst_pad_push_event (sel->srcpad, close_event);
669
670   if (start_event)
671     gst_pad_push_event (sel->srcpad, start_event);
672
673   if (selpad->discont) {
674     buf = gst_buffer_make_metadata_writable (buf);
675
676     GST_DEBUG_OBJECT (pad, "Marking discont buffer %p", buf);
677     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
678     selpad->discont = FALSE;
679   }
680
681   /* forward */
682   GST_DEBUG_OBJECT (pad, "Forwarding buffer %p from pad %s:%s", buf,
683       GST_DEBUG_PAD_NAME (pad));
684
685   res = gst_pad_push (sel->srcpad, buf);
686
687 done:
688   gst_object_unref (sel);
689   return res;
690
691   /* dropped buffers */
692 ignore:
693   {
694     GST_DEBUG_OBJECT (pad, "Pad not active, discard buffer %p", buf);
695     /* when we drop a buffer, we're creating a discont on this pad */
696     selpad->discont = TRUE;
697     GST_INPUT_SELECTOR_UNLOCK (sel);
698     gst_buffer_unref (buf);
699
700     /* figure out what to return upstream */
701     GST_OBJECT_LOCK (selpad);
702     if (selpad->always_ok)
703       res = GST_FLOW_OK;
704     else
705       res = GST_FLOW_NOT_LINKED;
706     GST_OBJECT_UNLOCK (selpad);
707
708     goto done;
709   }
710 flushing:
711   {
712     GST_DEBUG_OBJECT (pad, "We are flushing, discard buffer %p", buf);
713     GST_INPUT_SELECTOR_UNLOCK (sel);
714     gst_buffer_unref (buf);
715     res = GST_FLOW_WRONG_STATE;
716     goto done;
717   }
718 }
719
720 static void gst_input_selector_init (GstInputSelector * sel);
721 static void gst_input_selector_base_init (GstInputSelectorClass * klass);
722 static void gst_input_selector_class_init (GstInputSelectorClass * klass);
723
724 static void gst_input_selector_dispose (GObject * object);
725
726 static void gst_input_selector_set_property (GObject * object,
727     guint prop_id, const GValue * value, GParamSpec * pspec);
728 static void gst_input_selector_get_property (GObject * object,
729     guint prop_id, GValue * value, GParamSpec * pspec);
730
731 static GstPad *gst_input_selector_request_new_pad (GstElement * element,
732     GstPadTemplate * templ, const gchar * unused);
733 static void gst_input_selector_release_pad (GstElement * element, GstPad * pad);
734
735 static GstStateChangeReturn gst_input_selector_change_state (GstElement *
736     element, GstStateChange transition);
737
738 static GstCaps *gst_input_selector_getcaps (GstPad * pad);
739 static gboolean gst_input_selector_event (GstPad * pad, GstEvent * event);
740 static gboolean gst_input_selector_query (GstPad * pad, GstQuery * query);
741 static gint64 gst_input_selector_block (GstInputSelector * self);
742 static void gst_input_selector_switch (GstInputSelector * self,
743     GstPad * pad, gint64 stop_time, gint64 start_time);
744
745 static GstElementClass *parent_class = NULL;
746
747 GType
748 gst_input_selector_get_type (void)
749 {
750   static GType input_selector_type = 0;
751
752   if (!input_selector_type) {
753     static const GTypeInfo input_selector_info = {
754       sizeof (GstInputSelectorClass),
755       (GBaseInitFunc) gst_input_selector_base_init,
756       NULL,
757       (GClassInitFunc) gst_input_selector_class_init,
758       NULL,
759       NULL,
760       sizeof (GstInputSelector),
761       0,
762       (GInstanceInitFunc) gst_input_selector_init,
763     };
764     input_selector_type =
765         g_type_register_static (GST_TYPE_ELEMENT,
766         "GstInputSelector", &input_selector_info, 0);
767     GST_DEBUG_CATEGORY_INIT (input_selector_debug,
768         "input-selector", 0, "An input stream selector element");
769   }
770
771   return input_selector_type;
772 }
773
774 static void
775 gst_input_selector_base_init (GstInputSelectorClass * klass)
776 {
777   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
778
779   gst_element_class_set_details (element_class, &gst_input_selector_details);
780   gst_element_class_add_pad_template (element_class,
781       gst_static_pad_template_get (&gst_input_selector_sink_factory));
782   gst_element_class_add_pad_template (element_class,
783       gst_static_pad_template_get (&gst_input_selector_src_factory));
784 }
785
786 static void
787 gst_input_selector_class_init (GstInputSelectorClass * klass)
788 {
789   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
790   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
791
792   parent_class = g_type_class_peek_parent (klass);
793
794   gobject_class->dispose = gst_input_selector_dispose;
795
796   gobject_class->set_property =
797       GST_DEBUG_FUNCPTR (gst_input_selector_set_property);
798   gobject_class->get_property =
799       GST_DEBUG_FUNCPTR (gst_input_selector_get_property);
800
801   g_object_class_install_property (gobject_class, PROP_N_PADS,
802       g_param_spec_uint ("n-pads", "Number of Pads",
803           "The number of sink pads", 0, G_MAXUINT, 0, G_PARAM_READABLE));
804
805   g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
806       g_param_spec_object ("active-pad", "Active pad",
807           "The currently active sink pad", GST_TYPE_PAD, G_PARAM_READWRITE));
808
809   g_object_class_install_property (gobject_class, PROP_SELECT_ALL,
810       g_param_spec_boolean ("select-all", "Select all mode",
811           "Forwards data from all input pads", FALSE, G_PARAM_READWRITE));
812
813   /**
814    * GstInputSelector::block:
815    * @inputselector: the #GstInputSelector
816    *
817    * Block all sink pads in preparation for a switch. Returns the stop time of
818    * the current switch segment, as a running time, or 0 if there is no current
819    * active pad or the current active pad never received data.
820    */
821   gst_input_selector_signals[SIGNAL_BLOCK] =
822       g_signal_new ("block", G_TYPE_FROM_CLASS (klass),
823       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
824       G_STRUCT_OFFSET (GstInputSelectorClass, block), NULL, NULL,
825       gst_selector_marshal_INT64__VOID, G_TYPE_INT64, 0);
826   /**
827    * GstInputSelector::switch:
828    * @inputselector: the #GstInputSelector
829    * @pad:            the pad to switch to
830    * @stop_time:      running time at which to close the previous segment, or -1
831    *                  to use the running time of the previously active sink pad
832    * @start_time:     running time at which to start the new segment, or -1 to
833    *                  use the running time of the newly active sink pad
834    *
835    * Switch to a new feed. The segment opened by the previously active pad, if
836    * any, will be closed, and a new segment opened before data flows again.
837    *
838    * This signal must be emitted when the element has been blocked via the <link
839    * linkend="GstInputSelector-block">block</link> signal.
840    *
841    * If you have a stream with only one switch element, such as an audio-only
842    * stream, a stream switch should be performed by first emitting the block
843    * signal, and then emitting the switch signal with -1 for the stop and start
844    * time values.
845    *
846    * The intention of the @stop_time and @start_time arguments is to allow
847    * multiple switch elements to switch and maintain stream synchronization.
848    * When switching a stream with multiple feeds, you will need as many switch
849    * elements as you have feeds. For example, a feed with audio and video will
850    * have one switch element between the audio feeds and one for video.
851    *
852    * A switch over multiple switch elements should be performed as follows:
853    * First, emit the <link linkend="GstInputSelector-block">block</link>
854    * signal, collecting the returned values. The maximum running time returned
855    * by block should then be used as the time at which to close the previous
856    * segment.
857    *
858    * Then, query the running times of the new audio and video pads that you will
859    * switch to. Naturally, these pads are on separate switch elements. Take the
860    * minimum running time for those streams and use it for the time at which to
861    * open the new segment.
862    *
863    * If @pad is the same as the current active pad, the element will cancel any
864    * previous block without adjusting segments.
865    *
866    * <note><simpara>
867    * the signal changed from accepting the pad name to the pad object.
868    * </simpara></note>
869    *
870    * Since: 0.10.7
871    */
872   gst_input_selector_signals[SIGNAL_SWITCH] =
873       g_signal_new ("switch", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
874       G_STRUCT_OFFSET (GstInputSelectorClass, switch_),
875       NULL, NULL, gst_selector_marshal_VOID__OBJECT_INT64_INT64,
876       G_TYPE_NONE, 3, GST_TYPE_PAD, G_TYPE_INT64, G_TYPE_INT64);
877
878   gstelement_class->request_new_pad = gst_input_selector_request_new_pad;
879   gstelement_class->release_pad = gst_input_selector_release_pad;
880   gstelement_class->change_state = gst_input_selector_change_state;
881
882   klass->block = GST_DEBUG_FUNCPTR (gst_input_selector_block);
883   /* note the underscore because switch is a keyword otherwise */
884   klass->switch_ = GST_DEBUG_FUNCPTR (gst_input_selector_switch);
885 }
886
887 static void
888 gst_input_selector_init (GstInputSelector * sel)
889 {
890   sel->srcpad = gst_pad_new ("src", GST_PAD_SRC);
891   gst_pad_set_iterate_internal_links_function (sel->srcpad,
892       GST_DEBUG_FUNCPTR (gst_selector_pad_iterate_linked_pads));
893   gst_pad_set_getcaps_function (sel->srcpad,
894       GST_DEBUG_FUNCPTR (gst_input_selector_getcaps));
895   gst_pad_set_query_function (sel->srcpad,
896       GST_DEBUG_FUNCPTR (gst_input_selector_query));
897   gst_pad_set_event_function (sel->srcpad,
898       GST_DEBUG_FUNCPTR (gst_input_selector_event));
899   gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
900   /* sinkpad management */
901   sel->active_sinkpad = NULL;
902   sel->padcount = 0;
903   gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED);
904
905   sel->lock = g_mutex_new ();
906   sel->cond = g_cond_new ();
907   sel->blocked = FALSE;
908
909   sel->select_all = FALSE;
910 }
911
912 static void
913 gst_input_selector_dispose (GObject * object)
914 {
915   GstInputSelector *sel = GST_INPUT_SELECTOR (object);
916
917   if (sel->active_sinkpad) {
918     gst_object_unref (sel->active_sinkpad);
919     sel->active_sinkpad = NULL;
920   }
921   if (sel->lock) {
922     g_mutex_free (sel->lock);
923     sel->lock = NULL;
924   }
925   if (sel->cond) {
926     g_cond_free (sel->cond);
927     sel->cond = NULL;
928   }
929
930   G_OBJECT_CLASS (parent_class)->dispose (object);
931 }
932
933 /* Solve the following equation for B.timestamp, and set that as the segment
934  * stop:
935  * B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
936  */
937 static gint64
938 gst_segment_get_timestamp (GstSegment * segment, gint64 running_time)
939 {
940   return (running_time - segment->accum) * segment->abs_rate + segment->start;
941 }
942
943 static void
944 gst_segment_set_stop (GstSegment * segment, gint64 running_time)
945 {
946   segment->stop = gst_segment_get_timestamp (segment, running_time);
947   segment->last_stop = -1;
948 }
949
950 static void
951 gst_segment_set_start (GstSegment * segment, gint64 running_time)
952 {
953   gint64 new_start, duration;
954
955   new_start = gst_segment_get_timestamp (segment, running_time);
956
957   /* this is the duration we skipped */
958   duration = new_start - segment->start;
959   /* add the duration to the accumulated segment time */
960   segment->accum += duration;
961   /* move position in the segment */
962   segment->time += duration;
963   segment->start += duration;
964 }
965
966 /* this function must be called with the SELECTOR_LOCK. It returns TRUE when the
967  * active pad changed. */
968 static gboolean
969 gst_input_selector_set_active_pad (GstInputSelector * self,
970     GstPad * pad, gint64 stop_time, gint64 start_time)
971 {
972   GstSelectorPad *old, *new;
973   GstPad **active_pad_p;
974
975   if (pad == self->active_sinkpad)
976     return FALSE;
977
978   old = GST_SELECTOR_PAD_CAST (self->active_sinkpad);
979   new = GST_SELECTOR_PAD_CAST (pad);
980
981   GST_DEBUG_OBJECT (self, "setting active pad to %s:%s",
982       GST_DEBUG_PAD_NAME (new));
983
984   if (stop_time == -1 && old) {
985     /* no stop time given, get the latest running_time on the active pad to 
986      * close and open the new segment */
987     stop_time = start_time = gst_selector_pad_get_running_time (old);
988     GST_DEBUG_OBJECT (self, "using start/stop of %" G_GINT64_FORMAT,
989         start_time);
990   }
991
992   if (old && old->active && !self->pending_close && stop_time >= 0) {
993     /* schedule a last_stop update if one isn't already scheduled, and a
994        segment has been pushed before. */
995     memcpy (&self->segment, &old->segment, sizeof (self->segment));
996
997     GST_DEBUG_OBJECT (self, "setting stop_time to %" G_GINT64_FORMAT,
998         stop_time);
999     gst_segment_set_stop (&self->segment, stop_time);
1000     self->pending_close = TRUE;
1001   }
1002
1003   if (new && new->active && start_time >= 0) {
1004     GST_DEBUG_OBJECT (self, "setting start_time to %" G_GINT64_FORMAT,
1005         start_time);
1006     /* schedule a new segment push */
1007     gst_segment_set_start (&new->segment, start_time);
1008     new->segment_pending = TRUE;
1009   }
1010
1011   active_pad_p = &self->active_sinkpad;
1012   gst_object_replace ((GstObject **) active_pad_p, GST_OBJECT_CAST (pad));
1013   GST_DEBUG_OBJECT (self, "New active pad is %" GST_PTR_FORMAT,
1014       self->active_sinkpad);
1015
1016   return TRUE;
1017 }
1018
1019 static void
1020 gst_input_selector_set_property (GObject * object, guint prop_id,
1021     const GValue * value, GParamSpec * pspec)
1022 {
1023   GstInputSelector *sel = GST_INPUT_SELECTOR (object);
1024
1025   switch (prop_id) {
1026     case PROP_ACTIVE_PAD:
1027     {
1028       GstPad *pad;
1029
1030       pad = g_value_get_object (value);
1031
1032       GST_INPUT_SELECTOR_LOCK (sel);
1033       gst_input_selector_set_active_pad (sel, pad,
1034           GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE);
1035       GST_INPUT_SELECTOR_UNLOCK (sel);
1036       break;
1037     }
1038     case PROP_SELECT_ALL:
1039       GST_INPUT_SELECTOR_LOCK (object);
1040       sel->select_all = g_value_get_boolean (value);
1041       GST_INPUT_SELECTOR_UNLOCK (object);
1042       break;
1043     default:
1044       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1045       break;
1046   }
1047 }
1048
1049 static void
1050 gst_input_selector_get_property (GObject * object, guint prop_id,
1051     GValue * value, GParamSpec * pspec)
1052 {
1053   GstInputSelector *sel = GST_INPUT_SELECTOR (object);
1054
1055   switch (prop_id) {
1056     case PROP_N_PADS:
1057       GST_INPUT_SELECTOR_LOCK (object);
1058       g_value_set_uint (value, sel->n_pads);
1059       GST_INPUT_SELECTOR_UNLOCK (object);
1060       break;
1061     case PROP_ACTIVE_PAD:
1062       GST_INPUT_SELECTOR_LOCK (object);
1063       g_value_set_object (value, sel->active_sinkpad);
1064       GST_INPUT_SELECTOR_UNLOCK (object);
1065       break;
1066     case PROP_SELECT_ALL:
1067       GST_INPUT_SELECTOR_LOCK (object);
1068       g_value_set_boolean (value, sel->select_all);
1069       GST_INPUT_SELECTOR_UNLOCK (object);
1070       break;
1071     default:
1072       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1073       break;
1074   }
1075 }
1076
1077 static GstPad *
1078 gst_input_selector_get_linked_pad (GstPad * pad, gboolean strict)
1079 {
1080   GstInputSelector *sel;
1081   GstPad *otherpad = NULL;
1082
1083   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
1084
1085   GST_INPUT_SELECTOR_LOCK (sel);
1086   if (pad == sel->srcpad)
1087     otherpad = sel->active_sinkpad;
1088   else if (pad == sel->active_sinkpad || !strict)
1089     otherpad = sel->srcpad;
1090   if (otherpad)
1091     gst_object_ref (otherpad);
1092   GST_INPUT_SELECTOR_UNLOCK (sel);
1093
1094   gst_object_unref (sel);
1095
1096   return otherpad;
1097 }
1098
1099 static gboolean
1100 gst_input_selector_event (GstPad * pad, GstEvent * event)
1101 {
1102   gboolean res = FALSE;
1103   GstPad *otherpad;
1104
1105   otherpad = gst_input_selector_get_linked_pad (pad, TRUE);
1106
1107   if (otherpad) {
1108     res = gst_pad_push_event (otherpad, event);
1109
1110     gst_object_unref (otherpad);
1111   } else
1112     gst_event_unref (event);
1113   return res;
1114 }
1115
1116 /* query on the srcpad. We override this function because by default it will
1117  * only forward the query to one random sinkpad */
1118 static gboolean
1119 gst_input_selector_query (GstPad * pad, GstQuery * query)
1120 {
1121   gboolean res = TRUE;
1122   GstInputSelector *sel;
1123   GstPad *otherpad;
1124
1125   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
1126
1127   otherpad = gst_input_selector_get_linked_pad (pad, TRUE);
1128
1129   switch (GST_QUERY_TYPE (query)) {
1130     case GST_QUERY_LATENCY:
1131     {
1132       GList *walk;
1133       GstClockTime resmin, resmax;
1134       gboolean reslive;
1135
1136       resmin = 0;
1137       resmax = -1;
1138       reslive = FALSE;
1139
1140       /* assume FALSE, we become TRUE if one query succeeds */
1141       res = FALSE;
1142
1143       /* perform the query on all sinkpads and combine the results. We take the
1144        * max of min and the min of max for the result latency. */
1145       GST_INPUT_SELECTOR_LOCK (sel);
1146       for (walk = GST_ELEMENT_CAST (sel)->sinkpads; walk;
1147           walk = g_list_next (walk)) {
1148         GstPad *sinkpad = GST_PAD_CAST (walk->data);
1149
1150         if (gst_pad_peer_query (sinkpad, query)) {
1151           GstClockTime min, max;
1152           gboolean live;
1153
1154           /* one query succeeded, we succeed too */
1155           res = TRUE;
1156
1157           gst_query_parse_latency (query, &live, &min, &max);
1158
1159           GST_DEBUG_OBJECT (sinkpad,
1160               "peer latency min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT
1161               ", live %d", GST_TIME_ARGS (min), GST_TIME_ARGS (max), live);
1162
1163           if (live) {
1164             if (min > resmin)
1165               resmin = min;
1166             if (resmax == -1)
1167               resmax = max;
1168             else if (max < resmax)
1169               resmax = max;
1170             if (reslive == FALSE)
1171               reslive = live;
1172           }
1173         }
1174       }
1175       GST_INPUT_SELECTOR_UNLOCK (sel);
1176       if (res) {
1177         gst_query_set_latency (query, reslive, resmin, resmax);
1178
1179         GST_DEBUG_OBJECT (sel,
1180             "total latency min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT
1181             ", live %d", GST_TIME_ARGS (resmin), GST_TIME_ARGS (resmax),
1182             reslive);
1183       }
1184
1185       break;
1186     }
1187     default:
1188       if (otherpad)
1189         res = gst_pad_peer_query (otherpad, query);
1190       break;
1191   }
1192   if (otherpad)
1193     gst_object_unref (otherpad);
1194   gst_object_unref (sel);
1195
1196   return res;
1197 }
1198
1199 static GstCaps *
1200 gst_input_selector_getcaps (GstPad * pad)
1201 {
1202   GstPad *otherpad;
1203   GstObject *parent;
1204   GstCaps *caps;
1205
1206   parent = gst_object_get_parent (GST_OBJECT (pad));
1207
1208   otherpad = gst_input_selector_get_linked_pad (pad, FALSE);
1209
1210   if (!otherpad) {
1211     if (GST_INPUT_SELECTOR (parent)->select_all) {
1212       GST_DEBUG_OBJECT (parent,
1213           "Pad %s:%s not linked, returning merge of caps",
1214           GST_DEBUG_PAD_NAME (pad));
1215       caps = gst_pad_proxy_getcaps (pad);
1216     } else {
1217       GST_DEBUG_OBJECT (parent,
1218           "Pad %s:%s not linked, returning ANY", GST_DEBUG_PAD_NAME (pad));
1219       caps = gst_caps_new_any ();
1220     }
1221   } else {
1222     GST_DEBUG_OBJECT (parent,
1223         "Pad %s:%s is linked (to %s:%s), returning peer caps",
1224         GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (otherpad));
1225     /* if the peer has caps, use those. If the pad is not linked, this function
1226      * returns NULL and we return ANY */
1227     if (!(caps = gst_pad_peer_get_caps (otherpad)))
1228       caps = gst_caps_new_any ();
1229     gst_object_unref (otherpad);
1230   }
1231
1232   gst_object_unref (parent);
1233   return caps;
1234 }
1235
1236 /* check if the pad is the active sinkpad */
1237 static gboolean
1238 gst_input_selector_is_active_sinkpad (GstInputSelector * sel, GstPad * pad)
1239 {
1240   GstSelectorPad *selpad;
1241   gboolean res;
1242
1243   selpad = GST_SELECTOR_PAD_CAST (pad);
1244
1245   GST_INPUT_SELECTOR_LOCK (sel);
1246   res = (pad == sel->active_sinkpad);
1247   GST_INPUT_SELECTOR_UNLOCK (sel);
1248
1249   return res;
1250 }
1251
1252 /* Get or create the active sinkpad, must be called with SELECTOR_LOCK */
1253 static GstPad *
1254 gst_input_selector_activate_sinkpad (GstInputSelector * sel, GstPad * pad)
1255 {
1256   GstPad *active_sinkpad;
1257   GstSelectorPad *selpad;
1258
1259   selpad = GST_SELECTOR_PAD_CAST (pad);
1260
1261   selpad->active = TRUE;
1262   active_sinkpad = sel->active_sinkpad;
1263   if (active_sinkpad == NULL || sel->select_all) {
1264     /* first pad we get activity on becomes the activated pad by default, if we
1265      * select all, we also remember the last used pad. */
1266     if (sel->active_sinkpad)
1267       gst_object_unref (sel->active_sinkpad);
1268     active_sinkpad = sel->active_sinkpad = gst_object_ref (pad);
1269     GST_DEBUG_OBJECT (sel, "Activating pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1270   }
1271
1272   return active_sinkpad;
1273 }
1274
1275 static GstPad *
1276 gst_input_selector_request_new_pad (GstElement * element,
1277     GstPadTemplate * templ, const gchar * unused)
1278 {
1279   GstInputSelector *sel;
1280   gchar *name = NULL;
1281   GstPad *sinkpad = NULL;
1282
1283   g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
1284
1285   sel = GST_INPUT_SELECTOR (element);
1286
1287   GST_INPUT_SELECTOR_LOCK (sel);
1288
1289   GST_LOG_OBJECT (sel, "Creating new pad %d", sel->padcount);
1290   name = g_strdup_printf ("sink%d", sel->padcount++);
1291   sinkpad = g_object_new (GST_TYPE_SELECTOR_PAD,
1292       "name", name, "direction", templ->direction, "template", templ, NULL);
1293   g_free (name);
1294
1295   sel->n_pads++;
1296
1297   gst_pad_set_event_function (sinkpad,
1298       GST_DEBUG_FUNCPTR (gst_selector_pad_event));
1299   gst_pad_set_getcaps_function (sinkpad,
1300       GST_DEBUG_FUNCPTR (gst_selector_pad_getcaps));
1301   gst_pad_set_chain_function (sinkpad,
1302       GST_DEBUG_FUNCPTR (gst_selector_pad_chain));
1303   gst_pad_set_iterate_internal_links_function (sinkpad,
1304       GST_DEBUG_FUNCPTR (gst_selector_pad_iterate_linked_pads));
1305   gst_pad_set_bufferalloc_function (sinkpad,
1306       GST_DEBUG_FUNCPTR (gst_selector_pad_bufferalloc));
1307
1308   gst_pad_set_active (sinkpad, TRUE);
1309   gst_element_add_pad (GST_ELEMENT (sel), sinkpad);
1310   GST_INPUT_SELECTOR_UNLOCK (sel);
1311
1312   return sinkpad;
1313 }
1314
1315 static void
1316 gst_input_selector_release_pad (GstElement * element, GstPad * pad)
1317 {
1318   GstInputSelector *sel;
1319
1320   sel = GST_INPUT_SELECTOR (element);
1321   GST_LOG_OBJECT (sel, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1322
1323   GST_INPUT_SELECTOR_LOCK (sel);
1324   /* if the pad was the active pad, makes us select a new one */
1325   if (sel->active_sinkpad == pad) {
1326     GST_DEBUG_OBJECT (sel, "Deactivating pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1327     gst_object_unref (sel->active_sinkpad);
1328     sel->active_sinkpad = NULL;
1329   }
1330   sel->n_pads--;
1331
1332   gst_pad_set_active (pad, FALSE);
1333   gst_element_remove_pad (GST_ELEMENT (sel), pad);
1334   GST_INPUT_SELECTOR_UNLOCK (sel);
1335 }
1336
1337 static void
1338 gst_input_selector_reset (GstInputSelector * sel)
1339 {
1340   GList *walk;
1341
1342   GST_INPUT_SELECTOR_LOCK (sel);
1343   /* clear active pad */
1344   if (sel->active_sinkpad) {
1345     gst_object_unref (sel->active_sinkpad);
1346     sel->active_sinkpad = NULL;
1347   }
1348   /* reset segment */
1349   gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED);
1350   sel->pending_close = FALSE;
1351   /* reset each of our sinkpads state */
1352   for (walk = GST_ELEMENT_CAST (sel)->sinkpads; walk; walk = g_list_next (walk)) {
1353     GstSelectorPad *selpad = GST_SELECTOR_PAD_CAST (walk->data);
1354
1355     gst_selector_pad_reset (selpad);
1356
1357     if (selpad->tags) {
1358       gst_tag_list_free (selpad->tags);
1359       selpad->tags = NULL;
1360     }
1361   }
1362   GST_INPUT_SELECTOR_UNLOCK (sel);
1363 }
1364
1365 static GstStateChangeReturn
1366 gst_input_selector_change_state (GstElement * element,
1367     GstStateChange transition)
1368 {
1369   GstInputSelector *self = GST_INPUT_SELECTOR (element);
1370   GstStateChangeReturn result;
1371
1372   switch (transition) {
1373     case GST_STATE_CHANGE_READY_TO_PAUSED:
1374       GST_INPUT_SELECTOR_LOCK (self);
1375       self->blocked = FALSE;
1376       self->flushing = FALSE;
1377       GST_INPUT_SELECTOR_UNLOCK (self);
1378       break;
1379     case GST_STATE_CHANGE_PAUSED_TO_READY:
1380       /* first unlock before we call the parent state change function, which
1381        * tries to acquire the stream lock when going to ready. */
1382       GST_INPUT_SELECTOR_LOCK (self);
1383       self->blocked = FALSE;
1384       self->flushing = TRUE;
1385       GST_INPUT_SELECTOR_BROADCAST (self);
1386       GST_INPUT_SELECTOR_UNLOCK (self);
1387       break;
1388     default:
1389       break;
1390   }
1391
1392   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1393
1394   switch (transition) {
1395     case GST_STATE_CHANGE_PAUSED_TO_READY:
1396       gst_input_selector_reset (self);
1397       break;
1398     default:
1399       break;
1400   }
1401
1402   return result;
1403 }
1404
1405 static gint64
1406 gst_input_selector_block (GstInputSelector * self)
1407 {
1408   gint64 ret = 0;
1409   GstSelectorPad *spad;
1410
1411   GST_INPUT_SELECTOR_LOCK (self);
1412
1413   if (self->blocked)
1414     GST_WARNING_OBJECT (self, "switch already blocked");
1415
1416   self->blocked = TRUE;
1417   spad = GST_SELECTOR_PAD_CAST (self->active_sinkpad);
1418
1419   if (spad)
1420     ret = gst_selector_pad_get_running_time (spad);
1421   else
1422     GST_DEBUG_OBJECT (self, "no active pad while blocking");
1423
1424   GST_INPUT_SELECTOR_UNLOCK (self);
1425
1426   return ret;
1427 }
1428
1429 /* stop_time and start_time are running times */
1430 static void
1431 gst_input_selector_switch (GstInputSelector * self, GstPad * pad,
1432     gint64 stop_time, gint64 start_time)
1433 {
1434   gboolean changed;
1435
1436   g_return_if_fail (self->blocked == TRUE);
1437
1438   GST_INPUT_SELECTOR_LOCK (self);
1439   changed =
1440       gst_input_selector_set_active_pad (self, pad, stop_time, start_time);
1441
1442   self->blocked = FALSE;
1443   GST_INPUT_SELECTOR_BROADCAST (self);
1444   GST_INPUT_SELECTOR_UNLOCK (self);
1445
1446   if (changed)
1447     g_object_notify (G_OBJECT (self), "active-pad");
1448 }
1449
1450 static gboolean
1451 gst_input_selector_check_eos (GstElement * selector)
1452 {
1453   GstIterator *it = gst_element_iterate_sink_pads (selector);
1454   GstIteratorResult ires;
1455   gpointer item;
1456   gboolean done = FALSE, is_eos = FALSE;
1457   GstSelectorPad *pad;
1458
1459   while (!done) {
1460     ires = gst_iterator_next (it, &item);
1461     switch (ires) {
1462       case GST_ITERATOR_DONE:
1463         GST_INFO_OBJECT (selector, "all sink pads have eos");
1464         done = TRUE;
1465         is_eos = TRUE;
1466         break;
1467       case GST_ITERATOR_OK:
1468         pad = GST_SELECTOR_PAD_CAST (item);
1469         if (!pad->eos) {
1470           done = TRUE;
1471         }
1472         gst_object_unref (pad);
1473         break;
1474       case GST_ITERATOR_RESYNC:
1475         gst_iterator_resync (it);
1476         break;
1477       default:
1478         done = TRUE;
1479         break;
1480     }
1481   }
1482   gst_iterator_free (it);
1483
1484   return is_eos;
1485 }