librewolf: update to 134.0-1
[oi-userland.git] / components / multimedia / gst-plugins-good / patches / 02-selector.patch
blob130e103e9b3ce6b8f01fd7ad3b398732c7ae54a1
1 --- /dev/null 2008-12-16 15:34:15.000000000 +0800
2 +++ gst-plugins-good-0.10.21/gst/selector/Makefile.am 2008-12-16 15:09:01.090359516 +0800
3 @@ -0,0 +1,24 @@
4 +glib_gen_prefix = gst_selector
5 +glib_gen_basename = gstselector
7 +include $(top_srcdir)/common/gst-glib-gen.mak
9 +built_sources = gstselector-marshal.c
10 +built_headers = gstselector-marshal.h
12 +BUILT_SOURCES = $(built_sources) $(built_headers)
14 +CLEANFILES = $(BUILT_SOURCES)
16 +EXTRA_DIST = gstselector-marshal.list
18 +plugin_LTLIBRARIES = libgstselector.la
20 +libgstselector_la_SOURCES = gstselector.c gstinputselector.c gstoutputselector.c
21 +nodist_libgstselector_la_SOURCES = $(built_sources)
22 +libgstselector_la_CFLAGS = $(GST_CFLAGS)
23 +libgstselector_la_LIBADD =
24 +libgstselector_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS)
25 +libgstselector_la_LIBTOOLFLAGS = --tag=disable-static
27 +noinst_HEADERS = gstinputselector.h gstoutputselector.h
28 --- /dev/null 2008-12-16 15:34:15.000000000 +0800
29 +++ gst-plugins-good-0.10.21/gst/selector/gstinputselector.c 2008-12-16 15:09:01.091207753 +0800
30 @@ -0,0 +1,1455 @@
31 +/* GStreamer
32 + * Copyright (C) 2003 Julien Moutte <julien@moutte.net>
33 + * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
34 + * Copyright (C) 2005 Jan Schmidt <thaytan@mad.scientist.com>
35 + * Copyright (C) 2007 Wim Taymans <wim.taymans@gmail.com>
36 + * Copyright (C) 2007 Andy Wingo <wingo@pobox.com>
37 + * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
38 + *
39 + * This library is free software; you can redistribute it and/or
40 + * modify it under the terms of the GNU Library General Public
41 + * License as published by the Free Software Foundation; either
42 + * version 2 of the License, or (at your option) any later version.
43 + *
44 + * This library is distributed in the hope that it will be useful,
45 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
46 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
47 + * Library General Public License for more details.
48 + *
49 + * You should have received a copy of the GNU Library General Public
50 + * License along with this library; if not, write to the
51 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
52 + * Boston, MA 02111-1307, USA.
53 + */
55 +/**
56 + * SECTION:element-input-selector
57 + * @see_also: #GstOutputSelector
58 + *
59 + * Direct one out of N input streams to the output pad.
60 + */
62 +#ifdef HAVE_CONFIG_H
63 +#include "config.h"
64 +#endif
66 +#include <string.h>
68 +#include "gstinputselector.h"
69 +#include "gstselector-marshal.h"
71 +GST_DEBUG_CATEGORY_STATIC (input_selector_debug);
72 +#define GST_CAT_DEFAULT input_selector_debug
74 +static const GstElementDetails gst_input_selector_details =
75 +GST_ELEMENT_DETAILS ("Input selector",
76 + "Generic",
77 + "N-to-1 input stream selectoring",
78 + "Julien Moutte <julien@moutte.net>\n"
79 + "Jan Schmidt <thaytan@mad.scientist.com>\n"
80 + "Wim Taymans <wim.taymans@gmail.com>");
82 +static GstStaticPadTemplate gst_input_selector_sink_factory =
83 +GST_STATIC_PAD_TEMPLATE ("sink%d",
84 + GST_PAD_SINK,
85 + GST_PAD_REQUEST,
86 + GST_STATIC_CAPS_ANY);
88 +static GstStaticPadTemplate gst_input_selector_src_factory =
89 +GST_STATIC_PAD_TEMPLATE ("src",
90 + GST_PAD_SRC,
91 + GST_PAD_ALWAYS,
92 + GST_STATIC_CAPS_ANY);
94 +enum
96 + PROP_0,
97 + PROP_N_PADS,
98 + PROP_ACTIVE_PAD,
99 + PROP_SELECT_ALL,
100 + PROP_LAST
103 +#define DEFAULT_PAD_ALWAYS_OK TRUE
105 +enum
107 + PROP_PAD_0,
108 + PROP_PAD_RUNNING_TIME,
109 + PROP_PAD_TAGS,
110 + PROP_PAD_ACTIVE,
111 + PROP_PAD_ALWAYS_OK,
112 + PROP_PAD_LAST
115 +enum
117 + /* methods */
118 + SIGNAL_BLOCK,
119 + SIGNAL_SWITCH,
120 + LAST_SIGNAL
122 +static guint gst_input_selector_signals[LAST_SIGNAL] = { 0 };
124 +static inline gboolean gst_input_selector_is_active_sinkpad (GstInputSelector *
125 + sel, GstPad * pad);
126 +static GstPad *gst_input_selector_activate_sinkpad (GstInputSelector * sel,
127 + GstPad * pad);
128 +static GstPad *gst_input_selector_get_linked_pad (GstPad * pad,
129 + gboolean strict);
130 +static gboolean gst_input_selector_check_eos (GstElement * selector);
132 +#define GST_TYPE_SELECTOR_PAD \
133 + (gst_selector_pad_get_type())
134 +#define GST_SELECTOR_PAD(obj) \
135 + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SELECTOR_PAD, GstSelectorPad))
136 +#define GST_SELECTOR_PAD_CLASS(klass) \
137 + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SELECTOR_PAD, GstSelectorPadClass))
138 +#define GST_IS_SELECTOR_PAD(obj) \
139 + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SELECTOR_PAD))
140 +#define GST_IS_SELECTOR_PAD_CLASS(klass) \
141 + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SELECTOR_PAD))
142 +#define GST_SELECTOR_PAD_CAST(obj) \
143 + ((GstSelectorPad *)(obj))
145 +typedef struct _GstSelectorPad GstSelectorPad;
146 +typedef struct _GstSelectorPadClass GstSelectorPadClass;
148 +struct _GstSelectorPad
150 + GstPad parent;
152 + gboolean active; /* when buffer have passed the pad */
153 + gboolean eos; /* when EOS has been received */
154 + gboolean discont; /* after switching we create a discont */
155 + gboolean always_ok;
156 + GstSegment segment; /* the current segment on the pad */
157 + GstTagList *tags; /* last tags received on the pad */
159 + gboolean segment_pending;
162 +struct _GstSelectorPadClass
164 + GstPadClass parent;
167 +static void gst_selector_pad_class_init (GstSelectorPadClass * klass);
168 +static void gst_selector_pad_init (GstSelectorPad * pad);
169 +static void gst_selector_pad_finalize (GObject * object);
170 +static void gst_selector_pad_get_property (GObject * object,
171 + guint prop_id, GValue * value, GParamSpec * pspec);
172 +static void gst_selector_pad_set_property (GObject * object,
173 + guint prop_id, const GValue * value, GParamSpec * pspec);
175 +static GstPadClass *selector_pad_parent_class = NULL;
177 +static gint64 gst_selector_pad_get_running_time (GstSelectorPad * pad);
178 +static void gst_selector_pad_reset (GstSelectorPad * pad);
179 +static gboolean gst_selector_pad_event (GstPad * pad, GstEvent * event);
180 +static GstCaps *gst_selector_pad_getcaps (GstPad * pad);
181 +static gboolean gst_selector_pad_acceptcaps (GstPad * pad, GstCaps * caps);
182 +static GstIterator *gst_selector_pad_iterate_linked_pads (GstPad * pad);
183 +static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf);
184 +static GstFlowReturn gst_selector_pad_bufferalloc (GstPad * pad,
185 + guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
187 +static GType
188 +gst_selector_pad_get_type (void)
190 + static GType selector_pad_type = 0;
192 + if (!selector_pad_type) {
193 + static const GTypeInfo selector_pad_info = {
194 + sizeof (GstSelectorPadClass),
195 + NULL,
196 + NULL,
197 + (GClassInitFunc) gst_selector_pad_class_init,
198 + NULL,
199 + NULL,
200 + sizeof (GstSelectorPad),
201 + 0,
202 + (GInstanceInitFunc) gst_selector_pad_init,
203 + };
205 + selector_pad_type =
206 + g_type_register_static (GST_TYPE_PAD, "GstSelectorPad",
207 + &selector_pad_info, 0);
209 + return selector_pad_type;
212 +static void
213 +gst_selector_pad_class_init (GstSelectorPadClass * klass)
215 + GObjectClass *gobject_class;
217 + gobject_class = (GObjectClass *) klass;
219 + selector_pad_parent_class = g_type_class_peek_parent (klass);
221 + gobject_class->finalize = gst_selector_pad_finalize;
223 + gobject_class->get_property = gst_selector_pad_get_property;
224 + gobject_class->set_property = gst_selector_pad_set_property;
226 + g_object_class_install_property (gobject_class, PROP_PAD_RUNNING_TIME,
227 + g_param_spec_int64 ("running-time", "Running time",
228 + "Running time of stream on pad", 0, G_MAXINT64, 0, G_PARAM_READABLE));
229 + g_object_class_install_property (gobject_class, PROP_PAD_TAGS,
230 + g_param_spec_boxed ("tags", "Tags",
231 + "The currently active tags on the pad", GST_TYPE_TAG_LIST,
232 + G_PARAM_READABLE));
233 + g_object_class_install_property (gobject_class, PROP_PAD_ACTIVE,
234 + g_param_spec_boolean ("active", "Active",
235 + "If the pad is currently active", FALSE, G_PARAM_READABLE));
236 + g_object_class_install_property (gobject_class, PROP_PAD_ALWAYS_OK,
237 + g_param_spec_boolean ("always-ok", "Always OK",
238 + "Make an inactive pad return OK instead of NOT_LINKED",
239 + DEFAULT_PAD_ALWAYS_OK, G_PARAM_READWRITE));
242 +static void
243 +gst_selector_pad_init (GstSelectorPad * pad)
245 + pad->always_ok = DEFAULT_PAD_ALWAYS_OK;
246 + gst_selector_pad_reset (pad);
249 +static void
250 +gst_selector_pad_finalize (GObject * object)
252 + GstSelectorPad *pad;
254 + pad = GST_SELECTOR_PAD_CAST (object);
256 + if (pad->tags)
257 + gst_tag_list_free (pad->tags);
259 + G_OBJECT_CLASS (selector_pad_parent_class)->finalize (object);
262 +static void
263 +gst_selector_pad_set_property (GObject * object, guint prop_id,
264 + const GValue * value, GParamSpec * pspec)
266 + GstSelectorPad *spad = GST_SELECTOR_PAD_CAST (object);
268 + switch (prop_id) {
269 + case PROP_PAD_ALWAYS_OK:
270 + GST_OBJECT_LOCK (object);
271 + spad->always_ok = g_value_get_boolean (value);
272 + GST_OBJECT_UNLOCK (object);
273 + break;
274 + default:
275 + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
276 + break;
280 +static void
281 +gst_selector_pad_get_property (GObject * object, guint prop_id,
282 + GValue * value, GParamSpec * pspec)
284 + GstSelectorPad *spad = GST_SELECTOR_PAD_CAST (object);
286 + switch (prop_id) {
287 + case PROP_PAD_RUNNING_TIME:
288 + g_value_set_int64 (value, gst_selector_pad_get_running_time (spad));
289 + break;
290 + case PROP_PAD_TAGS:
291 + GST_OBJECT_LOCK (object);
292 + g_value_set_boxed (value, spad->tags);
293 + GST_OBJECT_UNLOCK (object);
294 + break;
295 + case PROP_PAD_ACTIVE:
297 + GstInputSelector *sel;
299 + sel = GST_INPUT_SELECTOR (gst_pad_get_parent (spad));
300 + g_value_set_boolean (value, gst_input_selector_is_active_sinkpad (sel,
301 + GST_PAD_CAST (spad)));
302 + gst_object_unref (sel);
303 + break;
305 + case PROP_PAD_ALWAYS_OK:
306 + GST_OBJECT_LOCK (object);
307 + g_value_set_boolean (value, spad->always_ok);
308 + GST_OBJECT_UNLOCK (object);
309 + break;
310 + default:
311 + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
312 + break;
316 +static gint64
317 +gst_selector_pad_get_running_time (GstSelectorPad * pad)
319 + gint64 ret = 0;
321 + GST_OBJECT_LOCK (pad);
322 + if (pad->active) {
323 + gint64 last_stop = pad->segment.last_stop;
325 + if (last_stop >= 0)
326 + ret = gst_segment_to_running_time (&pad->segment, GST_FORMAT_TIME,
327 + last_stop);
329 + GST_OBJECT_UNLOCK (pad);
331 + GST_DEBUG_OBJECT (pad, "running time: %" GST_TIME_FORMAT,
332 + GST_TIME_ARGS (ret));
334 + return ret;
337 +static void
338 +gst_selector_pad_reset (GstSelectorPad * pad)
340 + GST_OBJECT_LOCK (pad);
341 + pad->active = FALSE;
342 + pad->eos = FALSE;
343 + pad->segment_pending = FALSE;
344 + pad->discont = FALSE;
345 + gst_segment_init (&pad->segment, GST_FORMAT_UNDEFINED);
346 + GST_OBJECT_UNLOCK (pad);
349 +/* strictly get the linked pad from the sinkpad. If the pad is active we return
350 + * the srcpad else we return NULL */
351 +static GstIterator *
352 +gst_selector_pad_iterate_linked_pads (GstPad * pad)
354 + GstInputSelector *sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
355 + GstPad *otherpad;
356 + GstIterator *it;
358 + otherpad = gst_input_selector_get_linked_pad (pad, TRUE);
359 + it = gst_iterator_new_single (GST_TYPE_PAD, otherpad,
360 + (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref);
362 + if (otherpad)
363 + gst_object_unref (otherpad);
364 + gst_object_unref (sel);
366 + return it;
369 +static gboolean
370 +gst_selector_pad_event (GstPad * pad, GstEvent * event)
372 + gboolean res = TRUE;
373 + gboolean forward = TRUE;
374 + GstInputSelector *sel;
375 + GstSelectorPad *selpad;
376 + GstPad *prev_active_sinkpad;
377 + GstPad *active_sinkpad;
379 + sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
380 + selpad = GST_SELECTOR_PAD_CAST (pad);
382 + GST_INPUT_SELECTOR_LOCK (sel);
383 + prev_active_sinkpad = sel->active_sinkpad;
384 + active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
386 + /* only forward if we are dealing with the active sinkpad or if select_all
387 + * is enabled */
388 + if (pad != active_sinkpad && !sel->select_all)
389 + forward = FALSE;
390 + GST_INPUT_SELECTOR_UNLOCK (sel);
392 + if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad)
393 + g_object_notify (G_OBJECT (sel), "active-pad");
395 + switch (GST_EVENT_TYPE (event)) {
396 + case GST_EVENT_FLUSH_START:
397 + /* FIXME, flush out the waiter */
398 + break;
399 + case GST_EVENT_FLUSH_STOP:
400 + GST_INPUT_SELECTOR_LOCK (sel);
401 + gst_selector_pad_reset (selpad);
402 + sel->pending_close = FALSE;
403 + GST_INPUT_SELECTOR_UNLOCK (sel);
404 + break;
405 + case GST_EVENT_NEWSEGMENT:
407 + gboolean update;
408 + GstFormat format;
409 + gdouble rate, arate;
410 + gint64 start, stop, time;
412 + gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
413 + &start, &stop, &time);
415 + GST_DEBUG_OBJECT (pad,
416 + "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
417 + "format %d, "
418 + "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
419 + G_GINT64_FORMAT, update, rate, arate, format, start, stop, time);
421 + GST_INPUT_SELECTOR_LOCK (sel);
422 + GST_OBJECT_LOCK (selpad);
423 + gst_segment_set_newsegment_full (&selpad->segment, update,
424 + rate, arate, format, start, stop, time);
425 + GST_OBJECT_UNLOCK (selpad);
427 + /* If we aren't forwarding the event (because the pad is not the
428 + * active_sinkpad, and select_all is not set, then set the flag on the
429 + * that says a segment needs sending if/when that pad is activated.
430 + * For all other cases, we send the event immediately, which makes
431 + * sparse streams and other segment updates work correctly downstream.
432 + */
433 + if (!forward)
434 + selpad->segment_pending = TRUE;
436 + GST_INPUT_SELECTOR_UNLOCK (sel);
437 + break;
439 + case GST_EVENT_TAG:
441 + GstTagList *tags, *oldtags, *newtags;
443 + gst_event_parse_tag (event, &tags);
445 + GST_OBJECT_LOCK (selpad);
446 + oldtags = selpad->tags;
448 + newtags = gst_tag_list_merge (oldtags, tags, GST_TAG_MERGE_REPLACE);
449 + selpad->tags = newtags;
450 + if (oldtags)
451 + gst_tag_list_free (oldtags);
452 + GST_DEBUG_OBJECT (pad, "received tags %" GST_PTR_FORMAT, newtags);
453 + GST_OBJECT_UNLOCK (selpad);
455 + g_object_notify (G_OBJECT (selpad), "tags");
456 + break;
458 + case GST_EVENT_EOS:
459 + selpad->eos = TRUE;
460 + GST_DEBUG_OBJECT (pad, "received EOS");
461 + /* don't forward eos in select_all mode until all sink pads have eos */
462 + if (sel->select_all && !gst_input_selector_check_eos (GST_ELEMENT (sel))) {
463 + forward = FALSE;
465 + break;
466 + default:
467 + break;
469 + if (forward) {
470 + GST_DEBUG_OBJECT (pad, "forwarding event");
471 + res = gst_pad_push_event (sel->srcpad, event);
472 + } else
473 + gst_event_unref (event);
475 + gst_object_unref (sel);
477 + return res;
480 +static GstCaps *
481 +gst_selector_pad_getcaps (GstPad * pad)
483 + GstInputSelector *sel;
484 + GstCaps *caps;
486 + sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
488 + GST_DEBUG_OBJECT (sel, "Getting caps of srcpad peer");
489 + caps = gst_pad_peer_get_caps (sel->srcpad);
490 + if (caps == NULL)
491 + caps = gst_caps_new_any ();
493 + gst_object_unref (sel);
495 + return caps;
498 +static gboolean
499 +gst_selector_pad_acceptcaps (GstPad * pad, GstCaps * caps)
501 + GstInputSelector *sel;
502 + gboolean res;
504 + sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
506 + GST_DEBUG_OBJECT (sel, "Checking acceptcaps of srcpad peer");
507 + res = gst_pad_peer_accept_caps (sel->srcpad, caps);
508 + gst_object_unref (sel);
510 + return res;
513 +static GstFlowReturn
514 +gst_selector_pad_bufferalloc (GstPad * pad, guint64 offset,
515 + guint size, GstCaps * caps, GstBuffer ** buf)
517 + GstInputSelector *sel;
518 + GstFlowReturn result;
519 + GstPad *active_sinkpad;
520 + GstPad *prev_active_sinkpad;
521 + GstSelectorPad *selpad;
523 + sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
524 + selpad = GST_SELECTOR_PAD_CAST (pad);
526 + GST_DEBUG_OBJECT (pad, "received alloc");
528 + GST_INPUT_SELECTOR_LOCK (sel);
529 + prev_active_sinkpad = sel->active_sinkpad;
530 + active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
532 + if (pad != active_sinkpad)
533 + goto not_active;
535 + GST_INPUT_SELECTOR_UNLOCK (sel);
537 + if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad)
538 + g_object_notify (G_OBJECT (sel), "active-pad");
540 + result = gst_pad_alloc_buffer (sel->srcpad, offset, size, caps, buf);
542 +done:
543 + gst_object_unref (sel);
545 + return result;
547 + /* ERRORS */
548 +not_active:
550 + GST_INPUT_SELECTOR_UNLOCK (sel);
552 + /* unselected pad, perform fallback alloc or return unlinked when
553 + * asked */
554 + GST_OBJECT_LOCK (selpad);
555 + if (selpad->always_ok) {
556 + GST_DEBUG_OBJECT (pad, "Not selected, performing fallback allocation");
557 + *buf = NULL;
558 + result = GST_FLOW_OK;
559 + } else {
560 + GST_DEBUG_OBJECT (pad, "Not selected, return NOT_LINKED");
561 + result = GST_FLOW_NOT_LINKED;
563 + GST_OBJECT_UNLOCK (selpad);
565 + goto done;
569 +/* must be called with the SELECTOR_LOCK, will block while the pad is blocked
570 + * or return TRUE when flushing */
571 +static gboolean
572 +gst_input_selector_wait (GstInputSelector * self, GstPad * pad)
574 + while (self->blocked && !self->flushing) {
575 + /* we can be unlocked here when we are shutting down (flushing) or when we
576 + * get unblocked */
577 + GST_INPUT_SELECTOR_WAIT (self);
579 + return self->flushing;
582 +static GstFlowReturn
583 +gst_selector_pad_chain (GstPad * pad, GstBuffer * buf)
585 + GstInputSelector *sel;
586 + GstFlowReturn res;
587 + GstPad *active_sinkpad;
588 + GstPad *prev_active_sinkpad;
589 + GstSelectorPad *selpad;
590 + GstClockTime start_time;
591 + GstSegment *seg;
592 + GstEvent *close_event = NULL, *start_event = NULL;
593 + GstCaps *caps;
595 + sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
596 + selpad = GST_SELECTOR_PAD_CAST (pad);
597 + seg = &selpad->segment;
599 + GST_INPUT_SELECTOR_LOCK (sel);
600 + /* wait or check for flushing */
601 + if (gst_input_selector_wait (sel, pad))
602 + goto flushing;
604 + GST_DEBUG_OBJECT (pad, "getting active pad");
606 + prev_active_sinkpad = sel->active_sinkpad;
607 + active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
609 + /* update the segment on the srcpad */
610 + start_time = GST_BUFFER_TIMESTAMP (buf);
611 + if (GST_CLOCK_TIME_IS_VALID (start_time)) {
612 + GST_DEBUG_OBJECT (pad, "received start time %" GST_TIME_FORMAT,
613 + GST_TIME_ARGS (start_time));
614 + if (GST_BUFFER_DURATION_IS_VALID (buf))
615 + GST_DEBUG_OBJECT (pad, "received end time %" GST_TIME_FORMAT,
616 + GST_TIME_ARGS (start_time + GST_BUFFER_DURATION (buf)));
618 + GST_OBJECT_LOCK (pad);
619 + gst_segment_set_last_stop (seg, seg->format, start_time);
620 + GST_OBJECT_UNLOCK (pad);
623 + /* Ignore buffers from pads except the selected one */
624 + if (pad != active_sinkpad)
625 + goto ignore;
627 + if (G_UNLIKELY (sel->pending_close)) {
628 + GstSegment *cseg = &sel->segment;
630 + GST_DEBUG_OBJECT (sel,
631 + "pushing close NEWSEGMENT update %d, rate %lf, applied rate %lf, "
632 + "format %d, "
633 + "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
634 + G_GINT64_FORMAT, TRUE, cseg->rate, cseg->applied_rate, cseg->format,
635 + cseg->start, cseg->stop, cseg->time);
637 + /* create update segment */
638 + close_event = gst_event_new_new_segment_full (TRUE, cseg->rate,
639 + cseg->applied_rate, cseg->format, cseg->start, cseg->stop, cseg->time);
641 + sel->pending_close = FALSE;
643 + /* if we have a pending segment, push it out now */
644 + if (G_UNLIKELY (selpad->segment_pending)) {
645 + GST_DEBUG_OBJECT (pad,
646 + "pushing pending NEWSEGMENT update %d, rate %lf, applied rate %lf, "
647 + "format %d, "
648 + "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
649 + G_GINT64_FORMAT, FALSE, seg->rate, seg->applied_rate, seg->format,
650 + seg->start, seg->stop, seg->time);
652 + start_event = gst_event_new_new_segment_full (FALSE, seg->rate,
653 + seg->applied_rate, seg->format, seg->start, seg->stop, seg->time);
655 + selpad->segment_pending = FALSE;
657 + GST_INPUT_SELECTOR_UNLOCK (sel);
659 + if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad)
660 + g_object_notify (G_OBJECT (sel), "active-pad");
662 + if (close_event)
663 + gst_pad_push_event (sel->srcpad, close_event);
665 + if (start_event)
666 + gst_pad_push_event (sel->srcpad, start_event);
668 + if (selpad->discont) {
669 + buf = gst_buffer_make_metadata_writable (buf);
671 + GST_DEBUG_OBJECT (pad, "Marking discont buffer %p", buf);
672 + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
673 + selpad->discont = FALSE;
676 + /* forward */
677 + GST_DEBUG_OBJECT (pad, "Forwarding buffer %p from pad %s:%s", buf,
678 + GST_DEBUG_PAD_NAME (pad));
680 + if ((caps = GST_BUFFER_CAPS (buf))) {
681 + if (GST_PAD_CAPS (sel->srcpad) != caps)
682 + gst_pad_set_caps (sel->srcpad, caps);
685 + res = gst_pad_push (sel->srcpad, buf);
687 +done:
688 + gst_object_unref (sel);
689 + return res;
691 + /* dropped buffers */
692 +ignore:
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);
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);
708 + goto done;
710 +flushing:
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;
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);
724 +static void gst_input_selector_dispose (GObject * object);
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);
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);
735 +static GstStateChangeReturn gst_input_selector_change_state (GstElement *
736 + element, GstStateChange transition);
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);
745 +static GstElementClass *parent_class = NULL;
747 +GType
748 +gst_input_selector_get_type (void)
750 + static GType input_selector_type = 0;
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");
771 + return input_selector_type;
774 +static void
775 +gst_input_selector_base_init (GstInputSelectorClass * klass)
777 + GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
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));
786 +static void
787 +gst_input_selector_class_init (GstInputSelectorClass * klass)
789 + GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
790 + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
792 + parent_class = g_type_class_peek_parent (klass);
794 + gobject_class->dispose = gst_input_selector_dispose;
796 + gobject_class->set_property = gst_input_selector_set_property;
797 + gobject_class->get_property = gst_input_selector_get_property;
799 + g_object_class_install_property (gobject_class, PROP_N_PADS,
800 + g_param_spec_uint ("n-pads", "Number of Pads",
801 + "The number of sink pads", 0, G_MAXUINT, 0, G_PARAM_READABLE));
803 + g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
804 + g_param_spec_object ("active-pad", "Active pad",
805 + "The currently active sink pad", GST_TYPE_PAD, G_PARAM_READWRITE));
807 + g_object_class_install_property (gobject_class, PROP_SELECT_ALL,
808 + g_param_spec_boolean ("select-all", "Select all mode",
809 + "Forwards data from all input pads", FALSE, G_PARAM_READWRITE));
811 + /**
812 + * GstInputSelector::block:
813 + * @inputselector: the #GstInputSelector
815 + * Block all sink pads in preparation for a switch. Returns the stop time of
816 + * the current switch segment, as a running time, or 0 if there is no current
817 + * active pad or the current active pad never received data.
818 + */
819 + gst_input_selector_signals[SIGNAL_BLOCK] =
820 + g_signal_new ("block", G_TYPE_FROM_CLASS (klass),
821 + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
822 + G_STRUCT_OFFSET (GstInputSelectorClass, block), NULL, NULL,
823 + gst_selector_marshal_INT64__VOID, G_TYPE_INT64, 0);
824 + /**
825 + * GstInputSelector::switch:
826 + * @inputselector: the #GstInputSelector
827 + * @pad: the pad to switch to
828 + * @stop_time: running time at which to close the previous segment, or -1
829 + * to use the running time of the previously active sink pad
830 + * @start_time: running time at which to start the new segment, or -1 to
831 + * use the running time of the newly active sink pad
833 + * Switch to a new feed. The segment opened by the previously active pad, if
834 + * any, will be closed, and a new segment opened before data flows again.
836 + * This signal must be emitted when the element has been blocked via the <link
837 + * linkend="GstInputSelector-block">block</link> signal.
839 + * If you have a stream with only one switch element, such as an audio-only
840 + * stream, a stream switch should be performed by first emitting the block
841 + * signal, and then emitting the switch signal with -1 for the stop and start
842 + * time values.
844 + * The intention of the @stop_time and @start_time arguments is to allow
845 + * multiple switch elements to switch and maintain stream synchronization.
846 + * When switching a stream with multiple feeds, you will need as many switch
847 + * elements as you have feeds. For example, a feed with audio and video will
848 + * have one switch element between the audio feeds and one for video.
850 + * A switch over multiple switch elements should be performed as follows:
851 + * First, emit the <link linkend="GstInputSelector-block">block</link>
852 + * signal, collecting the returned values. The maximum running time returned
853 + * by block should then be used as the time at which to close the previous
854 + * segment.
856 + * Then, query the running times of the new audio and video pads that you will
857 + * switch to. Naturally, these pads are on separate switch elements. Take the
858 + * minimum running time for those streams and use it for the time at which to
859 + * open the new segment.
861 + * If @pad is the same as the current active pad, the element will cancel any
862 + * previous block without adjusting segments.
864 + * <note><simpara>
865 + * the signal changed from accepting the pad name to the pad object.
866 + * </simpara></note>
868 + * Since: 0.10.7
869 + */
870 + gst_input_selector_signals[SIGNAL_SWITCH] =
871 + g_signal_new ("switch", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
872 + G_STRUCT_OFFSET (GstInputSelectorClass, switch_),
873 + NULL, NULL, gst_selector_marshal_VOID__OBJECT_INT64_INT64,
874 + G_TYPE_NONE, 3, GST_TYPE_PAD, G_TYPE_INT64, G_TYPE_INT64);
876 + gstelement_class->request_new_pad = gst_input_selector_request_new_pad;
877 + gstelement_class->release_pad = gst_input_selector_release_pad;
878 + gstelement_class->change_state = gst_input_selector_change_state;
880 + klass->block = GST_DEBUG_FUNCPTR (gst_input_selector_block);
881 + /* note the underscore because switch is a keyword otherwise */
882 + klass->switch_ = GST_DEBUG_FUNCPTR (gst_input_selector_switch);
885 +static void
886 +gst_input_selector_init (GstInputSelector * sel)
888 + sel->srcpad = gst_pad_new ("src", GST_PAD_SRC);
889 + gst_pad_set_iterate_internal_links_function (sel->srcpad,
890 + GST_DEBUG_FUNCPTR (gst_selector_pad_iterate_linked_pads));
891 + gst_pad_set_getcaps_function (sel->srcpad,
892 + GST_DEBUG_FUNCPTR (gst_input_selector_getcaps));
893 + gst_pad_set_query_function (sel->srcpad,
894 + GST_DEBUG_FUNCPTR (gst_input_selector_query));
895 + gst_pad_set_event_function (sel->srcpad,
896 + GST_DEBUG_FUNCPTR (gst_input_selector_event));
897 + gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
898 + /* sinkpad management */
899 + sel->active_sinkpad = NULL;
900 + sel->padcount = 0;
901 + gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED);
903 + sel->lock = g_mutex_new ();
904 + sel->cond = g_cond_new ();
905 + sel->blocked = FALSE;
907 + sel->select_all = FALSE;
910 +static void
911 +gst_input_selector_dispose (GObject * object)
913 + GstInputSelector *sel = GST_INPUT_SELECTOR (object);
915 + if (sel->active_sinkpad) {
916 + gst_object_unref (sel->active_sinkpad);
917 + sel->active_sinkpad = NULL;
919 + if (sel->lock) {
920 + g_mutex_free (sel->lock);
921 + sel->lock = NULL;
923 + if (sel->cond) {
924 + g_cond_free (sel->cond);
925 + sel->cond = NULL;
928 + G_OBJECT_CLASS (parent_class)->dispose (object);
931 +/* Solve the following equation for B.timestamp, and set that as the segment
932 + * stop:
933 + * B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
934 + */
935 +static gint64
936 +gst_segment_get_timestamp (GstSegment * segment, gint64 running_time)
938 + if (running_time <= segment->accum)
939 + return segment->start;
940 + else
941 + return (running_time - segment->accum) * segment->abs_rate + segment->start;
944 +static void
945 +gst_segment_set_stop (GstSegment * segment, gint64 running_time)
947 + segment->stop = gst_segment_get_timestamp (segment, running_time);
948 + segment->last_stop = -1;
951 +static void
952 +gst_segment_set_start (GstSegment * segment, gint64 running_time)
954 + gint64 new_start, duration;
956 + new_start = gst_segment_get_timestamp (segment, running_time);
958 + /* this is the duration we skipped */
959 + duration = new_start - segment->start;
960 + /* add the duration to the accumulated segment time */
961 + segment->accum += duration;
962 + /* move position in the segment */
963 + segment->time += duration;
964 + segment->start += duration;
967 +/* this function must be called with the SELECTOR_LOCK. It returns TRUE when the
968 + * active pad changed. */
969 +static gboolean
970 +gst_input_selector_set_active_pad (GstInputSelector * self,
971 + GstPad * pad, gint64 stop_time, gint64 start_time)
973 + GstSelectorPad *old, *new;
974 + GstPad **active_pad_p;
976 + if (pad == self->active_sinkpad)
977 + return FALSE;
979 + old = GST_SELECTOR_PAD_CAST (self->active_sinkpad);
980 + new = GST_SELECTOR_PAD_CAST (pad);
982 + GST_DEBUG_OBJECT (self, "setting active pad to %s:%s",
983 + GST_DEBUG_PAD_NAME (new));
985 + if (stop_time == -1 && old) {
986 + /* no stop time given, get the latest running_time on the active pad to
987 + * close and open the new segment */
988 + stop_time = start_time = gst_selector_pad_get_running_time (old);
989 + GST_DEBUG_OBJECT (self, "using start/stop of %" G_GINT64_FORMAT,
990 + start_time);
993 + if (old && old->active && !self->pending_close && stop_time >= 0) {
994 + /* schedule a last_stop update if one isn't already scheduled, and a
995 + segment has been pushed before. */
996 + memcpy (&self->segment, &old->segment, sizeof (self->segment));
998 + GST_DEBUG_OBJECT (self, "setting stop_time to %" G_GINT64_FORMAT,
999 + stop_time);
1000 + gst_segment_set_stop (&self->segment, stop_time);
1001 + self->pending_close = TRUE;
1004 + if (new && new->active && start_time >= 0) {
1005 + GST_DEBUG_OBJECT (self, "setting start_time to %" G_GINT64_FORMAT,
1006 + start_time);
1007 + /* schedule a new segment push */
1008 + gst_segment_set_start (&new->segment, start_time);
1009 + new->segment_pending = TRUE;
1012 + active_pad_p = &self->active_sinkpad;
1013 + gst_object_replace ((GstObject **) active_pad_p, GST_OBJECT_CAST (pad));
1014 + GST_DEBUG_OBJECT (self, "New active pad is %" GST_PTR_FORMAT,
1015 + self->active_sinkpad);
1017 + return TRUE;
1020 +static void
1021 +gst_input_selector_set_property (GObject * object, guint prop_id,
1022 + const GValue * value, GParamSpec * pspec)
1024 + GstInputSelector *sel = GST_INPUT_SELECTOR (object);
1026 + switch (prop_id) {
1027 + case PROP_ACTIVE_PAD:
1029 + GstPad *pad;
1031 + pad = g_value_get_object (value);
1033 + GST_INPUT_SELECTOR_LOCK (sel);
1034 + gst_input_selector_set_active_pad (sel, pad,
1035 + GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE);
1036 + GST_INPUT_SELECTOR_UNLOCK (sel);
1037 + break;
1039 + case PROP_SELECT_ALL:
1040 + GST_INPUT_SELECTOR_LOCK (object);
1041 + sel->select_all = g_value_get_boolean (value);
1042 + GST_INPUT_SELECTOR_UNLOCK (object);
1043 + break;
1044 + default:
1045 + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1046 + break;
1050 +static void
1051 +gst_input_selector_get_property (GObject * object, guint prop_id,
1052 + GValue * value, GParamSpec * pspec)
1054 + GstInputSelector *sel = GST_INPUT_SELECTOR (object);
1056 + switch (prop_id) {
1057 + case PROP_N_PADS:
1058 + GST_INPUT_SELECTOR_LOCK (object);
1059 + g_value_set_uint (value, sel->n_pads);
1060 + GST_INPUT_SELECTOR_UNLOCK (object);
1061 + break;
1062 + case PROP_ACTIVE_PAD:
1063 + GST_INPUT_SELECTOR_LOCK (object);
1064 + g_value_set_object (value, sel->active_sinkpad);
1065 + GST_INPUT_SELECTOR_UNLOCK (object);
1066 + break;
1067 + case PROP_SELECT_ALL:
1068 + GST_INPUT_SELECTOR_LOCK (object);
1069 + g_value_set_boolean (value, sel->select_all);
1070 + GST_INPUT_SELECTOR_UNLOCK (object);
1071 + break;
1072 + default:
1073 + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1074 + break;
1078 +static GstPad *
1079 +gst_input_selector_get_linked_pad (GstPad * pad, gboolean strict)
1081 + GstInputSelector *sel;
1082 + GstPad *otherpad = NULL;
1084 + sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
1086 + GST_INPUT_SELECTOR_LOCK (sel);
1087 + if (pad == sel->srcpad)
1088 + otherpad = sel->active_sinkpad;
1089 + else if (pad == sel->active_sinkpad || !strict)
1090 + otherpad = sel->srcpad;
1091 + if (otherpad)
1092 + gst_object_ref (otherpad);
1093 + GST_INPUT_SELECTOR_UNLOCK (sel);
1095 + gst_object_unref (sel);
1097 + return otherpad;
1100 +static gboolean
1101 +gst_input_selector_event (GstPad * pad, GstEvent * event)
1103 + gboolean res = FALSE;
1104 + GstPad *otherpad;
1106 + otherpad = gst_input_selector_get_linked_pad (pad, TRUE);
1108 + if (otherpad) {
1109 + res = gst_pad_push_event (otherpad, event);
1111 + gst_object_unref (otherpad);
1112 + } else
1113 + gst_event_unref (event);
1114 + return res;
1117 +/* query on the srcpad. We override this function because by default it will
1118 + * only forward the query to one random sinkpad */
1119 +static gboolean
1120 +gst_input_selector_query (GstPad * pad, GstQuery * query)
1122 + gboolean res = TRUE;
1123 + GstInputSelector *sel;
1124 + GstPad *otherpad;
1126 + sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
1128 + otherpad = gst_input_selector_get_linked_pad (pad, TRUE);
1130 + switch (GST_QUERY_TYPE (query)) {
1131 + case GST_QUERY_LATENCY:
1133 + GList *walk;
1134 + GstClockTime resmin, resmax;
1135 + gboolean reslive;
1137 + resmin = 0;
1138 + resmax = -1;
1139 + reslive = FALSE;
1141 + /* assume FALSE, we become TRUE if one query succeeds */
1142 + res = FALSE;
1144 + /* perform the query on all sinkpads and combine the results. We take the
1145 + * max of min and the min of max for the result latency. */
1146 + GST_INPUT_SELECTOR_LOCK (sel);
1147 + for (walk = GST_ELEMENT_CAST (sel)->sinkpads; walk;
1148 + walk = g_list_next (walk)) {
1149 + GstPad *sinkpad = GST_PAD_CAST (walk->data);
1151 + if (gst_pad_peer_query (sinkpad, query)) {
1152 + GstClockTime min, max;
1153 + gboolean live;
1155 + /* one query succeeded, we succeed too */
1156 + res = TRUE;
1158 + gst_query_parse_latency (query, &live, &min, &max);
1160 + GST_DEBUG_OBJECT (sinkpad,
1161 + "peer latency min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT
1162 + ", live %d", GST_TIME_ARGS (min), GST_TIME_ARGS (max), live);
1164 + if (live) {
1165 + if (min > resmin)
1166 + resmin = min;
1167 + if (resmax == -1)
1168 + resmax = max;
1169 + else if (max < resmax)
1170 + resmax = max;
1171 + if (reslive == FALSE)
1172 + reslive = live;
1176 + GST_INPUT_SELECTOR_UNLOCK (sel);
1177 + if (res) {
1178 + gst_query_set_latency (query, reslive, resmin, resmax);
1180 + GST_DEBUG_OBJECT (sel,
1181 + "total latency min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT
1182 + ", live %d", GST_TIME_ARGS (resmin), GST_TIME_ARGS (resmax),
1183 + reslive);
1186 + break;
1188 + default:
1189 + if (otherpad)
1190 + res = gst_pad_peer_query (otherpad, query);
1191 + break;
1193 + if (otherpad)
1194 + gst_object_unref (otherpad);
1195 + gst_object_unref (sel);
1197 + return res;
1200 +static GstCaps *
1201 +gst_input_selector_getcaps (GstPad * pad)
1203 + GstPad *otherpad;
1204 + GstObject *parent;
1205 + GstCaps *caps;
1207 + parent = gst_object_get_parent (GST_OBJECT (pad));
1209 + otherpad = gst_input_selector_get_linked_pad (pad, FALSE);
1211 + if (!otherpad) {
1212 + if (GST_INPUT_SELECTOR (parent)->select_all) {
1213 + GST_DEBUG_OBJECT (parent,
1214 + "Pad %s:%s not linked, returning merge of caps",
1215 + GST_DEBUG_PAD_NAME (pad));
1216 + caps = gst_pad_proxy_getcaps (pad);
1217 + } else {
1218 + GST_DEBUG_OBJECT (parent,
1219 + "Pad %s:%s not linked, returning ANY", GST_DEBUG_PAD_NAME (pad));
1220 + caps = gst_caps_new_any ();
1222 + } else {
1223 + GST_DEBUG_OBJECT (parent,
1224 + "Pad %s:%s is linked (to %s:%s), returning peer caps",
1225 + GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (otherpad));
1226 + /* if the peer has caps, use those. If the pad is not linked, this function
1227 + * returns NULL and we return ANY */
1228 + if (!(caps = gst_pad_peer_get_caps (otherpad)))
1229 + caps = gst_caps_new_any ();
1230 + gst_object_unref (otherpad);
1233 + gst_object_unref (parent);
1234 + return caps;
1237 +/* check if the pad is the active sinkpad */
1238 +static inline gboolean
1239 +gst_input_selector_is_active_sinkpad (GstInputSelector * sel, GstPad * pad)
1241 + gboolean res;
1243 + GST_INPUT_SELECTOR_LOCK (sel);
1244 + res = (pad == sel->active_sinkpad);
1245 + GST_INPUT_SELECTOR_UNLOCK (sel);
1247 + return res;
1250 +/* Get or create the active sinkpad, must be called with SELECTOR_LOCK */
1251 +static GstPad *
1252 +gst_input_selector_activate_sinkpad (GstInputSelector * sel, GstPad * pad)
1254 + GstPad *active_sinkpad;
1255 + GstSelectorPad *selpad;
1257 + selpad = GST_SELECTOR_PAD_CAST (pad);
1259 + selpad->active = TRUE;
1260 + active_sinkpad = sel->active_sinkpad;
1261 + if (active_sinkpad == NULL || sel->select_all) {
1262 + /* first pad we get activity on becomes the activated pad by default, if we
1263 + * select all, we also remember the last used pad. */
1264 + if (sel->active_sinkpad)
1265 + gst_object_unref (sel->active_sinkpad);
1266 + active_sinkpad = sel->active_sinkpad = gst_object_ref (pad);
1267 + GST_DEBUG_OBJECT (sel, "Activating pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1270 + return active_sinkpad;
1273 +static GstPad *
1274 +gst_input_selector_request_new_pad (GstElement * element,
1275 + GstPadTemplate * templ, const gchar * unused)
1277 + GstInputSelector *sel;
1278 + gchar *name = NULL;
1279 + GstPad *sinkpad = NULL;
1281 + g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
1283 + sel = GST_INPUT_SELECTOR (element);
1285 + GST_INPUT_SELECTOR_LOCK (sel);
1287 + GST_LOG_OBJECT (sel, "Creating new pad %d", sel->padcount);
1288 + name = g_strdup_printf ("sink%d", sel->padcount++);
1289 + sinkpad = g_object_new (GST_TYPE_SELECTOR_PAD,
1290 + "name", name, "direction", templ->direction, "template", templ, NULL);
1291 + g_free (name);
1293 + sel->n_pads++;
1295 + gst_pad_set_event_function (sinkpad,
1296 + GST_DEBUG_FUNCPTR (gst_selector_pad_event));
1297 + gst_pad_set_getcaps_function (sinkpad,
1298 + GST_DEBUG_FUNCPTR (gst_selector_pad_getcaps));
1299 + gst_pad_set_acceptcaps_function (sinkpad,
1300 + GST_DEBUG_FUNCPTR (gst_selector_pad_acceptcaps));
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));
1308 + gst_pad_set_active (sinkpad, TRUE);
1309 + gst_element_add_pad (GST_ELEMENT (sel), sinkpad);
1310 + GST_INPUT_SELECTOR_UNLOCK (sel);
1312 + return sinkpad;
1315 +static void
1316 +gst_input_selector_release_pad (GstElement * element, GstPad * pad)
1318 + GstInputSelector *sel;
1320 + sel = GST_INPUT_SELECTOR (element);
1321 + GST_LOG_OBJECT (sel, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
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;
1330 + sel->n_pads--;
1332 + gst_pad_set_active (pad, FALSE);
1333 + gst_element_remove_pad (GST_ELEMENT (sel), pad);
1334 + GST_INPUT_SELECTOR_UNLOCK (sel);
1337 +static void
1338 +gst_input_selector_reset (GstInputSelector * sel)
1340 + GList *walk;
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;
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);
1355 + gst_selector_pad_reset (selpad);
1357 + if (selpad->tags) {
1358 + gst_tag_list_free (selpad->tags);
1359 + selpad->tags = NULL;
1362 + GST_INPUT_SELECTOR_UNLOCK (sel);
1365 +static GstStateChangeReturn
1366 +gst_input_selector_change_state (GstElement * element,
1367 + GstStateChange transition)
1369 + GstInputSelector *self = GST_INPUT_SELECTOR (element);
1370 + GstStateChangeReturn result;
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;
1392 + result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1394 + switch (transition) {
1395 + case GST_STATE_CHANGE_PAUSED_TO_READY:
1396 + gst_input_selector_reset (self);
1397 + break;
1398 + default:
1399 + break;
1402 + return result;
1405 +static gint64
1406 +gst_input_selector_block (GstInputSelector * self)
1408 + gint64 ret = 0;
1409 + GstSelectorPad *spad;
1411 + GST_INPUT_SELECTOR_LOCK (self);
1413 + if (self->blocked)
1414 + GST_WARNING_OBJECT (self, "switch already blocked");
1416 + self->blocked = TRUE;
1417 + spad = GST_SELECTOR_PAD_CAST (self->active_sinkpad);
1419 + if (spad)
1420 + ret = gst_selector_pad_get_running_time (spad);
1421 + else
1422 + GST_DEBUG_OBJECT (self, "no active pad while blocking");
1424 + GST_INPUT_SELECTOR_UNLOCK (self);
1426 + return ret;
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)
1434 + gboolean changed;
1436 + g_return_if_fail (self->blocked == TRUE);
1438 + GST_INPUT_SELECTOR_LOCK (self);
1439 + changed =
1440 + gst_input_selector_set_active_pad (self, pad, stop_time, start_time);
1442 + self->blocked = FALSE;
1443 + GST_INPUT_SELECTOR_BROADCAST (self);
1444 + GST_INPUT_SELECTOR_UNLOCK (self);
1446 + if (changed)
1447 + g_object_notify (G_OBJECT (self), "active-pad");
1450 +static gboolean
1451 +gst_input_selector_check_eos (GstElement * selector)
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;
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;
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;
1482 + gst_iterator_free (it);
1484 + return is_eos;
1486 --- /dev/null 2008-12-16 15:34:15.000000000 +0800
1487 +++ gst-plugins-good-0.10.21/gst/selector/gstinputselector.h 2008-12-16 15:09:01.086278737 +0800
1488 @@ -0,0 +1,84 @@
1489 +/* GStreamer
1490 + * Copyright (C) 2003 Julien Moutte <julien@moutte.net>
1491 + * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
1492 + * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
1494 + * This library is free software; you can redistribute it and/or
1495 + * modify it under the terms of the GNU Library General Public
1496 + * License as published by the Free Software Foundation; either
1497 + * version 2 of the License, or (at your option) any later version.
1499 + * This library is distributed in the hope that it will be useful,
1500 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1501 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1502 + * Library General Public License for more details.
1504 + * You should have received a copy of the GNU Library General Public
1505 + * License along with this library; if not, write to the
1506 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1507 + * Boston, MA 02111-1307, USA.
1508 + */
1510 +#ifndef __GST_INPUT_SELECTOR_H__
1511 +#define __GST_INPUT_SELECTOR_H__
1513 +#include <gst/gst.h>
1515 +G_BEGIN_DECLS
1517 +#define GST_TYPE_INPUT_SELECTOR \
1518 + (gst_input_selector_get_type())
1519 +#define GST_INPUT_SELECTOR(obj) \
1520 + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_INPUT_SELECTOR, GstInputSelector))
1521 +#define GST_INPUT_SELECTOR_CLASS(klass) \
1522 + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_INPUT_SELECTOR, GstInputSelectorClass))
1523 +#define GST_IS_INPUT_SELECTOR(obj) \
1524 + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_INPUT_SELECTOR))
1525 +#define GST_IS_INPUT_SELECTOR_CLASS(klass) \
1526 + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_INPUT_SELECTOR))
1528 +typedef struct _GstInputSelector GstInputSelector;
1529 +typedef struct _GstInputSelectorClass GstInputSelectorClass;
1531 +#define GST_INPUT_SELECTOR_GET_LOCK(sel) (((GstInputSelector*)(sel))->lock)
1532 +#define GST_INPUT_SELECTOR_GET_COND(sel) (((GstInputSelector*)(sel))->cond)
1533 +#define GST_INPUT_SELECTOR_LOCK(sel) (g_mutex_lock (GST_INPUT_SELECTOR_GET_LOCK(sel)))
1534 +#define GST_INPUT_SELECTOR_UNLOCK(sel) (g_mutex_unlock (GST_INPUT_SELECTOR_GET_LOCK(sel)))
1535 +#define GST_INPUT_SELECTOR_WAIT(sel) (g_cond_wait (GST_INPUT_SELECTOR_GET_COND(sel), \
1536 + GST_INPUT_SELECTOR_GET_LOCK(sel)))
1537 +#define GST_INPUT_SELECTOR_BROADCAST(sel) (g_cond_broadcast (GST_INPUT_SELECTOR_GET_COND(sel)))
1539 +struct _GstInputSelector {
1540 + GstElement element;
1542 + GstPad *srcpad;
1544 + GstPad *active_sinkpad;
1545 + guint n_pads;
1546 + guint padcount;
1548 + GstSegment segment; /* the output segment */
1549 + gboolean pending_close; /* if we should push a close first */
1551 + GMutex *lock;
1552 + GCond *cond;
1553 + gboolean blocked;
1554 + gboolean flushing;
1556 + /* select all mode, send data from all input pads forward */
1557 + gboolean select_all;
1560 +struct _GstInputSelectorClass {
1561 + GstElementClass parent_class;
1563 + gint64 (*block) (GstInputSelector *self);
1564 + void (*switch_) (GstInputSelector *self, GstPad *pad,
1565 + gint64 stop_time, gint64 start_time);
1568 +GType gst_input_selector_get_type (void);
1570 +G_END_DECLS
1572 +#endif /* __GST_INPUT_SELECTOR_H__ */
1573 --- /dev/null 2008-12-16 15:34:15.000000000 +0800
1574 +++ gst-plugins-good-0.10.21/gst/selector/gstoutputselector.c 2008-12-16 15:09:01.089181384 +0800
1575 @@ -0,0 +1,510 @@
1576 +/* GStreamer
1577 + * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
1579 + * This library is free software; you can redistribute it and/or
1580 + * modify it under the terms of the GNU Library General Public
1581 + * License as published by the Free Software Foundation; either
1582 + * version 2 of the License, or (at your option) any later version.
1584 + * This library is distributed in the hope that it will be useful,
1585 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1586 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1587 + * Library General Public License for more details.
1589 + * You should have received a copy of the GNU Library General Public
1590 + * License along with this library; if not, write to the
1591 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1592 + * Boston, MA 02111-1307, USA.
1593 + */
1595 +/**
1596 + * SECTION:element-output-selector
1597 + * @see_also: #GstOutputSelector, #GstInputSelector
1599 + * Direct input stream to one out of N output pads.
1600 + */
1602 +#ifdef HAVE_CONFIG_H
1603 +#include "config.h"
1604 +#endif
1606 +#include <string.h>
1608 +#include "gstoutputselector.h"
1610 +GST_DEBUG_CATEGORY_STATIC (output_selector_debug);
1611 +#define GST_CAT_DEFAULT output_selector_debug
1613 +static const GstElementDetails gst_output_selector_details =
1614 +GST_ELEMENT_DETAILS ("Output selector",
1615 + "Generic",
1616 + "1-to-N output stream selectoring",
1617 + "Stefan Kost <stefan.kost@nokia.com>");
1619 +static GstStaticPadTemplate gst_output_selector_sink_factory =
1620 +GST_STATIC_PAD_TEMPLATE ("sink",
1621 + GST_PAD_SINK,
1622 + GST_PAD_ALWAYS,
1623 + GST_STATIC_CAPS_ANY);
1625 +static GstStaticPadTemplate gst_output_selector_src_factory =
1626 +GST_STATIC_PAD_TEMPLATE ("src%d",
1627 + GST_PAD_SRC,
1628 + GST_PAD_REQUEST,
1629 + GST_STATIC_CAPS_ANY);
1631 +enum
1633 + PROP_0,
1634 + PROP_ACTIVE_PAD,
1635 + PROP_RESEND_LATEST,
1636 + PROP_LAST
1639 +GST_BOILERPLATE (GstOutputSelector, gst_output_selector, GstElement,
1640 + GST_TYPE_ELEMENT);
1642 +static void gst_output_selector_dispose (GObject * object);
1643 +static void gst_output_selector_set_property (GObject * object,
1644 + guint prop_id, const GValue * value, GParamSpec * pspec);
1645 +static void gst_output_selector_get_property (GObject * object,
1646 + guint prop_id, GValue * value, GParamSpec * pspec);
1647 +static GstPad *gst_output_selector_request_new_pad (GstElement * element,
1648 + GstPadTemplate * templ, const gchar * unused);
1649 +static void gst_output_selector_release_pad (GstElement * element,
1650 + GstPad * pad);
1651 +static GstFlowReturn gst_output_selector_chain (GstPad * pad, GstBuffer * buf);
1652 +static GstFlowReturn gst_output_selector_buffer_alloc (GstPad * pad,
1653 + guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
1654 +static GstStateChangeReturn gst_output_selector_change_state (GstElement *
1655 + element, GstStateChange transition);
1656 +static gboolean gst_output_selector_handle_sink_event (GstPad * pad,
1657 + GstEvent * event);
1659 +static void
1660 +gst_output_selector_base_init (gpointer g_class)
1662 + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1664 + gst_element_class_set_details (element_class, &gst_output_selector_details);
1665 + gst_element_class_add_pad_template (element_class,
1666 + gst_static_pad_template_get (&gst_output_selector_sink_factory));
1667 + gst_element_class_add_pad_template (element_class,
1668 + gst_static_pad_template_get (&gst_output_selector_src_factory));
1671 +static void
1672 +gst_output_selector_class_init (GstOutputSelectorClass * klass)
1674 + GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1675 + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1677 + parent_class = g_type_class_peek_parent (klass);
1679 + gobject_class->dispose = gst_output_selector_dispose;
1681 + gobject_class->set_property =
1682 + GST_DEBUG_FUNCPTR (gst_output_selector_set_property);
1683 + gobject_class->get_property =
1684 + GST_DEBUG_FUNCPTR (gst_output_selector_get_property);
1686 + g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
1687 + g_param_spec_object ("active-pad", "Active pad",
1688 + "Currently active src pad", GST_TYPE_PAD, G_PARAM_READWRITE));
1689 + g_object_class_install_property (gobject_class, PROP_RESEND_LATEST,
1690 + g_param_spec_boolean ("resend-latest", "Resend latest buffer",
1691 + "Resend latest buffer after a switch to a new pad", FALSE,
1692 + G_PARAM_READWRITE));
1694 + gstelement_class->request_new_pad =
1695 + GST_DEBUG_FUNCPTR (gst_output_selector_request_new_pad);
1696 + gstelement_class->release_pad =
1697 + GST_DEBUG_FUNCPTR (gst_output_selector_release_pad);
1699 + gstelement_class->change_state = gst_output_selector_change_state;
1701 + GST_DEBUG_CATEGORY_INIT (output_selector_debug,
1702 + "output-selector", 0, "An output stream selector element");
1705 +static void
1706 +gst_output_selector_init (GstOutputSelector * sel,
1707 + GstOutputSelectorClass * g_class)
1709 + sel->sinkpad =
1710 + gst_pad_new_from_static_template (&gst_output_selector_sink_factory,
1711 + "sink");
1712 + gst_pad_set_chain_function (sel->sinkpad,
1713 + GST_DEBUG_FUNCPTR (gst_output_selector_chain));
1714 + gst_pad_set_event_function (sel->sinkpad,
1715 + GST_DEBUG_FUNCPTR (gst_output_selector_handle_sink_event));
1716 + gst_pad_set_bufferalloc_function (sel->sinkpad,
1717 + GST_DEBUG_FUNCPTR (gst_output_selector_buffer_alloc));
1718 + /*
1719 + gst_pad_set_setcaps_function (sel->sinkpad,
1720 + GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
1721 + gst_pad_set_getcaps_function (sel->sinkpad,
1722 + GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
1723 + */
1725 + gst_element_add_pad (GST_ELEMENT (sel), sel->sinkpad);
1727 + /* srcpad management */
1728 + sel->active_srcpad = NULL;
1729 + sel->nb_srcpads = 0;
1730 + gst_segment_init (&sel->segment, GST_FORMAT_TIME);
1731 + sel->pending_srcpad = NULL;
1733 + sel->resend_latest = FALSE;
1734 + sel->latest_buffer = NULL;
1737 +static void
1738 +gst_output_selector_reset (GstOutputSelector * osel)
1740 + if (osel->pending_srcpad != NULL) {
1741 + gst_object_unref (osel->pending_srcpad);
1742 + osel->pending_srcpad = NULL;
1744 + if (osel->latest_buffer != NULL) {
1745 + gst_buffer_unref (osel->latest_buffer);
1746 + osel->latest_buffer = NULL;
1748 + gst_segment_init (&osel->segment, GST_FORMAT_UNDEFINED);
1751 +static void
1752 +gst_output_selector_dispose (GObject * object)
1754 + GstOutputSelector *osel = GST_OUTPUT_SELECTOR (object);
1756 + gst_output_selector_reset (osel);
1758 + G_OBJECT_CLASS (parent_class)->dispose (object);
1761 +static void
1762 +gst_output_selector_set_property (GObject * object, guint prop_id,
1763 + const GValue * value, GParamSpec * pspec)
1765 + GstOutputSelector *sel = GST_OUTPUT_SELECTOR (object);
1767 + switch (prop_id) {
1768 + case PROP_ACTIVE_PAD:
1770 + GstPad *next_pad;
1772 + next_pad = g_value_get_object (value);
1774 + GST_INFO_OBJECT (sel, "Activating pad %s:%s",
1775 + GST_DEBUG_PAD_NAME (next_pad));
1777 + GST_OBJECT_LOCK (object);
1778 + if (next_pad != sel->active_srcpad) {
1779 + /* switch to new srcpad in next chain run */
1780 + if (sel->pending_srcpad != NULL) {
1781 + GST_INFO ("replacing pending switch");
1782 + gst_object_unref (sel->pending_srcpad);
1784 + if (next_pad)
1785 + gst_object_ref (next_pad);
1786 + sel->pending_srcpad = next_pad;
1787 + } else {
1788 + GST_INFO ("pad already active");
1789 + if (sel->pending_srcpad != NULL) {
1790 + gst_object_unref (sel->pending_srcpad);
1791 + sel->pending_srcpad = NULL;
1794 + GST_OBJECT_UNLOCK (object);
1795 + break;
1797 + case PROP_RESEND_LATEST:{
1798 + sel->resend_latest = g_value_get_boolean (value);
1799 + break;
1801 + default:
1802 + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1803 + break;
1807 +static void
1808 +gst_output_selector_get_property (GObject * object, guint prop_id,
1809 + GValue * value, GParamSpec * pspec)
1811 + GstOutputSelector *sel = GST_OUTPUT_SELECTOR (object);
1813 + switch (prop_id) {
1814 + case PROP_ACTIVE_PAD:
1815 + GST_OBJECT_LOCK (object);
1816 + g_value_set_object (value,
1817 + sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad);
1818 + GST_OBJECT_UNLOCK (object);
1819 + break;
1820 + case PROP_RESEND_LATEST:{
1821 + GST_OBJECT_LOCK (object);
1822 + g_value_set_boolean (value, sel->resend_latest);
1823 + GST_OBJECT_UNLOCK (object);
1824 + break;
1826 + default:
1827 + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1828 + break;
1832 +static GstFlowReturn
1833 +gst_output_selector_buffer_alloc (GstPad * pad, guint64 offset, guint size,
1834 + GstCaps * caps, GstBuffer ** buf)
1836 + GstOutputSelector *sel;
1837 + GstFlowReturn res;
1838 + GstPad *allocpad;
1840 + sel = GST_OUTPUT_SELECTOR (GST_PAD_PARENT (pad));
1841 + res = GST_FLOW_NOT_LINKED;
1843 + GST_OBJECT_LOCK (sel);
1844 + allocpad = sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad;
1845 + if (allocpad) {
1846 + /* if we had a previous pad we used for allocating a buffer, continue using
1847 + * it. */
1848 + GST_DEBUG_OBJECT (sel, "using pad %s:%s for alloc",
1849 + GST_DEBUG_PAD_NAME (allocpad));
1850 + gst_object_ref (allocpad);
1851 + GST_OBJECT_UNLOCK (sel);
1853 + res = gst_pad_alloc_buffer (allocpad, offset, size, caps, buf);
1854 + gst_object_unref (allocpad);
1856 + GST_OBJECT_LOCK (sel);
1857 + } else {
1858 + /* fallback case, allocate a buffer of our own, add pad caps. */
1859 + GST_DEBUG_OBJECT (pad, "fallback buffer alloc");
1860 + *buf = NULL;
1861 + res = GST_FLOW_OK;
1863 + GST_OBJECT_UNLOCK (sel);
1865 + GST_DEBUG_OBJECT (sel, "buffer alloc finished: %s", gst_flow_get_name (res));
1867 + return res;
1870 +static GstPad *
1871 +gst_output_selector_request_new_pad (GstElement * element,
1872 + GstPadTemplate * templ, const gchar * name)
1874 + gchar *padname;
1875 + GstPad *srcpad;
1876 + GstOutputSelector *osel;
1878 + osel = GST_OUTPUT_SELECTOR (element);
1880 + GST_DEBUG_OBJECT (osel, "requesting pad");
1882 + GST_OBJECT_LOCK (osel);
1883 + padname = g_strdup_printf ("src%d", osel->nb_srcpads++);
1884 + srcpad = gst_pad_new_from_template (templ, padname);
1885 + GST_OBJECT_UNLOCK (osel);
1887 + gst_pad_set_active (srcpad, TRUE);
1888 + gst_element_add_pad (GST_ELEMENT (osel), srcpad);
1890 + /* Set the first requested src pad as active by default */
1891 + if (osel->active_srcpad == NULL) {
1892 + osel->active_srcpad = srcpad;
1894 + g_free (padname);
1896 + return srcpad;
1899 +static void
1900 +gst_output_selector_release_pad (GstElement * element, GstPad * pad)
1902 + GstOutputSelector *osel;
1904 + osel = GST_OUTPUT_SELECTOR (element);
1906 + GST_DEBUG_OBJECT (osel, "releasing pad");
1908 + gst_pad_set_active (pad, FALSE);
1910 + gst_element_remove_pad (GST_ELEMENT_CAST (osel), pad);
1913 +static gboolean
1914 +gst_output_selector_switch (GstOutputSelector * osel)
1916 + gboolean res = FALSE;
1917 + GstEvent *ev = NULL;
1918 + GstSegment *seg = NULL;
1919 + gint64 start = 0, position = 0;
1921 + /* Switch */
1922 + GST_OBJECT_LOCK (GST_OBJECT (osel));
1923 + GST_INFO ("switching to pad %" GST_PTR_FORMAT, osel->pending_srcpad);
1924 + if (gst_pad_is_linked (osel->pending_srcpad)) {
1925 + osel->active_srcpad = osel->pending_srcpad;
1926 + res = TRUE;
1928 + gst_object_unref (osel->pending_srcpad);
1929 + osel->pending_srcpad = NULL;
1930 + GST_OBJECT_UNLOCK (GST_OBJECT (osel));
1932 + /* Send NEWSEGMENT event and latest buffer if switching succeeded */
1933 + if (res) {
1934 + /* Send NEWSEGMENT to the pad we are going to switch to */
1935 + seg = &osel->segment;
1936 + /* If resending then mark newsegment start and position accordingly */
1937 + if (osel->resend_latest && osel->latest_buffer &&
1938 + GST_BUFFER_TIMESTAMP_IS_VALID (osel->latest_buffer)) {
1939 + start = position = GST_BUFFER_TIMESTAMP (osel->latest_buffer);
1940 + } else {
1941 + start = position = seg->last_stop;
1943 + ev = gst_event_new_new_segment (TRUE, seg->rate,
1944 + seg->format, start, seg->stop, position);
1945 + if (!gst_pad_push_event (osel->active_srcpad, ev)) {
1946 + GST_WARNING_OBJECT (osel,
1947 + "newsegment handling failed in %" GST_PTR_FORMAT,
1948 + osel->active_srcpad);
1951 + /* Resend latest buffer to newly switched pad */
1952 + if (osel->resend_latest && osel->latest_buffer) {
1953 + GST_INFO ("resending latest buffer");
1954 + gst_pad_push (osel->active_srcpad, osel->latest_buffer);
1955 + osel->latest_buffer = NULL;
1957 + } else {
1958 + GST_WARNING_OBJECT (osel, "switch failed, pad not linked");
1961 + return res;
1964 +static GstFlowReturn
1965 +gst_output_selector_chain (GstPad * pad, GstBuffer * buf)
1967 + GstFlowReturn res;
1968 + GstOutputSelector *osel;
1969 + GstClockTime last_stop, duration;
1971 + osel = GST_OUTPUT_SELECTOR (gst_pad_get_parent (pad));
1973 + if (osel->pending_srcpad) {
1974 + /* Do the switch */
1975 + gst_output_selector_switch (osel);
1978 + if (osel->latest_buffer) {
1979 + gst_buffer_unref (osel->latest_buffer);
1980 + osel->latest_buffer = NULL;
1983 + if (osel->resend_latest) {
1984 + /* Keep reference to latest buffer to resend it after switch */
1985 + osel->latest_buffer = gst_buffer_ref (buf);
1988 + /* Keep track of last stop and use it in NEWSEGMENT start after
1989 + switching to a new src pad */
1990 + last_stop = GST_BUFFER_TIMESTAMP (buf);
1991 + if (GST_CLOCK_TIME_IS_VALID (last_stop)) {
1992 + duration = GST_BUFFER_DURATION (buf);
1993 + if (GST_CLOCK_TIME_IS_VALID (duration)) {
1994 + last_stop += duration;
1996 + GST_LOG_OBJECT (osel, "setting last stop %" GST_TIME_FORMAT,
1997 + GST_TIME_ARGS (last_stop));
1998 + gst_segment_set_last_stop (&osel->segment, osel->segment.format, last_stop);
2001 + GST_LOG_OBJECT (osel, "pushing buffer to %" GST_PTR_FORMAT,
2002 + osel->active_srcpad);
2003 + res = gst_pad_push (osel->active_srcpad, buf);
2004 + gst_object_unref (osel);
2006 + return res;
2009 +static GstStateChangeReturn
2010 +gst_output_selector_change_state (GstElement * element,
2011 + GstStateChange transition)
2013 + GstOutputSelector *sel;
2014 + GstStateChangeReturn result;
2016 + sel = GST_OUTPUT_SELECTOR (element);
2018 + switch (transition) {
2019 + case GST_STATE_CHANGE_READY_TO_PAUSED:
2020 + break;
2021 + default:
2022 + break;
2025 + result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2027 + switch (transition) {
2028 + case GST_STATE_CHANGE_PAUSED_TO_READY:
2029 + gst_output_selector_reset (sel);
2030 + break;
2031 + default:
2032 + break;
2035 + return result;
2038 +static gboolean
2039 +gst_output_selector_handle_sink_event (GstPad * pad, GstEvent * event)
2041 + gboolean res = TRUE;
2042 + GstOutputSelector *sel;
2043 + GstPad *output_pad = NULL;
2045 + sel = GST_OUTPUT_SELECTOR (gst_pad_get_parent (pad));
2047 + switch (GST_EVENT_TYPE (event)) {
2048 + case GST_EVENT_NEWSEGMENT:
2050 + gboolean update;
2051 + GstFormat format;
2052 + gdouble rate, arate;
2053 + gint64 start, stop, time;
2055 + gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
2056 + &start, &stop, &time);
2058 + GST_DEBUG_OBJECT (sel,
2059 + "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
2060 + "format %d, " "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
2061 + G_GINT64_FORMAT, update, rate, arate, format, start, stop, time);
2063 + gst_segment_set_newsegment_full (&sel->segment, update,
2064 + rate, arate, format, start, stop, time);
2066 + /* Send newsegment to all src pads */
2067 + gst_pad_event_default (pad, event);
2068 + break;
2070 + case GST_EVENT_EOS:
2071 + /* Send eos to all src pads */
2072 + gst_pad_event_default (pad, event);
2073 + break;
2074 + default:
2075 + /* Send other events to pending or active src pad */
2076 + output_pad =
2077 + sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad;
2078 + res = gst_pad_push_event (output_pad, event);
2079 + break;
2082 + gst_object_unref (sel);
2084 + return res;
2086 --- /dev/null 2008-12-16 15:34:15.000000000 +0800
2087 +++ gst-plugins-good-0.10.21/gst/selector/gstoutputselector.h 2008-12-16 15:09:01.073579304 +0800
2088 @@ -0,0 +1,66 @@
2089 +/* GStreamer
2090 + * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
2092 + * This library is free software; you can redistribute it and/or
2093 + * modify it under the terms of the GNU Library General Public
2094 + * License as published by the Free Software Foundation; either
2095 + * version 2 of the License, or (at your option) any later version.
2097 + * This library is distributed in the hope that it will be useful,
2098 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2099 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2100 + * Library General Public License for more details.
2102 + * You should have received a copy of the GNU Library General Public
2103 + * License along with this library; if not, write to the
2104 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2105 + * Boston, MA 02111-1307, USA.
2106 + */
2108 +#ifndef __GST_OUTPUT_SELECTOR_H__
2109 +#define __GST_OUTPUT_SELECTOR_H__
2111 +#include <gst/gst.h>
2113 +G_BEGIN_DECLS
2115 +#define GST_TYPE_OUTPUT_SELECTOR \
2116 + (gst_output_selector_get_type())
2117 +#define GST_OUTPUT_SELECTOR(obj) \
2118 + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OUTPUT_SELECTOR, GstOutputSelector))
2119 +#define GST_OUTPUT_SELECTOR_CLASS(klass) \
2120 + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_OUTPUT_SELECTOR, GstOutputSelectorClass))
2121 +#define GST_IS_OUTPUT_SELECTOR(obj) \
2122 + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OUTPUT_SELECTOR))
2123 +#define GST_IS_OUTPUT_SELECTOR_CLASS(klass) \
2124 + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_OUTPUT_SELECTOR))
2126 +typedef struct _GstOutputSelector GstOutputSelector;
2127 +typedef struct _GstOutputSelectorClass GstOutputSelectorClass;
2129 +struct _GstOutputSelector {
2130 + GstElement element;
2132 + GstPad *sinkpad;
2134 + GstPad *active_srcpad;
2135 + GstPad *pending_srcpad;
2136 + guint nb_srcpads;
2138 + GstSegment segment;
2140 + /* resend latest buffer after switch */
2141 + gboolean resend_latest;
2142 + GstBuffer *latest_buffer;
2146 +struct _GstOutputSelectorClass {
2147 + GstElementClass parent_class;
2150 +GType gst_output_selector_get_type (void);
2152 +G_END_DECLS
2154 +#endif /* __GST_OUTPUT_SELECTOR_H__ */
2155 --- /dev/null 2008-12-16 15:34:15.000000000 +0800
2156 +++ gst-plugins-good-0.10.21/gst/selector/gstselector.c 2008-12-16 15:09:01.090104873 +0800
2157 @@ -0,0 +1,44 @@
2158 +/* GStreamer
2159 + * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
2161 + * This library is free software; you can redistribute it and/or
2162 + * modify it under the terms of the GNU Library General Public
2163 + * License as published by the Free Software Foundation; either
2164 + * version 2 of the License, or (at your option) any later version.
2166 + * This library is distributed in the hope that it will be useful,
2167 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2168 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2169 + * Library General Public License for more details.
2171 + * You should have received a copy of the GNU Library General Public
2172 + * License along with this library; if not, write to the
2173 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2174 + * Boston, MA 02111-1307, USA.
2175 + */
2177 +#ifdef HAVE_CONFIG_H
2178 +#include "config.h"
2179 +#endif
2181 +#include <gst/gst.h>
2183 +#include "gstinputselector.h"
2184 +#include "gstoutputselector.h"
2187 +static gboolean
2188 +plugin_init (GstPlugin * plugin)
2191 + return gst_element_register (plugin, "input-selector",
2192 + GST_RANK_NONE, GST_TYPE_INPUT_SELECTOR) &&
2193 + gst_element_register (plugin, "output-selector",
2194 + GST_RANK_NONE, GST_TYPE_OUTPUT_SELECTOR);
2197 +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2198 + GST_VERSION_MINOR,
2199 + "selector",
2200 + "input/output stream selector elements",
2201 + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
2202 --- /dev/null 2008-12-20 18:00:51.000000000 +0800
2203 +++ gst-plugins-good-0.10.21/gst/selector/gstselector-marshal.list 2008-12-16 15:09:01.089768915 +0800
2204 @@ -0,0 +1,2 @@
2205 +INT64:VOID
2206 +VOID:OBJECT,INT64,INT64
2207 diff -ruN gst-plugins-good-0.10.21.rig/configure.ac gst-plugins-good-0.10.21/configure.ac
2208 --- gst-plugins-good-0.10.21.rig/configure.ac 2010-03-11 23:23:18.783135772 +0000
2209 +++ gst-plugins-good-0.10.21/configure.ac 2010-03-11 23:24:00.041240170 +0000
2210 @@ -316,6 +316,7 @@
2211 AG_GST_CHECK_PLUGIN(rtp)
2212 AG_GST_CHECK_PLUGIN(rtpmanager)
2213 AG_GST_CHECK_PLUGIN(rtsp)
2214 +AG_GST_CHECK_PLUGIN(selector)
2215 AG_GST_CHECK_PLUGIN(shapewipe)
2216 AG_GST_CHECK_PLUGIN(smpte)
2217 AG_GST_CHECK_PLUGIN(spectrum)
2218 @@ -1104,6 +1105,7 @@
2219 gst/rtp/Makefile
2220 gst/rtpmanager/Makefile
2221 gst/rtsp/Makefile
2222 +gst/selector/Makefile
2223 gst/shapewipe/Makefile
2224 gst/smpte/Makefile
2225 gst/spectrum/Makefile