From 3f43bfacd2edf62c855e1fbc0c8b856d4a8fd771 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 16 Nov 2007 15:05:07 +0000 Subject: [PATCH] gst/playback/gststreamselector.*: Improve streamselector, make it select and unselect the current pad more intelligen... Original commit message from CVS: * gst/playback/gststreamselector.c: (gst_selector_pad_get_type), (gst_selector_pad_class_init), (gst_selector_pad_init), (gst_selector_pad_finalize), (gst_selector_pad_reset), (gst_selector_pad_get_linked_pads), (gst_selector_pad_event), (gst_selector_pad_getcaps), (gst_selector_pad_bufferalloc), (gst_selector_pad_chain), (gst_stream_selector_get_type), (gst_stream_selector_base_init), (gst_stream_selector_class_init), (gst_stream_selector_init), (gst_stream_selector_set_property), (gst_stream_selector_get_linked_pad), (gst_stream_selector_getcaps), (gst_stream_selector_is_active_sinkpad), (gst_stream_selector_activate_sinkpad), (gst_stream_selector_get_linked_pads), (gst_stream_selector_request_new_pad), (gst_stream_selector_release_pad): * gst/playback/gststreamselector.h: Improve streamselector, make it select and unselect the current pad more intelligently. Subclass GstPad for the sinkpads of the selector. Handle segments more correctly. Fix caps negotiation. Implement release_pad. --- ChangeLog | 25 ++ gst/playback/gststreamselector.c | 546 +++++++++++++++++++++++++++++---------- gst/playback/gststreamselector.h | 5 +- 3 files changed, 434 insertions(+), 142 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9204257..d476340 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,30 @@ 2007-11-16 Wim Taymans + * gst/playback/gststreamselector.c: (gst_selector_pad_get_type), + (gst_selector_pad_class_init), (gst_selector_pad_init), + (gst_selector_pad_finalize), (gst_selector_pad_reset), + (gst_selector_pad_get_linked_pads), (gst_selector_pad_event), + (gst_selector_pad_getcaps), (gst_selector_pad_bufferalloc), + (gst_selector_pad_chain), (gst_stream_selector_get_type), + (gst_stream_selector_base_init), (gst_stream_selector_class_init), + (gst_stream_selector_init), (gst_stream_selector_set_property), + (gst_stream_selector_get_linked_pad), + (gst_stream_selector_getcaps), + (gst_stream_selector_is_active_sinkpad), + (gst_stream_selector_activate_sinkpad), + (gst_stream_selector_get_linked_pads), + (gst_stream_selector_request_new_pad), + (gst_stream_selector_release_pad): + * gst/playback/gststreamselector.h: + Improve streamselector, make it select and unselect the current pad more + intelligently. + Subclass GstPad for the sinkpads of the selector. + Handle segments more correctly. + Fix caps negotiation. + Implement release_pad. + +2007-11-16 Wim Taymans + * gst/playback/gstdecodebin2.c: (gst_decode_bin_class_init), (gst_decode_group_check_if_drained), (source_pad_event_probe), (remove_fakesink): diff --git a/gst/playback/gststreamselector.c b/gst/playback/gststreamselector.c index 2eaf315..d556872 100644 --- a/gst/playback/gststreamselector.c +++ b/gst/playback/gststreamselector.c @@ -2,6 +2,7 @@ * Copyright (C) 2003 Julien Moutte * Copyright (C) 2005 Ronald S. Bultje * Copyright (C) 2005 Jan Schmidt + * Copyright (C) 2007 Wim Taymans * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,13 +20,6 @@ * Boston, MA 02111-1307, USA. */ -/* - * !!!!!!!!!!!!!!!!! Big phat warning. !!!!!!!!!!!!!!!!!!!!!! - * - * This is not a generic switch element. This is not to be used for - * any such purpose. Patches to make it do that will be rejected. - */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -43,7 +37,8 @@ GST_ELEMENT_DETAILS ("StreamSelector", "N-to-1 input stream_selectoring", "Julien Moutte \n" "Ronald S. Bultje \n" - "Jan Schmidt "); + "Jan Schmidt \n" + "Wim Taymans "); static GstStaticPadTemplate gst_stream_selector_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink%d", @@ -62,23 +57,320 @@ enum PROP_ACTIVE_PAD = 1 }; +static gboolean gst_stream_selector_is_active_sinkpad (GstStreamSelector * sel, + GstPad * pad); +static GstPad *gst_stream_selector_activate_sinkpad (GstStreamSelector * sel, + GstPad * pad); +static GstPad *gst_stream_selector_get_linked_pad (GstPad * pad, + gboolean strict); + +#define GST_TYPE_SELECTOR_PAD \ + (gst_selector_pad_get_type()) +#define GST_SELECTOR_PAD(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SELECTOR_PAD, GstSelectorPad)) +#define GST_SELECTOR_PAD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SELECTOR_PAD, GstSelectorPadClass)) +#define GST_IS_SELECTOR_PAD(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SELECTOR_PAD)) +#define GST_IS_SELECTOR_PAD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SELECTOR_PAD)) +#define GST_SELECTOR_PAD_CAST(obj) \ + ((GstSelectorPad *)(obj)) + +typedef struct _GstSelectorPad GstSelectorPad; +typedef struct _GstSelectorPadClass GstSelectorPadClass; + +struct _GstSelectorPad +{ + GstPad parent; + + gboolean active; + gboolean eos; + gboolean segment_pending; + GstSegment segment; +}; + +struct _GstSelectorPadClass +{ + GstPadClass parent; +}; + +static void gst_selector_pad_class_init (GstSelectorPadClass * klass); +static void gst_selector_pad_init (GstSelectorPad * pad); +static void gst_selector_pad_finalize (GObject * object); + +static GstPadClass *selector_pad_parent_class = NULL; + +static void gst_selector_pad_reset (GstSelectorPad * pad); +static gboolean gst_selector_pad_event (GstPad * pad, GstEvent * event); +static GstCaps *gst_selector_pad_getcaps (GstPad * pad); +static GList *gst_selector_pad_get_linked_pads (GstPad * pad); +static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf); +static GstFlowReturn gst_selector_pad_bufferalloc (GstPad * pad, + guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); + +static GType +gst_selector_pad_get_type (void) +{ + static GType selector_pad_type = 0; + + if (!selector_pad_type) { + static const GTypeInfo selector_pad_info = { + sizeof (GstSelectorPadClass), + NULL, + NULL, + (GClassInitFunc) gst_selector_pad_class_init, + NULL, + NULL, + sizeof (GstSelectorPad), + 0, + (GInstanceInitFunc) gst_selector_pad_init, + }; + + selector_pad_type = + g_type_register_static (GST_TYPE_PAD, "GstSelectorPad", + &selector_pad_info, 0); + } + return selector_pad_type; +} + +static void +gst_selector_pad_class_init (GstSelectorPadClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + selector_pad_parent_class = g_type_class_peek_parent (klass); + + gobject_class->finalize = gst_selector_pad_finalize; +} + +static void +gst_selector_pad_init (GstSelectorPad * pad) +{ +} + +static void +gst_selector_pad_finalize (GObject * object) +{ + GstSelectorPad *pad; + + pad = GST_SELECTOR_PAD_CAST (object); + + G_OBJECT_CLASS (selector_pad_parent_class)->finalize (object); +} + +static void +gst_selector_pad_reset (GstSelectorPad * pad) +{ + pad->active = FALSE; + pad->eos = FALSE; + gst_segment_init (&pad->segment, GST_FORMAT_UNDEFINED); +} + +/* strictly get the linked pad from the sinkpad. If the pad is active we return + * the srcpad else we return NULL */ +static GList * +gst_selector_pad_get_linked_pads (GstPad * pad) +{ + GstPad *otherpad; + + otherpad = gst_stream_selector_get_linked_pad (pad, TRUE); + if (!otherpad) + return NULL; + + /* need to drop the ref, internal linked pads is not MT safe */ + gst_object_unref (otherpad); + + return g_list_append (NULL, otherpad); +} + +static gboolean +gst_selector_pad_event (GstPad * pad, GstEvent * event) +{ + gboolean res = TRUE; + gboolean forward = TRUE; + GstStreamSelector *sel; + GstSelectorPad *selpad; + + sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad)); + selpad = GST_SELECTOR_PAD_CAST (pad); + + /* only forward if we are dealing with the active sinkpad */ + forward = gst_stream_selector_is_active_sinkpad (sel, pad); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_STOP: + gst_selector_pad_reset (selpad); + break; + case GST_EVENT_NEWSEGMENT: + { + gboolean update; + GstFormat format; + gdouble rate, arate; + gint64 start, stop, time; + + gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, + &start, &stop, &time); + + GST_DEBUG_OBJECT (sel, + "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, " + "format %d, " + "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" + G_GINT64_FORMAT, update, rate, arate, format, start, stop, time); + + gst_segment_set_newsegment_full (&selpad->segment, update, + rate, arate, format, start, stop, time); + /* if we are not going to forward the segment, mark the segment as + * pending */ + if (!forward) + selpad->segment_pending = TRUE; + break; + } + case GST_EVENT_EOS: + selpad->eos = TRUE; + break; + default: + break; + } + if (forward) + res = gst_pad_push_event (sel->srcpad, event); + + gst_object_unref (sel); + + return res; +} + +static GstCaps * +gst_selector_pad_getcaps (GstPad * pad) +{ + GstStreamSelector *sel; + GstCaps *caps; + + sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (sel, "Getting caps of srcpad peer"); + caps = gst_pad_peer_get_caps (sel->srcpad); + if (caps == NULL) + caps = gst_caps_new_any (); + + gst_object_unref (sel); + + return caps; +} + +static GstFlowReturn +gst_selector_pad_bufferalloc (GstPad * pad, guint64 offset, + guint size, GstCaps * caps, GstBuffer ** buf) +{ + GstStreamSelector *sel; + GstFlowReturn result; + GstPad *active_sinkpad; + + sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad)); + + active_sinkpad = gst_stream_selector_activate_sinkpad (sel, pad); + + /* Fallback allocation for buffers from pads except the selected one */ + if (pad != active_sinkpad) { + GST_DEBUG_OBJECT (sel, + "Pad %s:%s is not selected. Performing fallback allocation", + GST_DEBUG_PAD_NAME (pad)); + + *buf = NULL; + result = GST_FLOW_OK; + } else { + result = gst_pad_alloc_buffer (sel->srcpad, offset, size, caps, buf); + + /* FIXME: HACK. If buffer alloc returns not-linked, perform a fallback + * allocation. This should NOT be necessary, because playbin should + * properly block the source pad from running until it's finished hooking + * everything up, but playbin needs refactoring first. */ + if (result == GST_FLOW_NOT_LINKED) { + GST_DEBUG_OBJECT (sel, + "No peer pad yet - performing fallback allocation for pad %s:%s", + GST_DEBUG_PAD_NAME (pad)); + + *buf = NULL; + result = GST_FLOW_OK; + } + } + + gst_object_unref (sel); + + return result; +} + +static GstFlowReturn +gst_selector_pad_chain (GstPad * pad, GstBuffer * buf) +{ + GstStreamSelector *sel; + GstFlowReturn res; + GstPad *active_sinkpad; + GstSelectorPad *selpad; + GstClockTime timestamp; + GstSegment *seg; + + sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad)); + selpad = GST_SELECTOR_PAD_CAST (pad); + seg = &selpad->segment; + + active_sinkpad = gst_stream_selector_activate_sinkpad (sel, pad); + + timestamp = GST_BUFFER_TIMESTAMP (buf); + if (GST_CLOCK_TIME_IS_VALID (timestamp)) { + GST_DEBUG_OBJECT (sel, "received timestamp %" GST_TIME_FORMAT, + GST_TIME_ARGS (timestamp)); + gst_segment_set_last_stop (seg, seg->format, timestamp); + } + + /* Ignore buffers from pads except the selected one */ + if (pad != active_sinkpad) + goto ignore; + + /* if we have a pending segment, push it out now */ + if (selpad->segment_pending) { + gst_pad_push_event (sel->srcpad, gst_event_new_new_segment_full (FALSE, + seg->rate, seg->applied_rate, seg->format, seg->start, seg->stop, + seg->time)); + + selpad->segment_pending = FALSE; + } + + /* forward */ + GST_DEBUG_OBJECT (sel, "Forwarding buffer %p from pad %s:%s", buf, + GST_DEBUG_PAD_NAME (pad)); + res = gst_pad_push (sel->srcpad, buf); +done: + gst_object_unref (sel); + return res; + /* dropped buffers */ +ignore: + { + GST_DEBUG_OBJECT (sel, "Ignoring buffer %p from pad %s:%s", + buf, GST_DEBUG_PAD_NAME (pad)); + gst_buffer_unref (buf); + res = GST_FLOW_NOT_LINKED; + goto done; + } + +} + static void gst_stream_selector_dispose (GObject * object); static void gst_stream_selector_init (GstStreamSelector * sel); static void gst_stream_selector_base_init (GstStreamSelectorClass * klass); static void gst_stream_selector_class_init (GstStreamSelectorClass * klass); - -static GstCaps *gst_stream_selector_getcaps (GstPad * pad); -static GList *gst_stream_selector_get_linked_pads (GstPad * pad); +static void gst_stream_selector_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_stream_selector_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); static GstPad *gst_stream_selector_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * unused); -static GstFlowReturn gst_stream_selector_chain (GstPad * pad, GstBuffer * buf); -static void gst_stream_selector_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_stream_selector_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static GstFlowReturn gst_stream_selector_bufferalloc (GstPad * pad, - guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); - +static void gst_stream_selector_release_pad (GstElement * element, + GstPad * pad); +static GList *gst_stream_selector_get_linked_pads (GstPad * pad); +static GstCaps *gst_stream_selector_getcaps (GstPad * pad); static GstElementClass *parent_class = NULL; GType @@ -98,11 +390,9 @@ gst_stream_selector_get_type (void) 0, (GInstanceInitFunc) gst_stream_selector_init, }; - stream_selector_type = g_type_register_static (GST_TYPE_ELEMENT, "GstStreamSelector", &stream_selector_info, 0); - GST_DEBUG_CATEGORY_INIT (stream_selector_debug, "streamselector", 0, "A stream-selector element"); } @@ -116,7 +406,6 @@ gst_stream_selector_base_init (GstStreamSelectorClass * klass) GstElementClass *element_class = GST_ELEMENT_CLASS (klass); gst_element_class_set_details (element_class, &gst_stream_selector_details); - gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&gst_stream_selector_sink_factory)); gst_element_class_add_pad_template (element_class, @@ -130,19 +419,16 @@ gst_stream_selector_class_init (GstStreamSelectorClass * klass) GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); - gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_stream_selector_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_stream_selector_get_property); - g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD, - g_param_spec_string ("active-pad", "Active pad", "Name of the currently" - " active sink pad", NULL, G_PARAM_READWRITE)); - + g_param_spec_string ("active-pad", "Active pad", + "Name of the currently" " active sink pad", NULL, G_PARAM_READWRITE)); gobject_class->dispose = gst_stream_selector_dispose; - gstelement_class->request_new_pad = gst_stream_selector_request_new_pad; + gstelement_class->release_pad = gst_stream_selector_release_pad; } static void @@ -154,12 +440,10 @@ gst_stream_selector_init (GstStreamSelector * sel) gst_pad_set_getcaps_function (sel->srcpad, GST_DEBUG_FUNCPTR (gst_stream_selector_getcaps)); gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad); - /* sinkpad management */ sel->active_sinkpad = NULL; sel->nb_sinkpads = 0; - - //GST_OBJECT_FLAG_SET (sel, GST_ELEMENT_WORK_IN_PLACE); + gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED); } static void @@ -187,40 +471,28 @@ gst_stream_selector_set_property (GObject * object, guint prop_id, GstPad *pad = NULL; GstPad **active_pad_p; - if (strcmp (pad_name, "") != 0) { + if (strcmp (pad_name, "") != 0) pad = gst_element_get_pad (GST_ELEMENT (object), pad_name); - } - GST_OBJECT_LOCK (object); - if (pad == sel->active_sinkpad) { - GST_OBJECT_UNLOCK (object); - if (pad) - gst_object_unref (pad); - break; + if (pad != sel->active_sinkpad) { + GstSelectorPad *selpad; + + selpad = GST_SELECTOR_PAD_CAST (pad); + /* we can only activate pads that have data received */ + if (selpad && !selpad->active) { + GST_DEBUG_OBJECT (sel, "No data received on pad %" GST_PTR_FORMAT, + pad); + } else { + active_pad_p = &sel->active_sinkpad; + gst_object_replace ((GstObject **) active_pad_p, + GST_OBJECT_CAST (pad)); + GST_DEBUG_OBJECT (sel, "New active pad is %" GST_PTR_FORMAT, + sel->active_sinkpad); + } } -#if 0 - if (sel->active_sinkpad && (GST_STATE (sel) >= GST_STATE_PAUSED)) { - gst_pad_set_active (sel->active_sinkpad, FALSE); - GST_DEBUG_OBJECT (sel, "Deactivating pad %" GST_PTR_FORMAT, - sel->active_sinkpad); - } -#endif - - active_pad_p = &sel->active_sinkpad; - gst_object_replace ((GstObject **) active_pad_p, GST_OBJECT_CAST (pad)); + GST_OBJECT_UNLOCK (object); if (pad) gst_object_unref (pad); - -#if 0 - if (sel->active_sinkpad && (GST_STATE (sel) >= GST_STATE_PAUSED)) { - gst_pad_set_active (sel->active_sinkpad, TRUE); - GST_DEBUG_OBJECT (sel, "Activating pad %" GST_PTR_FORMAT, - sel->active_sinkpad); - } -#endif - GST_DEBUG_OBJECT (sel, "New active pad is %" GST_PTR_FORMAT, - sel->active_sinkpad); - GST_OBJECT_UNLOCK (object); break; } default: @@ -255,93 +527,98 @@ gst_stream_selector_get_property (GObject * object, guint prop_id, static GstPad * gst_stream_selector_get_linked_pad (GstPad * pad, gboolean strict) { - GstStreamSelector *sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad)); + GstStreamSelector *sel; GstPad *otherpad = NULL; + sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad)); + GST_OBJECT_LOCK (sel); if (pad == sel->srcpad) otherpad = sel->active_sinkpad; else if (pad == sel->active_sinkpad || !strict) otherpad = sel->srcpad; - + if (otherpad) + gst_object_ref (otherpad); + GST_OBJECT_UNLOCK (sel); gst_object_unref (sel); - return otherpad; } static GstCaps * gst_stream_selector_getcaps (GstPad * pad) { - GstPad *otherpad = gst_stream_selector_get_linked_pad (pad, FALSE); + GstPad *otherpad; GstObject *parent; + GstCaps *caps; + otherpad = gst_stream_selector_get_linked_pad (pad, FALSE); parent = gst_object_get_parent (GST_OBJECT (pad)); if (!otherpad) { GST_DEBUG_OBJECT (parent, "Pad %s:%s not linked, returning ANY", GST_DEBUG_PAD_NAME (pad)); - - gst_object_unref (parent); - return gst_caps_new_any (); + caps = gst_caps_new_any (); + } else { + GST_DEBUG_OBJECT (parent, + "Pad %s:%s is linked (to %s:%s), returning peer caps", + GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (otherpad)); + /* if the peer has caps, use those. If the pad is not linked, this function + * returns NULL and we return ANY */ + if (!(caps = gst_pad_peer_get_caps (otherpad))) + caps = gst_caps_new_any (); + gst_object_unref (otherpad); } - GST_DEBUG_OBJECT (parent, - "Pad %s:%s is linked (to %s:%s), returning allowed-caps", - GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (otherpad)); - gst_object_unref (parent); - - return gst_pad_peer_get_caps (otherpad); + return caps; } -static GstFlowReturn -gst_stream_selector_bufferalloc (GstPad * pad, guint64 offset, - guint size, GstCaps * caps, GstBuffer ** buf) +/* check if the pad is the active sinkpad */ +static gboolean +gst_stream_selector_is_active_sinkpad (GstStreamSelector * sel, GstPad * pad) { - GstStreamSelector *sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad)); - GstFlowReturn result; - GstPad *active_sinkpad; + GstSelectorPad *selpad; + gboolean res; + + selpad = GST_SELECTOR_PAD_CAST (pad); GST_OBJECT_LOCK (sel); - active_sinkpad = sel->active_sinkpad; + res = (pad == sel->active_sinkpad); GST_OBJECT_UNLOCK (sel); - /* Fallback allocation for buffers from pads except the selected one */ - if (pad != active_sinkpad) { - GST_DEBUG_OBJECT (sel, - "Pad %s:%s is not selected. Performing fallback allocation", - GST_DEBUG_PAD_NAME (pad)); + return res; +} - *buf = NULL; - result = GST_FLOW_OK; - } else { - result = gst_pad_alloc_buffer (sel->srcpad, offset, size, caps, buf); +/* Get or create the active sinkpad */ +static GstPad * +gst_stream_selector_activate_sinkpad (GstStreamSelector * sel, GstPad * pad) +{ + GstPad *active_sinkpad; + GstSelectorPad *selpad; - /* FIXME: HACK. If buffer alloc returns not-linked, perform a fallback - * allocation. This should NOT be necessary, because playbin should - * properly block the source pad from running until it's finished hooking - * everything up, but playbin needs refactoring first. */ - if (result == GST_FLOW_NOT_LINKED) { - GST_DEBUG_OBJECT (sel, - "No peer pad yet - performing fallback allocation for pad %s:%s", - GST_DEBUG_PAD_NAME (pad)); + selpad = GST_SELECTOR_PAD_CAST (pad); - *buf = NULL; - result = GST_FLOW_OK; - } + GST_OBJECT_LOCK (sel); + selpad->active = TRUE; + active_sinkpad = sel->active_sinkpad; + if (active_sinkpad == NULL) { + /* first pad we get an alloc on becomes the activated pad by default */ + active_sinkpad = sel->active_sinkpad = gst_object_ref (pad); + GST_DEBUG_OBJECT (sel, "Activating pad %s:%s", GST_DEBUG_PAD_NAME (pad)); } + GST_OBJECT_UNLOCK (sel); - gst_object_unref (sel); - - return result; + return active_sinkpad; } static GList * gst_stream_selector_get_linked_pads (GstPad * pad) { - GstPad *otherpad = gst_stream_selector_get_linked_pad (pad, TRUE); + GstPad *otherpad; + otherpad = gst_stream_selector_get_linked_pad (pad, TRUE); if (!otherpad) return NULL; - + /* need to drop the ref, internal linked pads is not MT safe */ + gst_object_unref (otherpad); return g_list_append (NULL, otherpad); } @@ -349,65 +626,52 @@ static GstPad * gst_stream_selector_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * unused) { - GstStreamSelector *sel = GST_STREAM_SELECTOR (element); + GstStreamSelector *sel; gchar *name = NULL; GstPad *sinkpad = NULL; + sel = GST_STREAM_SELECTOR (element); g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL); - GST_LOG_OBJECT (sel, "Creating new pad %d", sel->nb_sinkpads); - GST_OBJECT_LOCK (sel); name = g_strdup_printf ("sink%d", sel->nb_sinkpads++); - sinkpad = gst_pad_new_from_template (templ, name); + sinkpad = g_object_new (GST_TYPE_SELECTOR_PAD, + "name", name, "direction", templ->direction, "template", templ, NULL); g_free (name); - - if (sel->active_sinkpad == NULL) - sel->active_sinkpad = gst_object_ref (sinkpad); GST_OBJECT_UNLOCK (sel); + gst_pad_set_event_function (sinkpad, + GST_DEBUG_FUNCPTR (gst_selector_pad_event)); gst_pad_set_getcaps_function (sinkpad, - GST_DEBUG_FUNCPTR (gst_stream_selector_getcaps)); + GST_DEBUG_FUNCPTR (gst_selector_pad_getcaps)); gst_pad_set_chain_function (sinkpad, - GST_DEBUG_FUNCPTR (gst_stream_selector_chain)); + GST_DEBUG_FUNCPTR (gst_selector_pad_chain)); gst_pad_set_internal_link_function (sinkpad, - GST_DEBUG_FUNCPTR (gst_stream_selector_get_linked_pads)); + GST_DEBUG_FUNCPTR (gst_selector_pad_get_linked_pads)); gst_pad_set_bufferalloc_function (sinkpad, - GST_DEBUG_FUNCPTR (gst_stream_selector_bufferalloc)); + GST_DEBUG_FUNCPTR (gst_selector_pad_bufferalloc)); gst_pad_set_active (sinkpad, TRUE); gst_element_add_pad (GST_ELEMENT (sel), sinkpad); - return sinkpad; } -static GstFlowReturn -gst_stream_selector_chain (GstPad * pad, GstBuffer * buf) +static void +gst_stream_selector_release_pad (GstElement * element, GstPad * pad) { - GstStreamSelector *sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad)); - GstFlowReturn res; - GstPad *active_sinkpad; + GstStreamSelector *sel; - GST_OBJECT_LOCK (sel); - active_sinkpad = sel->active_sinkpad; - GST_OBJECT_UNLOCK (sel); + sel = GST_STREAM_SELECTOR (element); + GST_LOG_OBJECT (sel, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad)); - /* Ignore buffers from pads except the selected one */ - if (pad != active_sinkpad) { - GST_DEBUG_OBJECT (sel, "Ignoring buffer %p from pad %s:%s", - buf, GST_DEBUG_PAD_NAME (pad)); - - gst_object_unref (sel); - gst_buffer_unref (buf); - return GST_FLOW_NOT_LINKED; + GST_OBJECT_LOCK (sel); + /* if the pad was the active pad, makes us select a new one */ + if (sel->active_sinkpad == pad) { + GST_DEBUG_OBJECT (sel, "Deactivating pad %s:%s", GST_DEBUG_PAD_NAME (pad)); + sel->active_sinkpad = NULL; } + GST_OBJECT_UNLOCK (sel); - /* forward */ - GST_DEBUG_OBJECT (sel, "Forwarding buffer %p from pad %s:%s", - buf, GST_DEBUG_PAD_NAME (pad)); - res = gst_pad_push (sel->srcpad, buf); - - gst_object_unref (sel); - - return res; + gst_pad_set_active (pad, FALSE); + gst_element_remove_pad (GST_ELEMENT (sel), pad); } diff --git a/gst/playback/gststreamselector.h b/gst/playback/gststreamselector.h index cbd95ae..a7c4b22 100644 --- a/gst/playback/gststreamselector.h +++ b/gst/playback/gststreamselector.h @@ -42,9 +42,12 @@ typedef struct _GstStreamSelectorClass GstStreamSelectorClass; struct _GstStreamSelector { GstElement element; - GstPad *active_sinkpad; GstPad *srcpad; + + GstPad *active_sinkpad; guint nb_sinkpads; + + GstSegment segment; }; struct _GstStreamSelectorClass { -- 2.7.4