diff --git a/plugins/elements/gstinputselector.c b/plugins/elements/gstinputselector.c index e66eed3de5..9cd05c5bdf 100644 --- a/plugins/elements/gstinputselector.c +++ b/plugins/elements/gstinputselector.c @@ -65,13 +65,20 @@ GST_STATIC_PAD_TEMPLATE ("src", enum { - PROP_ACTIVE_PAD = 1, - PROP_SELECT_ALL + PROP_0, + PROP_N_PADS, + PROP_ACTIVE_PAD, + PROP_SELECT_ALL, + PROP_LAST }; enum { - PAD_PROP_RUNNING_TIME = 1 + PROP_PAD_0, + PROP_PAD_RUNNING_TIME, + PROP_PAD_TAGS, + PROP_PAD_ACTIVE, + PROP_PAD_LAST }; enum @@ -112,10 +119,12 @@ struct _GstSelectorPad { GstPad parent; - gboolean active; - gboolean eos; + gboolean active; /* when buffer have passed the pad */ + gboolean eos; /* when EOS has been received */ + GstSegment segment; /* the current segment on the pad */ + GstTagList *tags; /* last tags received on the pad */ + gboolean segment_pending; - GstSegment segment; }; struct _GstSelectorPadClass @@ -174,13 +183,21 @@ gst_selector_pad_class_init (GstSelectorPadClass * klass) selector_pad_parent_class = g_type_class_peek_parent (klass); + gobject_class->finalize = gst_selector_pad_finalize; + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_selector_pad_get_property); - g_object_class_install_property (gobject_class, PAD_PROP_RUNNING_TIME, + + g_object_class_install_property (gobject_class, PROP_PAD_RUNNING_TIME, g_param_spec_int64 ("running-time", "Running time", "Running time of stream on pad", 0, G_MAXINT64, 0, G_PARAM_READABLE)); - - gobject_class->finalize = gst_selector_pad_finalize; + g_object_class_install_property (gobject_class, PROP_PAD_TAGS, + g_param_spec_boxed ("tags", "Tags", + "The currently active tags on the pad", GST_TYPE_TAG_LIST, + G_PARAM_READABLE)); + g_object_class_install_property (gobject_class, PROP_PAD_ACTIVE, + g_param_spec_boolean ("active", "Active", + "If the pad is currently active", FALSE, G_PARAM_READABLE)); } static void @@ -196,6 +213,9 @@ gst_selector_pad_finalize (GObject * object) pad = GST_SELECTOR_PAD_CAST (object); + if (pad->tags) + gst_tag_list_free (pad->tags); + G_OBJECT_CLASS (selector_pad_parent_class)->finalize (object); } @@ -206,10 +226,24 @@ gst_selector_pad_get_property (GObject * object, guint prop_id, GstSelectorPad *spad = GST_SELECTOR_PAD_CAST (object); switch (prop_id) { - case PAD_PROP_RUNNING_TIME: + case PROP_PAD_RUNNING_TIME: g_value_set_int64 (value, gst_selector_pad_get_running_time (spad)); break; + case PROP_PAD_TAGS: + GST_OBJECT_LOCK (object); + g_value_set_boxed (value, spad->tags); + GST_OBJECT_UNLOCK (object); + break; + case PROP_PAD_ACTIVE: + { + GstInputSelector *sel; + sel = GST_INPUT_SELECTOR (gst_pad_get_parent (spad)); + g_value_set_boolean (value, gst_input_selector_is_active_sinkpad (sel, + GST_PAD_CAST (spad))); + gst_object_unref (sel); + break; + } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -311,6 +345,21 @@ gst_selector_pad_event (GstPad * pad, GstEvent * event) selpad->segment_pending = TRUE; break; } + case GST_EVENT_TAG: + { + GstTagList *tags; + + GST_OBJECT_LOCK (selpad); + if (selpad->tags) + gst_tag_list_free (selpad->tags); + gst_event_parse_tag (event, &tags); + if (tags) + tags = gst_tag_list_copy (tags); + selpad->tags = tags; + GST_DEBUG_OBJECT (sel, "received tags %" GST_PTR_FORMAT, selpad->tags); + GST_OBJECT_UNLOCK (selpad); + break; + } case GST_EVENT_EOS: selpad->eos = TRUE; /* don't forward eos in select_all mode until all sink pads have eos */ @@ -489,7 +538,7 @@ static GList *gst_input_selector_get_linked_pads (GstPad * pad); static GstCaps *gst_input_selector_getcaps (GstPad * pad); static gint64 gst_input_selector_block (GstInputSelector * self); static void gst_input_selector_switch (GstInputSelector * self, - const gchar * pad_name, gint64 stop_time, gint64 start_time); + GstPad * pad, gint64 stop_time, gint64 start_time); static GstElementClass *parent_class = NULL; @@ -539,20 +588,25 @@ gst_input_selector_class_init (GstInputSelectorClass * klass) GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); + + gobject_class->dispose = gst_input_selector_dispose; + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_input_selector_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_input_selector_get_property); + + g_object_class_install_property (gobject_class, PROP_N_PADS, + g_param_spec_uint ("n-pads", "Number of Pads", + "The number of sink pads", 0, G_MAXUINT, 0, G_PARAM_READABLE)); + 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_object ("active-pad", "Active pad", + "The currently active sink pad", GST_TYPE_PAD, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_SELECT_ALL, g_param_spec_boolean ("select-all", "Select all mode", "Forwards data from all input pads", FALSE, G_PARAM_READWRITE)); - gobject_class->dispose = gst_input_selector_dispose; - gstelement_class->request_new_pad = gst_input_selector_request_new_pad; - gstelement_class->release_pad = gst_input_selector_release_pad; - gstelement_class->change_state = gst_input_selector_change_state; /** * GstInputSelector::block: @@ -563,13 +617,14 @@ gst_input_selector_class_init (GstInputSelectorClass * klass) * active pad or the current active pad never received data. */ gst_input_selector_signals[SIGNAL_BLOCK] = - g_signal_new ("block", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstInputSelectorClass, block), - NULL, NULL, gst_selector_marshal_INT64__VOID, G_TYPE_INT64, 0); + g_signal_new ("block", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GstInputSelectorClass, block), NULL, NULL, + gst_selector_marshal_INT64__VOID, G_TYPE_INT64, 0); /** * GstInputSelector::switch: * @inputselector: the #GstInputSelector - * @pad: name of pad to switch to + * @pad: the pad to switch to * @stop_time: running time at which to close the previous segment, or -1 * to use the running time of the previously active sink pad * @start_time: running time at which to start the new segment, or -1 to @@ -609,8 +664,12 @@ gst_input_selector_class_init (GstInputSelectorClass * klass) gst_input_selector_signals[SIGNAL_SWITCH] = g_signal_new ("switch", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstInputSelectorClass, switch_), - NULL, NULL, gst_selector_marshal_VOID__STRING_INT64_INT64, - G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT64, G_TYPE_INT64); + NULL, NULL, gst_selector_marshal_VOID__OBJECT_INT64_INT64, + G_TYPE_NONE, 3, GST_TYPE_PAD, G_TYPE_INT64, G_TYPE_INT64); + + gstelement_class->request_new_pad = gst_input_selector_request_new_pad; + gstelement_class->release_pad = gst_input_selector_release_pad; + gstelement_class->change_state = gst_input_selector_change_state; klass->block = GST_DEBUG_FUNCPTR (gst_input_selector_block); klass->switch_ = GST_DEBUG_FUNCPTR (gst_input_selector_switch); @@ -627,7 +686,7 @@ gst_input_selector_init (GstInputSelector * sel) gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad); /* sinkpad management */ sel->active_sinkpad = NULL; - sel->nb_sinkpads = 0; + sel->padcount = 0; gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED); sel->blocked_cond = g_cond_new (); @@ -679,17 +738,11 @@ gst_segment_set_start (GstSegment * segment, gint64 running_time) static void gst_input_selector_set_active_pad (GstInputSelector * self, - const gchar * pad_name, gint64 stop_time, gint64 start_time) + GstPad * pad, gint64 stop_time, gint64 start_time) { - GstPad *pad; GstSelectorPad *old, *new; GstPad **active_pad_p; - if (strcmp (pad_name, "") != 0) - pad = gst_element_get_pad (GST_ELEMENT (self), pad_name); - else - pad = NULL; - GST_OBJECT_LOCK (self); if (pad == self->active_sinkpad) @@ -720,12 +773,8 @@ gst_input_selector_set_active_pad (GstInputSelector * self, done: GST_OBJECT_UNLOCK (self); - - if (pad) - gst_object_unref (pad); } - static void gst_input_selector_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -735,7 +784,7 @@ gst_input_selector_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_ACTIVE_PAD: gst_input_selector_set_active_pad (sel, - g_value_get_string (value), GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE); + g_value_get_object (value), GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE); break; case PROP_SELECT_ALL: sel->select_all = g_value_get_boolean (value); @@ -753,16 +802,16 @@ gst_input_selector_get_property (GObject * object, guint prop_id, GstInputSelector *sel = GST_INPUT_SELECTOR (object); switch (prop_id) { - case PROP_ACTIVE_PAD:{ + case PROP_N_PADS: GST_OBJECT_LOCK (object); - if (sel->active_sinkpad != NULL) { - g_value_take_string (value, gst_pad_get_name (sel->active_sinkpad)); - } else { - g_value_set_string (value, ""); - } + g_value_set_uint (value, sel->n_pads); + GST_OBJECT_UNLOCK (object); + break; + case PROP_ACTIVE_PAD: + GST_OBJECT_LOCK (object); + g_value_set_object (value, sel->active_sinkpad); GST_OBJECT_UNLOCK (object); break; - } case PROP_SELECT_ALL: g_value_set_boolean (value, sel->select_all); break; @@ -886,12 +935,13 @@ gst_input_selector_request_new_pad (GstElement * element, sel = GST_INPUT_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_LOG_OBJECT (sel, "Creating new pad %d", sel->padcount); GST_OBJECT_LOCK (sel); - name = g_strdup_printf ("sink%d", sel->nb_sinkpads++); + name = g_strdup_printf ("sink%d", sel->padcount++); sinkpad = g_object_new (GST_TYPE_SELECTOR_PAD, "name", name, "direction", templ->direction, "template", templ, NULL); g_free (name); + sel->n_pads++; GST_OBJECT_UNLOCK (sel); gst_pad_set_event_function (sinkpad, @@ -907,6 +957,7 @@ gst_input_selector_request_new_pad (GstElement * element, gst_pad_set_active (sinkpad, TRUE); gst_element_add_pad (GST_ELEMENT (sel), sinkpad); + return sinkpad; } @@ -924,6 +975,7 @@ gst_input_selector_release_pad (GstElement * element, GstPad * pad) GST_DEBUG_OBJECT (sel, "Deactivating pad %s:%s", GST_DEBUG_PAD_NAME (pad)); sel->active_sinkpad = NULL; } + sel->n_pads--; GST_OBJECT_UNLOCK (sel); gst_pad_set_active (pad, FALSE); @@ -983,6 +1035,8 @@ gst_input_selector_push_pending_stop (GstInputSelector * self) if (G_UNLIKELY (self->pending_stop)) { GstSegment *seg = &self->pending_stop_segment; + GST_DEBUG_OBJECT (self, "pushing pending stop"); + event = gst_event_new_new_segment_full (TRUE, seg->rate, seg->applied_rate, seg->format, seg->start, seg->stop, seg->stop); @@ -997,12 +1051,12 @@ gst_input_selector_push_pending_stop (GstInputSelector * self) /* stop_time and start_time are running times */ static void -gst_input_selector_switch (GstInputSelector * self, const gchar * pad_name, +gst_input_selector_switch (GstInputSelector * self, GstPad * pad, gint64 stop_time, gint64 start_time) { g_return_if_fail (self->blocked == TRUE); - gst_input_selector_set_active_pad (self, pad_name, stop_time, start_time); + gst_input_selector_set_active_pad (self, pad, stop_time, start_time); GST_OBJECT_LOCK (self); self->blocked = FALSE; diff --git a/plugins/elements/gstinputselector.h b/plugins/elements/gstinputselector.h index ee68346508..daefced8af 100644 --- a/plugins/elements/gstinputselector.h +++ b/plugins/elements/gstinputselector.h @@ -46,7 +46,8 @@ struct _GstInputSelector { GstPad *srcpad; GstPad *active_sinkpad; - guint nb_sinkpads; + guint n_pads; + guint padcount; GstSegment segment; @@ -63,7 +64,7 @@ struct _GstInputSelectorClass { GstElementClass parent_class; gint64 (*block) (GstInputSelector *self); - void (*switch_) (GstInputSelector *self, const gchar *pad_name, + void (*switch_) (GstInputSelector *self, GstPad *pad, gint64 stop_time, gint64 start_time); }; diff --git a/plugins/elements/gstoutputselector.c b/plugins/elements/gstoutputselector.c index 85c9356415..ea682a8f83 100644 --- a/plugins/elements/gstoutputselector.c +++ b/plugins/elements/gstoutputselector.c @@ -56,8 +56,10 @@ GST_STATIC_PAD_TEMPLATE ("src%d", enum { - PROP_ACTIVE_PAD = 1, - PROP_RESEND_LATEST + PROP_0, + PROP_ACTIVE_PAD, + PROP_RESEND_LATEST, + PROP_LAST }; static void gst_output_selector_dispose (GObject * object); @@ -126,24 +128,29 @@ gst_output_selector_class_init (GstOutputSelectorClass * klass) GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); + + gobject_class->dispose = gst_output_selector_dispose; + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_output_selector_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_output_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 src pad", NULL, G_PARAM_READWRITE)); + g_param_spec_object ("active-pad", "Active pad", + "Name of the currently active src pad", GST_TYPE_PAD, + G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_RESEND_LATEST, g_param_spec_boolean ("resend-latest", "Resend latest buffer", "Resend latest buffer after a switch to a new pad", FALSE, G_PARAM_READWRITE)); - gobject_class->dispose = gst_output_selector_dispose; + gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (gst_output_selector_request_new_pad); gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_output_selector_release_pad); - gstelement_class->change_state = gst_output_selector_change_state; + gstelement_class->change_state = gst_output_selector_change_state; } static void @@ -201,22 +208,23 @@ gst_output_selector_set_property (GObject * object, guint prop_id, GstOutputSelector *sel = GST_OUTPUT_SELECTOR (object); switch (prop_id) { - case PROP_ACTIVE_PAD:{ - GstPad *next_pad = - gst_element_get_static_pad (GST_ELEMENT (sel), - g_value_get_string (value)); - if (!next_pad) { - GST_WARNING ("pad %s not found, activation failed", - g_value_get_string (value)); - break; - } - GST_LOG ("Activating pad %s", g_value_get_string (value)); + case PROP_ACTIVE_PAD: + { + GstPad *next_pad; + + next_pad = g_value_get_object (value); + + GST_LOG ("Activating pad %s:%s", GST_DEBUG_PAD_NAME (next_pad)); + + GST_OBJECT_LOCK (object); if (next_pad != sel->active_srcpad) { /* switch to new srcpad in next chain run */ if (sel->pending_srcpad != NULL) { GST_INFO ("replacing pending switch"); gst_object_unref (sel->pending_srcpad); } + if (next_pad) + gst_object_ref (next_pad); sel->pending_srcpad = next_pad; } else { GST_INFO ("pad already active"); @@ -224,8 +232,8 @@ gst_output_selector_set_property (GObject * object, guint prop_id, gst_object_unref (sel->pending_srcpad); sel->pending_srcpad = NULL; } - gst_object_unref (next_pad); } + GST_OBJECT_UNLOCK (object); break; } case PROP_RESEND_LATEST:{ @@ -245,16 +253,11 @@ gst_output_selector_get_property (GObject * object, guint prop_id, GstOutputSelector *sel = GST_OUTPUT_SELECTOR (object); switch (prop_id) { - case PROP_ACTIVE_PAD:{ + case PROP_ACTIVE_PAD: GST_OBJECT_LOCK (object); - if (sel->active_srcpad != NULL) { - g_value_take_string (value, gst_pad_get_name (sel->active_srcpad)); - } else { - g_value_set_string (value, ""); - } + g_value_set_object (value, sel->active_srcpad); GST_OBJECT_UNLOCK (object); break; - } case PROP_RESEND_LATEST:{ GST_OBJECT_LOCK (object); g_value_set_boolean (value, sel->resend_latest); diff --git a/plugins/elements/gstselector-marshal.list b/plugins/elements/gstselector-marshal.list index 97c741cbb3..1102f04cb7 100644 --- a/plugins/elements/gstselector-marshal.list +++ b/plugins/elements/gstselector-marshal.list @@ -1,2 +1,2 @@ INT64:VOID -VOID:STRING,INT64,INT64 +VOID:OBJECT,INT64,INT64 diff --git a/tests/check/elements/selector.c b/tests/check/elements/selector.c index c4f6ca8d97..e308ac485d 100644 --- a/tests/check/elements/selector.c +++ b/tests/check/elements/selector.c @@ -129,8 +129,8 @@ cleanup_pad (GstPad * pad, GstElement * element) gst_object_unref (pad); /* cleanup selector pad, reffed by this function (_get_peer) and creator */ - gst_object_unref (selpad); gst_element_release_request_pad (element, selpad); + gst_object_unref (selpad); } /* Duplicate and push given buffer many times to all input_pads */ @@ -190,7 +190,7 @@ selector_set_active_pad (GstElement * elem, GstPad * selpad) padname = gst_pad_get_name (selpad); } - g_object_set (G_OBJECT (elem), "active-pad", padname, NULL); + g_object_set (G_OBJECT (elem), "active-pad", selpad, NULL); GST_DEBUG_OBJECT (elem, "activated selector pad: %s", padname); if (selpad) { g_free (padname); @@ -333,6 +333,7 @@ run_input_selector_buffer_count (gint num_input_pads, gst_pad_remove_data_probe (output_pad, probe_id); gst_pad_set_active (output_pad, FALSE); gst_check_teardown_sink_pad (sel); + GST_DEBUG ("setting selector pad to NULL"); selector_set_active_pad (sel, NULL); // unref input-selector active pad g_list_foreach (input_pads, (GFunc) cleanup_pad, sel); g_list_free (input_pads);