From f2cf753b17bcd10ece6e382f587a4f4d15e741bf Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Mon, 27 Jun 2005 18:35:05 +0000 Subject: [PATCH] gst/base/gsttypefindhelper.c (gst_type_find_helper): Unref any remaining buffer. Original commit message from CVS: 2005-06-27 Andy Wingo * gst/base/gsttypefindhelper.c (gst_type_find_helper): Unref any remaining buffer. * gst/gsttrace.c (gst_alloc_trace_list_sorted): New helper, returns a sorted copy of the trace list. (gst_alloc_trace_print_live): New API, only prints traces with live objects. Sort the list. (gst_alloc_trace_print_all): Sort the list. (gst_alloc_trace_print): Align columns. * gst/elements/gstttypefindelement.c: * gst/elements/gsttee.c: * gst/base/gstbasesrc.c: * gst/base/gstbasesink.c: * gst/base/gstbasetransform.c: * gst/gstqueue.c: Adapt for pad activation changes. * gst/gstpipeline.c (gst_pipeline_init): Unref after parenting sched. (gst_pipeline_dispose): Drop ref on sched. * gst/gstpad.c (gst_pad_init): Set the default activate func. (gst_pad_activate_default): Push mode by default. (pre_activate_switch, post_activate_switch): New stubs, things to do before and after switching activation modes on pads. (gst_pad_set_active): Take a boolean and not a mode, dispatch to the pad's activate function to choose which mode to activate. Shortcut on deactivation and call the right function directly. (gst_pad_activate_pull): New API, (de)activates a pad in pull mode. (gst_pad_activate_push): New API, same for push mode. (gst_pad_set_activate_function) (gst_pad_set_activatepull_function) (gst_pad_set_activatepush_function): Setters for new API. * gst/gstminiobject.c (gst_mini_object_new, gst_mini_object_free): Trace all miniobjects. (gst_mini_object_make_writable): Unref the arg if we copy, like gst_caps_make_writable. * gst/gstmessage.c (_gst_message_initialize): No trace init. * gst/gstghostpad.c (gst_proxy_pad_do_activate) (gst_proxy_pad_do_activatepull, gst_proxy_pad_do_activatepush): Adapt for new pad API. * gst/gstevent.c (_gst_event_initialize): Don't initialize trace. * gst/gstelement.h: * gst/gstelement.c (gst_element_iterate_src_pads) (gst_element_iterate_sink_pads): New API functions. * gst/gstelement.c (iterator_fold_with_resync): New utility, should fold into gstiterator.c in some form. (gst_element_pads_activate): Simplified via use of fold and delegation of decisions to gstpad->activate. * gst/gstbus.c (gst_bus_source_finalize): Set the bus to NULL, help in debugging. * gst/gstbuffer.c (_gst_buffer_initialize): Ref the buffer type class once in init, like gstmessage. Didn't run into this issue but it seems correct. Don't initialize a trace, gstminiobject does that. * check/pipelines/simple_launch_lines.c (test_stop_from_app): New test, runs fakesrc ! fakesink, stopping on ::handoff via a message to the bus. (assert_live_count): New util function, uses alloc traces to check cleanup. * check/gst/gstghostpad.c (test_ghost_pads): More refcount checks. To be modified when unlink drops the internal pad. --- ChangeLog | 76 ++++++ check/gst/gstghostpad.c | 33 +++ check/pipelines/simple_launch_lines.c | 65 ++++- docs/gst/tmpl/gstfakesrc.sgml | 5 + docs/gst/tmpl/gstpad.sgml | 6 +- gst/base/gstbasesink.c | 100 +++++--- gst/base/gstbasesrc.c | 92 ++++--- gst/base/gstbasetransform.c | 50 ++-- gst/base/gsttypefindhelper.c | 3 + gst/elements/gsttee.c | 49 ++-- gst/elements/gsttypefindelement.c | 114 +++++---- gst/gstbuffer.c | 16 +- gst/gstbus.c | 1 + gst/gstelement.c | 190 ++++++++------- gst/gstelement.h | 4 +- gst/gstevent.c | 9 - gst/gstghostpad.c | 74 +++++- gst/gstmessage.c | 10 +- gst/gstminiobject.c | 49 +++- gst/gstminiobject.h | 2 +- gst/gstpad.c | 357 +++++++++++++++++++--------- gst/gstpad.h | 15 +- gst/gstpipeline.c | 16 +- gst/gstqueue.c | 80 +++---- gst/gsttrace.c | 71 ++++-- gst/gsttrace.h | 1 + libs/gst/base/gstbasesink.c | 100 +++++--- libs/gst/base/gstbasesrc.c | 92 ++++--- libs/gst/base/gstbasetransform.c | 50 ++-- libs/gst/base/gsttypefindhelper.c | 3 + plugins/elements/gstqueue.c | 80 +++---- plugins/elements/gsttee.c | 49 ++-- plugins/elements/gsttypefindelement.c | 114 +++++---- tests/check/gst/gstghostpad.c | 33 +++ tests/check/pipelines/simple-launch-lines.c | 65 ++++- tools/gst-launch.c | 4 +- 36 files changed, 1379 insertions(+), 699 deletions(-) diff --git a/ChangeLog b/ChangeLog index 891346a..868d6db 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,79 @@ +2005-06-27 Andy Wingo + + * gst/base/gsttypefindhelper.c (gst_type_find_helper): Unref any + remaining buffer. + + * gst/gsttrace.c (gst_alloc_trace_list_sorted): New helper, + returns a sorted copy of the trace list. + (gst_alloc_trace_print_live): New API, only prints traces with + live objects. Sort the list. + (gst_alloc_trace_print_all): Sort the list. + (gst_alloc_trace_print): Align columns. + + * gst/elements/gstttypefindelement.c: + * gst/elements/gsttee.c: + * gst/base/gstbasesrc.c: + * gst/base/gstbasesink.c: + * gst/base/gstbasetransform.c: + * gst/gstqueue.c: Adapt for pad activation changes. + + * gst/gstpipeline.c (gst_pipeline_init): Unref after parenting + sched. + (gst_pipeline_dispose): Drop ref on sched. + + * gst/gstpad.c (gst_pad_init): Set the default activate func. + (gst_pad_activate_default): Push mode by default. + (pre_activate_switch, post_activate_switch): New stubs, things to + do before and after switching activation modes on pads. + (gst_pad_set_active): Take a boolean and not a mode, dispatch to + the pad's activate function to choose which mode to activate. + Shortcut on deactivation and call the right function directly. + (gst_pad_activate_pull): New API, (de)activates a pad in pull + mode. + (gst_pad_activate_push): New API, same for push mode. + (gst_pad_set_activate_function) + (gst_pad_set_activatepull_function) + (gst_pad_set_activatepush_function): Setters for new API. + + * gst/gstminiobject.c (gst_mini_object_new, gst_mini_object_free): + Trace all miniobjects. + (gst_mini_object_make_writable): Unref the arg if we copy, like + gst_caps_make_writable. + + * gst/gstmessage.c (_gst_message_initialize): No trace init. + + * gst/gstghostpad.c (gst_proxy_pad_do_activate) + (gst_proxy_pad_do_activatepull, gst_proxy_pad_do_activatepush): + Adapt for new pad API. + + * gst/gstevent.c (_gst_event_initialize): Don't initialize trace. + + * gst/gstelement.h: + * gst/gstelement.c (gst_element_iterate_src_pads) + (gst_element_iterate_sink_pads): New API functions. + + * gst/gstelement.c (iterator_fold_with_resync): New utility, + should fold into gstiterator.c in some form. + (gst_element_pads_activate): Simplified via use of fold and + delegation of decisions to gstpad->activate. + + * gst/gstbus.c (gst_bus_source_finalize): Set the bus to NULL, + help in debugging. + + * gst/gstbuffer.c (_gst_buffer_initialize): Ref the buffer type + class once in init, like gstmessage. Didn't run into this issue + but it seems correct. Don't initialize a trace, gstminiobject does + that. + + * check/pipelines/simple_launch_lines.c (test_stop_from_app): New + test, runs fakesrc ! fakesink, stopping on ::handoff via a message + to the bus. + (assert_live_count): New util function, uses alloc traces to check + cleanup. + + * check/gst/gstghostpad.c (test_ghost_pads): More refcount checks. + To be modified when unlink drops the internal pad. + 2005-06-27 Wim Taymans * gst/gstbin.c: (gst_bin_get_state), (gst_bin_iterate_state_order), diff --git a/check/gst/gstghostpad.c b/check/gst/gstghostpad.c index 44f910f..5ebcdd3 100644 --- a/check/gst/gstghostpad.c +++ b/check/gst/gstghostpad.c @@ -90,6 +90,39 @@ START_TEST (test_ghost_pads) fail_unless (gst_element_set_state (b1, GST_STATE_NULL) == GST_STATE_SUCCESS); gst_object_unref (GST_OBJECT (b1)); + /* unreffing the bin will unref all elements, which will unlink and unparent + * all pads */ + + /* FIXME: ghost pads need to drop their internal pad in the unlink function, + * but can't right now. So internal pads have a ref from their parent, and the + * internal pads' targets have refs from the internals. When we do the last + * unref on the ghost pads, these refs should go away. + */ + + assert_gstrefcount (fsrc, 2); /* gisrc */ + assert_gstrefcount (gsink, 1); + assert_gstrefcount (gsrc, 1); + assert_gstrefcount (fsink, 2); /* gisink */ + + assert_gstrefcount (gisrc, 2); /* gsink -- fixme drop ref in unlink */ + assert_gstrefcount (isink, 2); /* gsink */ + assert_gstrefcount (gisink, 2); /* gsrc -- fixme drop ref in unlink */ + assert_gstrefcount (isrc, 2); /* gsrc */ + + /* while the fixme isn't fixed, check cleanup */ + gst_object_unref (GST_OBJECT (gsink)); + assert_gstrefcount (isink, 1); + assert_gstrefcount (gisrc, 1); + assert_gstrefcount (fsrc, 2); /* gisrc */ + gst_object_unref (GST_OBJECT (gisrc)); + assert_gstrefcount (fsrc, 1); + + gst_object_unref (GST_OBJECT (gsrc)); + assert_gstrefcount (isrc, 1); + assert_gstrefcount (gisink, 1); + assert_gstrefcount (fsink, 2); /* gisrc */ + gst_object_unref (GST_OBJECT (gisink)); + assert_gstrefcount (fsink, 1); } END_TEST Suite * gst_ghost_pad_suite (void) { diff --git a/check/pipelines/simple_launch_lines.c b/check/pipelines/simple_launch_lines.c index 3e3db26..6ebf387 100644 --- a/check/pipelines/simple_launch_lines.c +++ b/check/pipelines/simple_launch_lines.c @@ -99,8 +99,68 @@ START_TEST (test_2_elements) ASSERT_CRITICAL (run_pipeline (setup_pipeline (s), s, GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN)); */ } -END_TEST Suite * -simple_launch_lines_suite (void) +END_TEST static void +got_handoff (GstElement * sink, GstBuffer * buf, GstPad * pad, gpointer unused) +{ + gst_element_post_message + (sink, gst_message_new_application (gst_structure_new ("foo", NULL))); +} + +static void +assert_live_count (GType type, gint live) +{ + GstAllocTrace *trace; + const gchar *name; + + if (gst_alloc_trace_available ()) { + name = g_type_name (type); + g_assert (name); + trace = gst_alloc_trace_get (name); + if (trace) { + g_return_if_fail (trace->live == live); + } + } else { + g_print ("\nSkipping live count tests; recompile with traces to enable\n"); + } +} + +START_TEST (test_stop_from_app) +{ + GstElement *fakesrc, *fakesink, *pipeline; + GstBus *bus; + GstMessageType revent; + + assert_live_count (GST_TYPE_BUFFER, 0); + + fakesrc = gst_element_factory_make ("fakesrc", NULL); + fakesink = gst_element_factory_make ("fakesink", NULL); + pipeline = gst_element_factory_make ("pipeline", NULL); + + g_return_if_fail (fakesrc && fakesink && pipeline); + + gst_element_link (fakesrc, fakesink); + gst_bin_add_many (GST_BIN (pipeline), fakesrc, fakesink, NULL); + + g_object_set (fakesink, "signal-handoffs", (gboolean) TRUE, NULL); + g_signal_connect (fakesink, "handoff", G_CALLBACK (got_handoff), NULL); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + bus = gst_element_get_bus (pipeline); + g_assert (bus); + + /* will time out after half a second */ + revent = gst_bus_poll (bus, GST_MESSAGE_APPLICATION, GST_SECOND / 2); + + g_return_if_fail (revent == GST_MESSAGE_APPLICATION); + gst_message_unref (gst_bus_pop (bus)); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (GST_OBJECT (pipeline)); + + assert_live_count (GST_TYPE_BUFFER, 0); +} +END_TEST Suite * simple_launch_lines_suite (void) { Suite *s = suite_create ("Pipelines"); TCase *tc_chain = tcase_create ("linear"); @@ -110,6 +170,7 @@ simple_launch_lines_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_2_elements); + tcase_add_test (tc_chain, test_stop_from_app); return s; } diff --git a/docs/gst/tmpl/gstfakesrc.sgml b/docs/gst/tmpl/gstfakesrc.sgml index c6dc59b..d67c381 100644 --- a/docs/gst/tmpl/gstfakesrc.sgml +++ b/docs/gst/tmpl/gstfakesrc.sgml @@ -63,6 +63,11 @@ GstFakeSrc + + + + + diff --git a/docs/gst/tmpl/gstpad.sgml b/docs/gst/tmpl/gstpad.sgml index 6509714..199d841 100644 --- a/docs/gst/tmpl/gstpad.sgml +++ b/docs/gst/tmpl/gstpad.sgml @@ -75,6 +75,8 @@ Last reviewed on December 13th, 2002 (0.5.0.1) @acceptcapsfunc: @fixatecapsfunc: @activatefunc: +@activatepushfunc: +@activatepullfunc: @linkfunc: @unlinkfunc: @peer: @@ -444,10 +446,10 @@ Checks if the pad is a sink pad. @pad: -@mode: +@active: @Returns: -@active: +@mode: diff --git a/gst/base/gstbasesink.c b/gst/base/gstbasesink.c index 4921178..081ca45 100644 --- a/gst/base/gstbasesink.c +++ b/gst/base/gstbasesink.c @@ -100,7 +100,8 @@ static GstElementStateReturn gst_basesink_change_state (GstElement * element); static GstFlowReturn gst_basesink_chain (GstPad * pad, GstBuffer * buffer); static void gst_basesink_loop (GstPad * pad); static GstFlowReturn gst_basesink_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_basesink_activate (GstPad * pad, GstActivateMode mode); +static gboolean gst_basesink_activate_push (GstPad * pad, gboolean active); +static gboolean gst_basesink_activate_pull (GstPad * pad, gboolean active); static gboolean gst_basesink_event (GstPad * pad, GstEvent * event); static inline GstFlowReturn gst_basesink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf); @@ -256,8 +257,10 @@ gst_basesink_finalize (GObject * object) static void gst_basesink_set_pad_functions (GstBaseSink * this, GstPad * pad) { - gst_pad_set_activate_function (pad, - GST_DEBUG_FUNCPTR (gst_basesink_activate)); + gst_pad_set_activatepush_function (pad, + GST_DEBUG_FUNCPTR (gst_basesink_activate_push)); + gst_pad_set_activatepull_function (pad, + GST_DEBUG_FUNCPTR (gst_basesink_activate_pull)); gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_basesink_event)); if (this->has_chain) @@ -824,51 +827,72 @@ paused: } static gboolean -gst_basesink_activate (GstPad * pad, GstActivateMode mode) +gst_basesink_deactivate (GstBaseSink * basesink, GstPad * pad) { gboolean result = FALSE; - GstBaseSink *basesink; GstBaseSinkClass *bclass; - basesink = GST_BASESINK (GST_OBJECT_PARENT (pad)); bclass = GST_BASESINK_GET_CLASS (basesink); - switch (mode) { - case GST_ACTIVATE_PUSH: - g_return_val_if_fail (basesink->has_chain, FALSE); - result = TRUE; - break; - case GST_ACTIVATE_PULL: - /* if we have a scheduler we can start the task */ - g_return_val_if_fail (basesink->has_loop, FALSE); - gst_pad_peer_set_active (pad, mode); - result = - gst_pad_start_task (pad, (GstTaskFunction) gst_basesink_loop, pad); - break; - case GST_ACTIVATE_NONE: - /* step 1, unblock clock sync (if any) or any other blocking thing */ - GST_PREROLL_LOCK (pad); - GST_LOCK (basesink); - if (basesink->clock_id) { - gst_clock_id_unschedule (basesink->clock_id); - } - GST_UNLOCK (basesink); + /* step 1, unblock clock sync (if any) or any other blocking thing */ + GST_PREROLL_LOCK (pad); + GST_LOCK (basesink); + if (basesink->clock_id) { + gst_clock_id_unschedule (basesink->clock_id); + } + GST_UNLOCK (basesink); - /* unlock any subclasses */ - if (bclass->unlock) - bclass->unlock (basesink); + /* unlock any subclasses */ + if (bclass->unlock) + bclass->unlock (basesink); - /* flush out the data thread if it's locked in finish_preroll */ - gst_basesink_preroll_queue_flush (basesink); - basesink->need_preroll = FALSE; - GST_PREROLL_SIGNAL (pad); - GST_PREROLL_UNLOCK (pad); + /* flush out the data thread if it's locked in finish_preroll */ + gst_basesink_preroll_queue_flush (basesink); + basesink->need_preroll = FALSE; + GST_PREROLL_SIGNAL (pad); + GST_PREROLL_UNLOCK (pad); - /* step 2, make sure streaming finishes */ - result = gst_pad_stop_task (pad); - break; + /* step 2, make sure streaming finishes */ + result = gst_pad_stop_task (pad); + + return result; +} + +static gboolean +gst_basesink_activate_push (GstPad * pad, gboolean active) +{ + gboolean result = FALSE; + GstBaseSink *basesink; + + basesink = GST_BASESINK (GST_OBJECT_PARENT (pad)); + + if (active) { + g_return_val_if_fail (basesink->has_chain, FALSE); + result = TRUE; + } else { + result = gst_basesink_deactivate (basesink, pad); + } + basesink->pad_mode = GST_ACTIVATE_PUSH; + + return result; +} + +/* this won't get called until we implement an activate function */ +static gboolean +gst_basesink_activate_pull (GstPad * pad, gboolean active) +{ + gboolean result = FALSE; + GstBaseSink *basesink; + + basesink = GST_BASESINK (GST_OBJECT_PARENT (pad)); + + if (active) { + /* if we have a scheduler we can start the task */ + g_return_val_if_fail (basesink->has_loop, FALSE); + result = gst_pad_start_task (pad, (GstTaskFunction) gst_basesink_loop, pad); + } else { + result = gst_basesink_deactivate (basesink, pad); } - basesink->pad_mode = mode; return result; } diff --git a/gst/base/gstbasesrc.c b/gst/base/gstbasesrc.c index 6600ade..4c3cb8d 100644 --- a/gst/base/gstbasesrc.c +++ b/gst/base/gstbasesrc.c @@ -82,7 +82,8 @@ gst_basesrc_get_type (void) return basesrc_type; } -static gboolean gst_basesrc_activate (GstPad * pad, GstActivateMode mode); +static gboolean gst_basesrc_activate_push (GstPad * pad, gboolean active); +static gboolean gst_basesrc_activate_pull (GstPad * pad, gboolean active); static void gst_basesrc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_basesrc_get_property (GObject * object, guint prop_id, @@ -158,7 +159,8 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class) pad = gst_pad_new_from_template (pad_template, "src"); - gst_pad_set_activate_function (pad, gst_basesrc_activate); + gst_pad_set_activatepush_function (pad, gst_basesrc_activate_push); + gst_pad_set_activatepull_function (pad, gst_basesrc_activate_pull); gst_pad_set_event_function (pad, gst_basesrc_event_handler); gst_pad_set_query_function (pad, gst_basesrc_query); @@ -729,54 +731,70 @@ gst_basesrc_stop (GstBaseSrc * basesrc) } static gboolean -gst_basesrc_activate (GstPad * pad, GstActivateMode mode) +gst_basesrc_deactivate (GstBaseSrc * basesrc, GstPad * pad) { gboolean result; + + GST_LIVE_LOCK (basesrc); + basesrc->live_running = TRUE; + GST_LIVE_SIGNAL (basesrc); + GST_LIVE_UNLOCK (basesrc); + + /* step 1, unblock clock sync (if any) */ + gst_basesrc_unlock (basesrc); + + /* step 2, make sure streaming finishes */ + result = gst_pad_stop_task (pad); + + return result; +} + +static gboolean +gst_basesrc_activate_push (GstPad * pad, gboolean active) +{ GstBaseSrc *basesrc; basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad)); /* prepare subclass first */ - switch (mode) { - case GST_ACTIVATE_PUSH: - case GST_ACTIVATE_PULL: - result = gst_basesrc_start (basesrc); - break; - default: - result = TRUE; - break; + if (active) { + if (!gst_basesrc_start (basesrc)) + goto error_start; + + return gst_pad_start_task (pad, (GstTaskFunction) gst_basesrc_loop, pad); + } else { + return gst_basesrc_deactivate (basesrc, pad); } - /* if that failed we can stop here */ - if (!result) - goto error_start; - result = FALSE; - switch (mode) { - case GST_ACTIVATE_PUSH: - result = - gst_pad_start_task (pad, (GstTaskFunction) gst_basesrc_loop, pad); - break; - case GST_ACTIVATE_PULL: - result = basesrc->seekable; - if (!result) - gst_basesrc_stop (basesrc); - break; - case GST_ACTIVATE_NONE: - GST_LIVE_LOCK (basesrc); - basesrc->live_running = TRUE; - GST_LIVE_SIGNAL (basesrc); - GST_LIVE_UNLOCK (basesrc); +error_start: + { + GST_DEBUG_OBJECT (basesrc, "failed to start"); + return FALSE; + } +} - /* step 1, unblock clock sync (if any) */ - gst_basesrc_unlock (basesrc); +static gboolean +gst_basesrc_activate_pull (GstPad * pad, gboolean active) +{ + GstBaseSrc *basesrc; - /* step 2, make sure streaming finishes */ - result = gst_pad_stop_task (pad); - break; + basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad)); + + /* prepare subclass first */ + if (active) { + if (!gst_basesrc_start (basesrc)) + goto error_start; + + if (!basesrc->seekable) { + gst_basesrc_stop (basesrc); + return FALSE; + } + + return TRUE; + } else { + return gst_basesrc_deactivate (basesrc, pad); } - return result; - /* ERROR */ error_start: { GST_DEBUG_OBJECT (basesrc, "failed to start"); diff --git a/gst/base/gstbasetransform.c b/gst/base/gstbasetransform.c index 9bc705a..0a29b36 100644 --- a/gst/base/gstbasetransform.c +++ b/gst/base/gstbasetransform.c @@ -84,10 +84,10 @@ static void gst_base_transform_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_base_transform_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean gst_base_transform_src_activate (GstPad * pad, - GstActivateMode mode); -static gboolean gst_base_transform_sink_activate (GstPad * pad, - GstActivateMode mode); +static gboolean gst_base_transform_src_activate_pull (GstPad * pad, + gboolean active); +static gboolean gst_base_transform_sink_activate_push (GstPad * pad, + gboolean active); static GstElementStateReturn gst_base_transform_change_state (GstElement * element); @@ -157,8 +157,8 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class) GST_DEBUG_FUNCPTR (gst_base_transform_event)); gst_pad_set_chain_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_chain)); - gst_pad_set_activate_function (trans->sinkpad, - GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate)); + gst_pad_set_activatepush_function (trans->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push)); gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad); pad_template = @@ -169,8 +169,8 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class) GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps)); gst_pad_set_getrange_function (trans->srcpad, GST_DEBUG_FUNCPTR (gst_base_transform_getrange)); - gst_pad_set_activate_function (trans->srcpad, - GST_DEBUG_FUNCPTR (gst_base_transform_src_activate)); + gst_pad_set_activatepull_function (trans->srcpad, + GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull)); gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad); } @@ -344,7 +344,7 @@ gst_base_transform_get_property (GObject * object, guint prop_id, } static gboolean -gst_base_transform_sink_activate (GstPad * pad, GstActivateMode mode) +gst_base_transform_sink_activate_push (GstPad * pad, gboolean active) { gboolean result = TRUE; GstBaseTransform *trans; @@ -353,39 +353,31 @@ gst_base_transform_sink_activate (GstPad * pad, GstActivateMode mode) trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad)); bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); - switch (mode) { - case GST_ACTIVATE_PUSH: - case GST_ACTIVATE_PULL: - if (bclass->start) - result = bclass->start (trans); - break; - case GST_ACTIVATE_NONE: - break; + if (active) { + if (bclass->start) + result = bclass->start (trans); } return result; } static gboolean -gst_base_transform_src_activate (GstPad * pad, GstActivateMode mode) +gst_base_transform_src_activate_pull (GstPad * pad, gboolean active) { gboolean result = FALSE; GstBaseTransform *trans; + GstBaseTransformClass *bclass; trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad)); + bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); - switch (mode) { - case GST_ACTIVATE_PUSH: - result = TRUE; - break; - case GST_ACTIVATE_PULL: - result = gst_pad_set_active (trans->sinkpad, mode); - result = gst_pad_peer_set_active (trans->sinkpad, mode); - break; - case GST_ACTIVATE_NONE: - result = TRUE; - break; + result = gst_pad_activate_pull (trans->sinkpad, active); + + if (active) { + if (result && bclass->start) + result &= bclass->start (trans); } + return result; } diff --git a/gst/base/gsttypefindhelper.c b/gst/base/gsttypefindhelper.c index d0edfba..884d7f9 100644 --- a/gst/base/gsttypefindhelper.c +++ b/gst/base/gsttypefindhelper.c @@ -130,5 +130,8 @@ gst_type_find_helper (GstPad * src, guint64 size) if (find.best_probability > 0) result = find.caps; + if (find.buffer) + gst_buffer_unref (find.buffer); + return result; } diff --git a/gst/elements/gsttee.c b/gst/elements/gsttee.c index 2b70a77..9b0bd65 100644 --- a/gst/elements/gsttee.c +++ b/gst/elements/gsttee.c @@ -75,7 +75,8 @@ static void gst_tee_get_property (GObject * object, guint prop_id, static GstFlowReturn gst_tee_chain (GstPad * pad, GstBuffer * buffer); static void gst_tee_loop (GstPad * pad); -static gboolean gst_tee_sink_activate (GstPad * pad, GstActivateMode mode); +static gboolean gst_tee_sink_activate_push (GstPad * pad, gboolean active); +static gboolean gst_tee_sink_activate_pull (GstPad * pad, gboolean active); static void @@ -153,8 +154,10 @@ gst_tee_init (GstTee * tee) static void gst_tee_update_pad_functions (GstTee * tee) { - gst_pad_set_activate_function (tee->sinkpad, - GST_DEBUG_FUNCPTR (gst_tee_sink_activate)); + gst_pad_set_activatepush_function (tee->sinkpad, + GST_DEBUG_FUNCPTR (gst_tee_sink_activate_push)); + gst_pad_set_activatepull_function (tee->sinkpad, + GST_DEBUG_FUNCPTR (gst_tee_sink_activate_pull)); if (tee->has_chain) gst_pad_set_chain_function (tee->sinkpad, @@ -348,27 +351,35 @@ pause_task: } static gboolean -gst_tee_sink_activate (GstPad * pad, GstActivateMode mode) +gst_tee_sink_activate_push (GstPad * pad, gboolean active) { - gboolean result = FALSE; GstTee *tee; tee = GST_TEE (GST_OBJECT_PARENT (pad)); - switch (mode) { - case GST_ACTIVATE_PUSH: - g_return_val_if_fail (tee->has_chain, FALSE); - result = TRUE; - break; - case GST_ACTIVATE_PULL: - g_return_val_if_fail (tee->has_sink_loop, FALSE); - result = gst_pad_start_task (pad, (GstTaskFunction) gst_tee_loop, pad); - break; - case GST_ACTIVATE_NONE: - result = gst_pad_stop_task (pad); - break; + tee->sink_mode = active && GST_ACTIVATE_PUSH; + + if (active) { + g_return_val_if_fail (tee->has_chain, FALSE); } - tee->sink_mode = mode; - return result; + return TRUE; +} + +/* won't be called until we implement an activate function */ +static gboolean +gst_tee_sink_activate_pull (GstPad * pad, gboolean active) +{ + GstTee *tee; + + tee = GST_TEE (GST_OBJECT_PARENT (pad)); + + tee->sink_mode = active && GST_ACTIVATE_PULL; + + if (active) { + g_return_val_if_fail (tee->has_sink_loop, FALSE); + return gst_pad_start_task (pad, (GstTaskFunction) gst_tee_loop, pad); + } else { + return gst_pad_stop_task (pad); + } } diff --git a/gst/elements/gsttypefindelement.c b/gst/elements/gsttypefindelement.c index 1eb7195..4fa1f34 100644 --- a/gst/elements/gsttypefindelement.c +++ b/gst/elements/gsttypefindelement.c @@ -133,8 +133,9 @@ static gboolean gst_type_find_element_checkgetrange (GstPad * srcpad); static GstElementStateReturn gst_type_find_element_change_state (GstElement * element); +static gboolean gst_type_find_element_activate (GstPad * pad); static gboolean -gst_type_find_element_activate (GstPad * pad, GstActivateMode mode); +gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active); static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 }; @@ -215,7 +216,8 @@ gst_type_find_element_init (GstTypeFindElement * typefind) typefind->src = gst_pad_new_from_template (gst_static_pad_template_get (&type_find_element_src_template), "src"); - gst_pad_set_activate_function (typefind->src, gst_type_find_element_activate); + gst_pad_set_activatepull_function (typefind->src, + gst_type_find_element_activate_src_pull); gst_pad_set_checkgetrange_function (typefind->src, gst_type_find_element_checkgetrange); gst_pad_set_getrange_function (typefind->src, gst_type_find_element_getrange); @@ -749,56 +751,80 @@ gst_type_find_element_getrange (GstPad * srcpad, } static gboolean -do_pull_typefind (GstTypeFindElement * typefind) +gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active) { - GstCaps *caps; - GstPad *peer; - gboolean res = FALSE; - - peer = gst_pad_get_peer (typefind->sink); - if (peer) { - if (gst_pad_peer_set_active (typefind->sink, GST_ACTIVATE_PULL)) { - gint64 size; - GstFormat format = GST_FORMAT_BYTES; - - gst_pad_query_position (peer, &format, NULL, &size); - caps = gst_type_find_helper (peer, (guint64) size); - if (caps) { - g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], - 0, 100, caps); - typefind->mode = MODE_NORMAL; - res = TRUE; - } - } else { - start_typefinding (typefind); - res = TRUE; - } + GstTypeFindElement *typefind; - gst_object_unref (GST_OBJECT (peer)); - } + typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad)); - return res; + return gst_pad_activate_pull (typefind->sink, active); } static gboolean -gst_type_find_element_activate (GstPad * pad, GstActivateMode mode) +gst_type_find_element_activate (GstPad * pad) { - gboolean result; + GstCaps *found_caps = NULL; GstTypeFindElement *typefind; typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad)); - switch (mode) { - case GST_ACTIVATE_PUSH: - case GST_ACTIVATE_PULL: - result = TRUE; - break; - default: - result = TRUE; - break; + /* 1. try to activate in pull mode. if not, switch to push and succeed. + 2. try to pull type find. + 3. deactivate pull mode. + 4. src pad might have been activated push by the state change. deactivate. + 5. if we didn't find any caps, fail. + 6. emit have-type; maybe the app connected the source pad to something. + 7. if the sink pad is activated, we are in pull mode. succeed. + otherwise activate both pads in push mode and succeed. + */ + + /* 1 */ + if (!gst_pad_activate_pull (pad, TRUE)) { + start_typefinding (typefind); + return gst_pad_activate_push (pad, TRUE); } - return result; + /* 2 */ + { + GstPad *peer; + + peer = gst_pad_get_peer (pad); + if (peer) { + gint64 size; + GstFormat format = GST_FORMAT_BYTES; + + gst_pad_query_position (peer, &format, NULL, &size); + found_caps = gst_type_find_helper (peer, (guint64) size); + gst_object_unref (GST_OBJECT (peer)); + } + } + + /* 3 */ + gst_pad_activate_pull (pad, FALSE); + + /* 4 */ + gst_pad_activate_push (typefind->src, FALSE); + + /* 5 */ + if (!found_caps) + return FALSE; + + /* 6 */ + g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], + 0, 100, found_caps); + typefind->mode = MODE_NORMAL; + /* FIXME see if I can unref the caps here */ + + /* 7 */ + if (gst_pad_is_active (pad)) + return TRUE; + else { + gboolean ret; + + ret = gst_pad_activate_push (typefind->src, TRUE); + ret &= gst_pad_activate_push (pad, TRUE); + return ret; + } } static GstElementStateReturn @@ -811,21 +837,11 @@ gst_type_find_element_change_state (GstElement * element) typefind = GST_TYPE_FIND_ELEMENT (element); transition = GST_STATE_TRANSITION (element); - switch (transition) { - case GST_STATE_READY_TO_PAUSED: - if (!do_pull_typefind (typefind)) - return GST_STATE_FAILURE; - //start_typefinding (typefind); - break; - default: - break; - } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); switch (transition) { case GST_STATE_PAUSED_TO_READY: - //stop_typefinding (typefind); gst_caps_replace (&typefind->caps, NULL); break; default: diff --git a/gst/gstbuffer.c b/gst/gstbuffer.c index 56532e4..322bd21 100644 --- a/gst/gstbuffer.c +++ b/gst/gstbuffer.c @@ -27,12 +27,6 @@ #include "gstutils.h" #include "gstminiobject.h" -#ifndef GST_DISABLE_TRACE -/* #define GST_WITH_ALLOC_TRACE */ -#include "gsttrace.h" - -static GstAllocTrace *_gst_buffer_trace; -#endif static void gst_buffer_init (GTypeInstance * instance, gpointer g_class); static void gst_buffer_class_init (gpointer g_class, gpointer class_data); @@ -43,11 +37,15 @@ static GstBuffer *_gst_buffer_copy (GstBuffer * buffer); void _gst_buffer_initialize (void) { + gpointer ptr; + gst_buffer_get_type (); -#ifndef GST_DISABLE_TRACE - _gst_buffer_trace = gst_alloc_trace_register (GST_BUFFER_TRACE_NAME); -#endif + /* the GstMiniObject types need to be class_ref'd once before it can be + * done from multiple threads; + * see http://bugzilla.gnome.org/show_bug.cgi?id=304551 */ + ptr = g_type_class_ref (GST_TYPE_BUFFER); + g_type_class_unref (ptr); } GType diff --git a/gst/gstbus.c b/gst/gstbus.c index f08e5cc..e53ff6a 100644 --- a/gst/gstbus.c +++ b/gst/gstbus.c @@ -434,6 +434,7 @@ gst_bus_source_finalize (GSource * source) GstBusSource *bsource = (GstBusSource *) source; gst_object_unref (GST_OBJECT_CAST (bsource->bus)); + bsource->bus = NULL; } static GSourceFuncs gst_bus_source_funcs = { diff --git a/gst/gstelement.c b/gst/gstelement.c index 77ef5f2..25c27f3 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -830,7 +830,7 @@ iterate_pad (GstIterator * it, GstPad * pad) * * Retrieves an iterattor of @element's pads. * - * Returns: the #GstIterator of #GstPad. unref each pad after usage. + * Returns: the #GstIterator of #GstPad. Unref each pad after use. * * MT safe. */ @@ -854,6 +854,56 @@ gst_element_iterate_pads (GstElement * element) return result; } +static gint +direction_filter (gconstpointer pad, gconstpointer direction) +{ + if (GST_PAD_DIRECTION (pad) == GPOINTER_TO_INT (direction)) { + /* pass the ref through */ + return 0; + } else { + /* unref */ + gst_object_unref (GST_OBJECT (pad)); + return 1; + } +} + +/** + * gst_element_iterate_src_pads: + * @element: a #GstElement. + * + * Retrieves an iterator of @element's source pads. + * + * Returns: the #GstIterator of #GstPad. Unref each pad after use. + * + * MT safe. + */ +GstIterator * +gst_element_iterate_src_pads (GstElement * element) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); + + return gst_iterator_filter (gst_element_iterate_pads (element), + direction_filter, GINT_TO_POINTER (GST_PAD_SRC)); +} + +/** + * gst_element_iterate_sink_pads: + * @element: a #GstElement. + * + * Retrieves an iterator of @element's sink pads. + * + * Returns: the #GstIterator of #GstPad. Unref each pad after use. + * + * MT safe. + */ +GstIterator * +gst_element_iterate_sink_pads (GstElement * element) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); + + return gst_iterator_filter (gst_element_iterate_pads (element), + direction_filter, GINT_TO_POINTER (GST_PAD_SINK)); +} /** * gst_element_class_add_pad_template: @@ -1792,97 +1842,73 @@ invalid_return: } } -/* is called with STATE_LOCK - * - * This function activates the pads of a given element. - * - * TODO: activate pads from src to sinks? - * move pad activate logic to GstPad because we also need this - * when pads are added to elements? - */ +/* gst_iterator_fold functions for pads_activate */ + static gboolean -gst_element_pads_activate (GstElement * element, gboolean active) +activate_pads (GstPad * pad, GValue * ret, gboolean * active) { - GList *pads; - gboolean result; - guint32 cookie; + if (!gst_pad_set_active (pad, *active)) + g_value_set_boolean (ret, FALSE); - GST_LOCK (element); -restart: - result = TRUE; - pads = element->pads; - cookie = element->pads_cookie; - for (; pads && result; pads = g_list_next (pads)) { - GstPad *pad, *peer; - gboolean pad_loop, pad_get; - gboolean done = FALSE; - - pad = GST_PAD (pads->data); - gst_object_ref (GST_OBJECT (pad)); - GST_UNLOCK (element); - - if (active) { - pad_get = GST_PAD_IS_SINK (pad) && gst_pad_check_pull_range (pad); - - /* see if the pad has a loop function and grab - * the peer */ - GST_LOCK (pad); - pad_loop = GST_PAD_LOOPFUNC (pad) != NULL; - peer = GST_PAD_PEER (pad); - if (peer) - gst_object_ref (GST_OBJECT_CAST (peer)); - GST_UNLOCK (pad); + gst_object_unref (GST_OBJECT (pad)); + return TRUE; +} - GST_DEBUG ("pad %s:%s: get: %d, loop: %d", - GST_DEBUG_PAD_NAME (pad), pad_get, pad_loop); +/* returns false on error or early cutout of the fold, true otherwise */ +static gboolean +iterator_fold_with_resync (GstIterator * iter, GstIteratorFoldFunction func, + GValue * ret, gpointer user_data) +{ + GstIteratorResult ires; + gboolean res = TRUE; - if (peer) { - gboolean peer_loop, peer_get; - - /* see if the peer has a getrange function */ - peer_get = GST_PAD_IS_SINK (peer) - && gst_pad_check_pull_range (GST_PAD_CAST (peer)); - /* see if the peer has a loop function */ - peer_loop = GST_PAD_LOOPFUNC (peer) != NULL; - - GST_DEBUG ("peer %s:%s: get: %d, loop: %d", - GST_DEBUG_PAD_NAME (peer), peer_get, peer_loop); - - /* If the pad is a sink with loop and the peer has a get function, - * we can activate the sinkpad, FIXME, logic is reversed as - * check_pull_range() checks the peer of the given pad. */ - if ((pad_get && pad_loop) || (peer_get && peer_loop)) { - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "activating pad %s in pull mode", GST_OBJECT_NAME (pad)); - - result &= gst_pad_set_active (pad, GST_ACTIVATE_PULL); - done = TRUE; - } - gst_object_unref (GST_OBJECT_CAST (peer)); - } + while (1) { + ires = gst_iterator_fold (iter, func, ret, user_data); - if (!done) { - /* all other conditions are just push based pads */ - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "activating pad %s in push mode", GST_OBJECT_NAME (pad)); + switch (ires) { + case GST_ITERATOR_RESYNC: + break; + case GST_ITERATOR_DONE: + res = TRUE; + goto done; + default: + res = FALSE; + goto done; + } + } - result &= gst_pad_set_active (pad, GST_ACTIVATE_PUSH); - } - } else { - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "deactivating pad %s", GST_OBJECT_NAME (pad)); +done: + return res; +} - result &= gst_pad_set_active (pad, GST_ACTIVATE_NONE); - } +/* is called with STATE_LOCK + */ +static gboolean +gst_element_pads_activate (GstElement * element, gboolean active) +{ + GValue ret = { 0, }; + GstIterator *iter; + gboolean fold_ok; + + /* no need to unset this later, it's just a boolean */ + g_value_init (&ret, G_TYPE_BOOLEAN); + g_value_set_boolean (&ret, TRUE); + + iter = gst_element_iterate_src_pads (element); + fold_ok = iterator_fold_with_resync + (iter, (GstIteratorFoldFunction) activate_pads, &ret, &active); + gst_iterator_free (iter); + if (!fold_ok || !g_value_get_boolean (&ret)) + return FALSE; - gst_object_unref (GST_OBJECT_CAST (pad)); - GST_LOCK (element); - if (cookie != element->pads_cookie) - goto restart; - } - GST_UNLOCK (element); + iter = gst_element_iterate_sink_pads (element); + fold_ok = iterator_fold_with_resync + (iter, (GstIteratorFoldFunction) activate_pads, &ret, &active); + gst_iterator_free (iter); + if (!fold_ok || !g_value_get_boolean (&ret)) + return FALSE; - return result; + return TRUE; } /* is called with STATE_LOCK */ diff --git a/gst/gstelement.h b/gst/gstelement.h index 11c6f70..0feea43 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -305,7 +305,9 @@ GstPad* gst_element_get_static_pad (GstElement *element, const gchar *name); GstPad* gst_element_get_request_pad (GstElement *element, const gchar *name); void gst_element_release_request_pad (GstElement *element, GstPad *pad); -GstIterator * gst_element_iterate_pads (GstElement * element); +GstIterator * gst_element_iterate_pads (GstElement * element); +GstIterator * gst_element_iterate_src_pads (GstElement * element); +GstIterator * gst_element_iterate_sink_pads (GstElement * element); /* event/query/format stuff */ gboolean gst_element_send_event (GstElement *element, GstEvent *event); diff --git a/gst/gstevent.c b/gst/gstevent.c index 78433a2..31dcc74 100644 --- a/gst/gstevent.c +++ b/gst/gstevent.c @@ -30,11 +30,6 @@ #include "gsttag.h" #include "gstutils.h" -#ifndef GST_DISABLE_TRACE -/* #define GST_WITH_ALLOC_TRACE */ -#include "gsttrace.h" -static GstAllocTrace *_event_trace; -#endif static void gst_event_init (GTypeInstance * instance, gpointer g_class); static void gst_event_class_init (gpointer g_class, gpointer class_data); @@ -45,10 +40,6 @@ void _gst_event_initialize (void) { gst_event_get_type (); - -#ifndef GST_DISABLE_TRACE - _event_trace = gst_alloc_trace_register (GST_EVENT_TRACE_NAME); -#endif } GType diff --git a/gst/gstghostpad.c b/gst/gstghostpad.c index cdad751..9746fd2 100644 --- a/gst/gstghostpad.c +++ b/gst/gstghostpad.c @@ -160,13 +160,51 @@ gst_proxy_pad_do_bufferalloc (GstPad * pad, guint64 offset, guint size, } static gboolean -gst_proxy_pad_do_activate (GstPad * pad, GstActivateMode mode) +gst_proxy_pad_do_activate (GstPad * pad) { GstPad *target = GST_PROXY_PAD_TARGET (pad); g_return_val_if_fail (target != NULL, FALSE); - return gst_pad_set_active (target, mode); + return target->activatefunc (pad); +} + +static gboolean +gst_proxy_pad_do_activatepull (GstPad * pad, gboolean active) +{ + GstActivateMode old; + GstPad *target = GST_PROXY_PAD_TARGET (pad); + + g_return_val_if_fail (target != NULL, FALSE); + + GST_LOCK (target); + old = GST_PAD_ACTIVATE_MODE (target); + GST_UNLOCK (target); + + if ((active && old == GST_ACTIVATE_PULL) + || (!active && old == GST_ACTIVATE_NONE)) + return TRUE; + else + return gst_pad_activate_pull (target, active); +} + +static gboolean +gst_proxy_pad_do_activatepush (GstPad * pad, gboolean active) +{ + GstActivateMode old; + GstPad *target = GST_PROXY_PAD_TARGET (pad); + + g_return_val_if_fail (target != NULL, FALSE); + + GST_LOCK (target); + old = GST_PAD_ACTIVATE_MODE (target); + GST_UNLOCK (target); + + if ((active && old == GST_ACTIVATE_PUSH) + || (!active && old == GST_ACTIVATE_NONE)) + return TRUE; + else + return gst_pad_activate_push (target, active); } static void @@ -275,6 +313,8 @@ gst_proxy_pad_set_property (GObject * object, guint prop_id, SETFUNC (queryfunc, query); SETFUNC (intlinkfunc, internal_link); SETFUNC (activatefunc, activate); + SETFUNC (activatepullfunc, activatepull); + SETFUNC (activatepushfunc, activatepush); SETFUNC (loopfunc, loop); SETFUNC (getcapsfunc, getcaps); SETFUNC (acceptcapsfunc, acceptcaps); @@ -437,6 +477,25 @@ gst_ghost_pad_class_init (GstGhostPadClass * klass) "The ghost pad's internal pad", GST_TYPE_PAD, G_PARAM_READWRITE)); } +/* will only be called for src pads (afaict) */ +static gboolean +gst_ghost_proxy_pad_do_activate_pull (GstPad * pad, gboolean active) +{ + GstObject *parent; + gboolean ret = FALSE; + + parent = gst_object_get_parent (GST_OBJECT (pad)); + if (parent) { + /* hacky hacky!!! */ + if (GST_IS_GHOST_PAD (parent)) + ret = gst_pad_activate_pull (GST_PAD (parent), active); + + gst_object_unref (parent); + } + + return ret; +} + static GstPadLinkReturn gst_ghost_pad_do_link (GstPad * pad, GstPad * peer) { @@ -474,7 +533,7 @@ gst_ghost_pad_do_unlink (GstPad * pad) if (target->unlinkfunc) target->unlinkfunc (target); - /* doesn't work with the object locks in the properties dispatcher... */ + /* FIXME: should do this here, but locks in deep_notify prevent it */ /* g_object_set (pad, "internal", NULL, NULL); */ } @@ -509,6 +568,8 @@ gst_ghost_pad_set_property (GObject * object, guint prop_id, if (pad->internal) { GstPad *intpeer; + gst_pad_set_activatepull_function (pad->internal, NULL); + g_signal_handler_disconnect (pad->internal, pad->notify_id); intpeer = gst_pad_get_peer (pad->internal); @@ -521,11 +582,6 @@ gst_ghost_pad_set_property (GObject * object, guint prop_id, gst_object_unref (GST_OBJECT (intpeer)); } - /* delete me, only here for testing... */ - if (GST_OBJECT_REFCOUNT_VALUE (pad->internal) != 1) { - gst_critical ("Refcounting problem: %" GST_PTR_FORMAT, pad->internal); - } - /* should dispose it */ gst_object_unparent (GST_OBJECT_CAST (pad->internal)); } @@ -546,6 +602,8 @@ gst_ghost_pad_set_property (GObject * object, guint prop_id, pad->notify_id = g_signal_connect (internal, "notify::caps", G_CALLBACK (on_int_notify), pad); on_int_notify (internal, NULL, pad); + gst_pad_set_activatepull_function (internal, + gst_ghost_proxy_pad_do_activate_pull); /* a ref was taken by set_parent */ } diff --git a/gst/gstmessage.c b/gst/gstmessage.c index 95cf52a..fd43540 100644 --- a/gst/gstmessage.c +++ b/gst/gstmessage.c @@ -29,17 +29,13 @@ #include "gsttag.h" #include "gstutils.h" -#ifndef GST_DISABLE_TRACE -/* #define GST_WITH_ALLOC_TRACE */ -#include "gsttrace.h" -static GstAllocTrace *_message_trace; -#endif static void gst_message_init (GTypeInstance * instance, gpointer g_class); static void gst_message_class_init (gpointer g_class, gpointer class_data); static void gst_message_finalize (GstMessage * message); static GstMessage *_gst_message_copy (GstMessage * message); + void _gst_message_initialize (void) { @@ -54,10 +50,6 @@ _gst_message_initialize (void) * see http://bugzilla.gnome.org/show_bug.cgi?id=304551 */ ptr = g_type_class_ref (GST_TYPE_MESSAGE); g_type_class_unref (ptr); - -#ifndef GST_DISABLE_TRACE - _message_trace = gst_alloc_trace_register (GST_MESSAGE_TRACE_NAME); -#endif } GType diff --git a/gst/gstminiobject.c b/gst/gstminiobject.c index cdb9e75..e3c7fcf 100644 --- a/gst/gstminiobject.c +++ b/gst/gstminiobject.c @@ -23,6 +23,10 @@ #include "config.h" #endif +#ifndef GST_DISABLE_TRACE +#include "gsttrace.h" +#endif + #include "gst/gstminiobject.h" #include "gst/gstinfo.h" #include "gst/gst_private.h" @@ -130,6 +134,21 @@ gst_mini_object_new (GType type) mini_object = (GstMiniObject *) g_type_create_instance (type); +#ifndef GST_DISABLE_TRACE + { + const gchar *name; + GstAllocTrace *trace; + + name = g_type_name (type); + + trace = gst_alloc_trace_get (name); + if (!trace) { + trace = gst_alloc_trace_register (name); + } + gst_alloc_trace_new (trace, mini_object); + } +#endif + return mini_object; } @@ -151,12 +170,18 @@ gst_mini_object_is_writable (const GstMiniObject * mini_object) } GstMiniObject * -gst_mini_object_make_writable (const GstMiniObject * mini_object) +gst_mini_object_make_writable (GstMiniObject * mini_object) { + GstMiniObject *ret; + if (gst_mini_object_is_writable (mini_object)) { - return (GstMiniObject *) mini_object; + ret = (GstMiniObject *) mini_object; + } else { + ret = gst_mini_object_copy (mini_object); + gst_mini_object_unref ((GstMiniObject *) mini_object); } - return gst_mini_object_copy (mini_object); + + return ret; } GstMiniObject * @@ -180,8 +205,24 @@ gst_mini_object_free (GstMiniObject * mini_object) /* if the refcount is still 0 we can really free the * object, else the finalize method recycled the object */ - if (g_atomic_int_get (&mini_object->refcount) == 0) + if (g_atomic_int_get (&mini_object->refcount) == 0) { +#ifndef GST_DISABLE_TRACE + { + const gchar *name; + GstAllocTrace *trace; + + name = g_type_name (G_TYPE_FROM_CLASS (mo_class)); + + trace = gst_alloc_trace_get (name); + if (G_LIKELY (trace)) { + gst_alloc_trace_free (trace, mini_object); + } else { + g_warning ("Untraced miniobject: (%s)%p", name, mini_object); + } + } +#endif g_type_free_instance ((GTypeInstance *) mini_object); + } } void diff --git a/gst/gstminiobject.h b/gst/gstminiobject.h index 7e38a0f..45cea98 100644 --- a/gst/gstminiobject.h +++ b/gst/gstminiobject.h @@ -81,7 +81,7 @@ GType gst_mini_object_get_type (void); GstMiniObject * gst_mini_object_new (GType type); GstMiniObject * gst_mini_object_copy (const GstMiniObject *mini_object); gboolean gst_mini_object_is_writable (const GstMiniObject *mini_object); -GstMiniObject * gst_mini_object_make_writable (const GstMiniObject *mini_object); +GstMiniObject * gst_mini_object_make_writable (GstMiniObject *mini_object); GstMiniObject * gst_mini_object_ref (GstMiniObject *mini_object); void gst_mini_object_unref (GstMiniObject *mini_object); diff --git a/gst/gstpad.c b/gst/gstpad.c index eb93418..8313761 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -90,6 +90,7 @@ static void gst_pad_get_property (GObject * object, guint prop_id, static GstCaps *gst_pad_get_caps_unlocked (GstPad * pad); static void gst_pad_set_pad_template (GstPad * pad, GstPadTemplate * templ); +static gboolean gst_pad_activate_default (GstPad * pad); #ifndef GST_DISABLE_LOADSAVE static xmlNodePtr gst_pad_save_thyself (GstObject * object, xmlNodePtr parent); @@ -181,6 +182,7 @@ gst_pad_init (GstPad * pad) pad->linkfunc = NULL; pad->getcapsfunc = NULL; + pad->activatefunc = gst_pad_activate_default; pad->eventfunc = gst_pad_event_default; pad->querytypefunc = gst_pad_get_query_types_default; pad->queryfunc = gst_pad_query_default; @@ -394,172 +396,265 @@ gst_pad_get_direction (GstPad * pad) return result; } +static gboolean +gst_pad_activate_default (GstPad * pad) +{ + return gst_pad_activate_push (pad, TRUE); +} + +static void +pre_activate_switch (GstPad * pad, gboolean new_active) +{ + if (new_active) { + return; + } else { + GST_LOCK (pad); + GST_PAD_SET_FLUSHING (pad); + /* unlock blocked pads so element can resume and stop */ + GST_PAD_BLOCK_SIGNAL (pad); + GST_UNLOCK (pad); + } +} + +static void +post_activate_switch (GstPad * pad, gboolean new_active) +{ + if (new_active) { + GST_LOCK (pad); + GST_PAD_UNSET_FLUSHING (pad); + GST_UNLOCK (pad); + } else { + /* make streaming stop */ + GST_STREAM_LOCK (pad); + GST_STREAM_UNLOCK (pad); + } +} + /** * gst_pad_set_active: * @pad: the #GstPad to activate or deactivate. - * @mode: the mode of the pad. + * @active: whether or not the pad should be active. * - * Activates or deactivates the given pad in the given mode. + * Activates or deactivates the given pad. Must be called with the STATE_LOCK. + * Normally called from within core state change functions. * - * For a source pad: PULL mode will call the getrange function, - * PUSH mode will require the element to call _push() on the pad. + * If @active, makes sure the pad is active. If it is already active, either in + * push or pull mode, just return. Otherwise dispatches to the pad's activate + * function to perform the actual activation. * - * For a sink pad: PULL mode will require the element to call - * the _pull_range() function, PUSH mode will call the chain function. + * If not @active, checks the pad's current mode and calls + * gst_pad_activate_push() or gst_pad_activate_pull(), as appropriate, with a + * FALSE argument. * * Returns: TRUE if the operation was successfull. * - * MT safe. + * MT safe. Must be called with STATE_LOCK. */ gboolean -gst_pad_set_active (GstPad * pad, GstActivateMode mode) +gst_pad_set_active (GstPad * pad, gboolean active) { GstActivateMode old; - GstPadActivateFunction activatefunc; - gboolean active, oldactive; + gboolean ret; g_return_val_if_fail (GST_IS_PAD (pad), FALSE); GST_LOCK (pad); - - active = GST_PAD_MODE_ACTIVATE (mode); old = GST_PAD_ACTIVATE_MODE (pad); - oldactive = GST_PAD_MODE_ACTIVATE (old); + GST_UNLOCK (pad); - /* if nothing changed, we can just exit */ - if (G_UNLIKELY (oldactive == active && old == mode)) - goto was_ok; + if (active) { + switch (old) { + case GST_ACTIVATE_PUSH: + case GST_ACTIVATE_PULL: + ret = TRUE; + break; + case GST_ACTIVATE_NONE: + ret = (GST_PAD_ACTIVATEFUNC (pad)) (pad); + break; + } + } else { + switch (old) { + case GST_ACTIVATE_PUSH: + ret = gst_pad_activate_push (pad, FALSE); + break; + case GST_ACTIVATE_PULL: + ret = gst_pad_activate_pull (pad, FALSE); + break; + case GST_ACTIVATE_NONE: + ret = TRUE; + break; + } + } - /* FIXME, no mode switching yet, need more design docs first */ -#if 0 - if (G_UNLIKELY (old == mode)) + return ret; +} + +/** + * gst_pad_activate_pull: + * @pad: the #GstPad to activate or deactivate. + * @active: whether or not the pad should be active. + * + * Activates or deactivates the given pad in pull mode via dispatching to the + * pad's activatepullfunc. For use from within pad activation functions only. + * When called on sink pads, will first proxy the call to the peer pad, which is + * expected to activate its internally linked pads from within its activate_pull + * function. + * + * If you don't know what this is, you probably don't want to call it. + * + * Returns: TRUE if the operation was successfull. + * + * MT safe. + */ +gboolean +gst_pad_activate_pull (GstPad * pad, gboolean active) +{ + GstActivateMode old; + + g_return_val_if_fail (GST_IS_PAD (pad), FALSE); + + GST_LOCK (pad); + old = GST_PAD_ACTIVATE_MODE (pad); + GST_UNLOCK (pad); + + if ((active && old == GST_ACTIVATE_PULL) + || (!active && old == GST_ACTIVATE_NONE)) goto was_ok; -#endif - /* make sure data is disallowed when going inactive or changing - * mode - */ - if (!active || oldactive) { - GST_CAT_DEBUG (GST_CAT_PADS, "de-activating pad %s:%s", - GST_DEBUG_PAD_NAME (pad)); - GST_PAD_SET_FLUSHING (pad); - /* unlock blocked pads so element can resume and stop */ - GST_PAD_BLOCK_SIGNAL (pad); + if (active) { + g_return_val_if_fail (old == GST_ACTIVATE_NONE, FALSE); + } else { + g_return_val_if_fail (old == GST_ACTIVATE_PULL, FALSE); } - if (active) { - if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) { - if (mode == GST_ACTIVATE_PULL) { - if (!pad->getrangefunc) - goto wrong_mode; - } else { - /* we can push if driven by a chain or loop on the sink pad. - * peer pad is assumed to be active now. */ - } - } else { - /* sink pads */ - if (mode == GST_ACTIVATE_PULL) { - /* the src can drive us with getrange */ - } else { - if (!pad->chainfunc) - goto wrong_mode; + if (gst_pad_get_direction (pad) == GST_PAD_SINK) { + GstPad *peer = gst_pad_get_peer (pad); + + if (peer) { + if (!gst_pad_activate_pull (peer, active)) { + GST_LOCK (peer); + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, + "activate_pull on peer (%s:%s) failed", GST_DEBUG_PAD_NAME (peer)); + GST_UNLOCK (peer); + gst_object_unref (GST_OBJECT (peer)); + goto failure; } } } - activatefunc = pad->activatefunc; - if (activatefunc) { - gboolean result; - - GST_CAT_DEBUG (GST_CAT_PADS, - "calling activate function on pad %s:%s with mode %d", - GST_DEBUG_PAD_NAME (pad), mode); + pre_activate_switch (pad, active); - /* unlock so element can sync */ - GST_UNLOCK (pad); - result = activatefunc (pad, mode); - /* and lock again */ - GST_LOCK (pad); - if (result == FALSE) - goto activate_error; - } - /* store the mode */ - GST_PAD_ACTIVATE_MODE (pad) = mode; - - /* when going to active allow data passing now */ - if (active) { - GST_CAT_DEBUG (GST_CAT_PADS, "activating pad %s:%s in mode %d", - GST_DEBUG_PAD_NAME (pad), mode); - GST_PAD_UNSET_FLUSHING (pad); - GST_UNLOCK (pad); + if (GST_PAD_ACTIVATEPULLFUNC (pad)) { + if (GST_PAD_ACTIVATEPULLFUNC (pad) (pad, active)) { + goto success; + } else { + goto failure; + } } else { - GST_UNLOCK (pad); - - /* and make streaming finish */ - GST_STREAM_LOCK (pad); - GST_STREAM_UNLOCK (pad); + /* can happen for sinks of passthrough elements */ + goto success; } - return TRUE; was_ok: { - GST_CAT_DEBUG (GST_CAT_PADS, - "pad %s:%s was active, old %d, new %d", - GST_DEBUG_PAD_NAME (pad), old, mode); - GST_UNLOCK (pad); + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "already %s in pull mode", + active ? "activated" : "deactivated"); return TRUE; } - /* errors */ -wrong_mode: + +success: { - GST_CAT_DEBUG (GST_CAT_PADS, - "pad %s:%s lacks functions to be active in mode %d", - GST_DEBUG_PAD_NAME (pad), mode); + GST_LOCK (pad); + GST_PAD_ACTIVATE_MODE (pad) = + active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE; GST_UNLOCK (pad); - return FALSE; + post_activate_switch (pad, active); + + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "%s in pull mode", + active ? "activated" : "deactivated"); + return TRUE; } -activate_error: + +failure: { - GST_CAT_DEBUG (GST_CAT_PADS, - "activate function returned FALSE for pad %s:%s", - GST_DEBUG_PAD_NAME (pad)); - GST_UNLOCK (pad); + GST_CAT_INFO_OBJECT (GST_CAT_PADS, pad, "failed to %s in pull mode", + active ? "activate" : "deactivate"); return FALSE; } } /** - * gst_pad_peer_set_active: - * @pad: the #GstPad to activate or deactivate the peer of. - * @mode: the mode of the pad. + * gst_pad_activate_push: + * @pad: the #GstPad to activate or deactivate. + * @active: whether or not the pad should be active. + * + * Activates or deactivates the given pad in push mode via dispatching to the + * pad's activatepushfunc. For use from within pad activation functions only. * - * Activates or deactivates the given peer of a pad. Elements - * that will perform a _pull_range() on their sinkpads need - * to call this function when the sinkpad is activated or when - * an internally linked source pad is activated in pull mode. + * If you don't know what this is, you probably don't want to call it. * * Returns: TRUE if the operation was successfull. * * MT safe. */ gboolean -gst_pad_peer_set_active (GstPad * pad, GstActivateMode mode) +gst_pad_activate_push (GstPad * pad, gboolean active) { - GstPad *peer; - gboolean result = FALSE; + GstActivateMode old; - peer = gst_pad_get_peer (pad); - if (!peer) - goto no_peer; + g_return_val_if_fail (GST_IS_PAD (pad), FALSE); - result = gst_pad_set_active (peer, mode); - gst_object_unref (GST_OBJECT_CAST (peer)); + GST_LOCK (pad); + old = GST_PAD_ACTIVATE_MODE (pad); + GST_UNLOCK (pad); - return result; + if ((active && old == GST_ACTIVATE_PUSH) + || (!active && old == GST_ACTIVATE_NONE)) + goto was_ok; - /* errors */ -no_peer: + if (active) { + g_return_val_if_fail (old == GST_ACTIVATE_NONE, FALSE); + } else { + g_return_val_if_fail (old == GST_ACTIVATE_PUSH, FALSE); + } + + pre_activate_switch (pad, active); + + if (GST_PAD_ACTIVATEPUSHFUNC (pad)) { + if (GST_PAD_ACTIVATEPUSHFUNC (pad) (pad, active)) { + goto success; + } else { + goto failure; + } + } else { + /* quite ok, element relies on state change func to prepare itself */ + goto success; + } + +was_ok: + { + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "already %s in push mode", + active ? "activated" : "deactivated"); + return TRUE; + } + +success: + { + GST_LOCK (pad); + GST_PAD_ACTIVATE_MODE (pad) = + active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE; + GST_UNLOCK (pad); + post_activate_switch (pad, active); + + GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "%s in push mode", + active ? "activated" : "deactivated"); + return TRUE; + } + +failure: { + GST_CAT_INFO_OBJECT (GST_CAT_PADS, pad, "failed to %s in push mode", + active ? "activate" : "deactivate"); return FALSE; } } @@ -721,8 +816,11 @@ gst_pad_is_blocked (GstPad * pad) * @pad: a sink #GstPad. * @chain: the #GstPadActivateFunction to set. * - * Sets the given activate function for the pad. The activate function is called to - * start or stop dataflow on a pad. + * Sets the given activate function for the pad. The activate function will + * dispatch to activate_push or activate_pull to perform the actual activation. + * Only makes sense to set on sink pads. + * + * Call this function if your sink pad can start a pull-based task. */ void gst_pad_set_activate_function (GstPad * pad, GstPadActivateFunction activate) @@ -735,6 +833,45 @@ gst_pad_set_activate_function (GstPad * pad, GstPadActivateFunction activate) } /** + * gst_pad_set_activatepull_function: + * @pad: a sink #GstPad. + * @chain: the #GstPadActivateModeFunction to set. + * + * Sets the given activate_pull function for the pad. An activate_pull function + * prepares the element and any upstream connections for pulling. See XXX + * part-activation.txt for details. + */ +void +gst_pad_set_activatepull_function (GstPad * pad, + GstPadActivateModeFunction activatepull) +{ + g_return_if_fail (GST_IS_PAD (pad)); + + GST_PAD_ACTIVATEPULLFUNC (pad) = activatepull; + GST_CAT_DEBUG (GST_CAT_PADS, "activatepullfunc for %s:%s set to %s", + GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (activatepull)); +} + +/** + * gst_pad_set_activatepush_function: + * @pad: a sink #GstPad. + * @chain: the #GstPadActivateModeFunction to set. + * + * Sets the given activate_push function for the pad. An activate_push function + * prepares the element for pushing. See XXX part-activation.txt for details. + */ +void +gst_pad_set_activatepush_function (GstPad * pad, + GstPadActivateModeFunction activatepush) +{ + g_return_if_fail (GST_IS_PAD (pad)); + + GST_PAD_ACTIVATEPUSHFUNC (pad) = activatepush; + GST_CAT_DEBUG (GST_CAT_PADS, "activatepushfunc for %s:%s set to %s", + GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (activatepush)); +} + +/** * gst_pad_set_loop_function: * @pad: a sink #GstPad. * @chain: the #GstPadLoopFunction to set. diff --git a/gst/gstpad.h b/gst/gstpad.h index c77910b..908adc1 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -91,7 +91,8 @@ typedef enum { #define GST_PAD_MODE_ACTIVATE(mode) ((mode) != GST_ACTIVATE_NONE) /* pad states */ -typedef gboolean (*GstPadActivateFunction) (GstPad *pad, GstActivateMode mode); +typedef gboolean (*GstPadActivateFunction) (GstPad *pad); +typedef gboolean (*GstPadActivateModeFunction) (GstPad *pad, gboolean active); /* data passing */ typedef GstFlowReturn (*GstPadChainFunction) (GstPad *pad, GstBuffer *buffer); @@ -173,6 +174,8 @@ struct _GstPad { GstPadFixateCapsFunction fixatecapsfunc; GstPadActivateFunction activatefunc; + GstPadActivateModeFunction activatepushfunc; + GstPadActivateModeFunction activatepullfunc; /* pad link */ GstPadLinkFunction linkfunc; @@ -229,6 +232,8 @@ struct _GstPadClass { #define GST_PAD_ACTIVATE_MODE(pad) (GST_PAD_CAST(pad)->mode) #define GST_PAD_ACTIVATEFUNC(pad) (GST_PAD_CAST(pad)->activatefunc) +#define GST_PAD_ACTIVATEPUSHFUNC(pad) (GST_PAD_CAST(pad)->activatepushfunc) +#define GST_PAD_ACTIVATEPULLFUNC(pad) (GST_PAD_CAST(pad)->activatepullfunc) #define GST_PAD_LOOPFUNC(pad) (GST_PAD_CAST(pad)->loopfunc) #define GST_PAD_CHAINFUNC(pad) (GST_PAD_CAST(pad)->chainfunc) #define GST_PAD_CHECKGETRANGEFUNC(pad) (GST_PAD_CAST(pad)->checkgetrangefunc) @@ -358,9 +363,11 @@ GstElement* gst_pad_get_parent (GstPad *pad); GstPadDirection gst_pad_get_direction (GstPad *pad); -gboolean gst_pad_set_active (GstPad *pad, GstActivateMode mode); -gboolean gst_pad_peer_set_active (GstPad *pad, GstActivateMode mode); +gboolean gst_pad_set_active (GstPad *pad, gboolean active); gboolean gst_pad_is_active (GstPad *pad); +gboolean gst_pad_activate_pull (GstPad *pad, gboolean active); +gboolean gst_pad_activate_push (GstPad *pad, gboolean active); + gboolean gst_pad_set_blocked (GstPad *pad, gboolean blocked); gboolean gst_pad_set_blocked_async (GstPad *pad, gboolean blocked, GstPadBlockCallback callback, gpointer user_data); @@ -377,6 +384,8 @@ GstFlowReturn gst_pad_alloc_buffer (GstPad *pad, guint64 offset, gint size, /* data passing setup functions */ void gst_pad_set_activate_function (GstPad *pad, GstPadActivateFunction activate); +void gst_pad_set_activatepull_function (GstPad *pad, GstPadActivateModeFunction activatepull); +void gst_pad_set_activatepush_function (GstPad *pad, GstPadActivateModeFunction activatepush); void gst_pad_set_loop_function (GstPad *pad, GstPadLoopFunction loop); void gst_pad_set_chain_function (GstPad *pad, GstPadChainFunction chain); void gst_pad_set_getrange_function (GstPad *pad, GstPadGetRangeFunction get); diff --git a/gst/gstpipeline.c b/gst/gstpipeline.c index 30c9600..89d3904 100644 --- a/gst/gstpipeline.c +++ b/gst/gstpipeline.c @@ -125,7 +125,7 @@ gst_pipeline_class_init (gpointer g_class, gpointer class_data) G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PLAY_TIMEOUT, g_param_spec_uint64 ("play-timeout", "Play Timeout", - "Max timeout for going " "to PLAYING in nanoseconds", 0, G_MAXUINT64, + "Max timeout for going to PLAYING in nanoseconds", 0, G_MAXUINT64, DEFAULT_PLAY_TIMEOUT, G_PARAM_READWRITE)); gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_pipeline_dispose); @@ -153,19 +153,24 @@ gst_pipeline_init (GTypeInstance * instance, gpointer g_class) g_error ("Critical error: could not get scheduler \"%s\"\n" "Are you sure you have a registry ?\n" "Run gst-register as root if you haven't done so yet.", name); + } else { + gst_element_set_scheduler (GST_ELEMENT (pipeline), scheduler); + /* set_scheduler refs the bus via gst_object_replace, we drop our ref */ + gst_object_unref ((GstObject *) scheduler); } - bus = g_object_new (gst_bus_get_type (), NULL); - gst_bus_set_sync_handler (bus, - (GstBusSyncHandler) pipeline_bus_handler, pipeline); + pipeline->eosed = NULL; pipeline->delay = DEFAULT_DELAY; pipeline->play_timeout = DEFAULT_PLAY_TIMEOUT; /* we are our own manager */ GST_ELEMENT_MANAGER (pipeline) = pipeline; + + bus = g_object_new (gst_bus_get_type (), NULL); + gst_bus_set_sync_handler (bus, + (GstBusSyncHandler) pipeline_bus_handler, pipeline); gst_element_set_bus (GST_ELEMENT (pipeline), bus); /* set_bus refs the bus via gst_object_replace, we drop our ref */ gst_object_unref ((GstObject *) bus); - gst_element_set_scheduler (GST_ELEMENT (pipeline), scheduler); } static void @@ -175,6 +180,7 @@ gst_pipeline_dispose (GObject * object) gst_element_set_bus (GST_ELEMENT (pipeline), NULL); gst_scheduler_reset (GST_ELEMENT_SCHEDULER (object)); + gst_element_set_scheduler (GST_ELEMENT (pipeline), NULL); gst_object_replace ((GstObject **) & pipeline->fixed_clock, NULL); G_OBJECT_CLASS (parent_class)->dispose (object); diff --git a/gst/gstqueue.c b/gst/gstqueue.c index 43645c5..dd17a3d 100644 --- a/gst/gstqueue.c +++ b/gst/gstqueue.c @@ -140,8 +140,8 @@ static GstPadLinkReturn gst_queue_link_sink (GstPad * pad, GstPad * peer); static GstPadLinkReturn gst_queue_link_src (GstPad * pad, GstPad * peer); static void gst_queue_locked_flush (GstQueue * queue); -static gboolean gst_queue_src_activate (GstPad * pad, GstActivateMode mode); -static gboolean gst_queue_sink_activate (GstPad * pad, GstActivateMode mode); +static gboolean gst_queue_src_activate_push (GstPad * pad, gboolean active); +static gboolean gst_queue_sink_activate_push (GstPad * pad, gboolean active); static GstElementStateReturn gst_queue_change_state (GstElement * element); @@ -300,8 +300,8 @@ gst_queue_init (GstQueue * queue) "sink"); gst_pad_set_chain_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_chain)); - gst_pad_set_activate_function (queue->sinkpad, - GST_DEBUG_FUNCPTR (gst_queue_sink_activate)); + gst_pad_set_activatepush_function (queue->sinkpad, + GST_DEBUG_FUNCPTR (gst_queue_sink_activate_push)); gst_pad_set_event_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_handle_sink_event)); gst_pad_set_link_function (queue->sinkpad, @@ -316,8 +316,8 @@ gst_queue_init (GstQueue * queue) gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate), "src"); gst_pad_set_loop_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_loop)); - gst_pad_set_activate_function (queue->srcpad, - GST_DEBUG_FUNCPTR (gst_queue_src_activate)); + gst_pad_set_activatepush_function (queue->srcpad, + GST_DEBUG_FUNCPTR (gst_queue_src_activate_push)); gst_pad_set_link_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_link_src)); gst_pad_set_getcaps_function (queue->srcpad, @@ -819,65 +819,55 @@ gst_queue_handle_src_query (GstPad * pad, GstQuery * query) } static gboolean -gst_queue_sink_activate (GstPad * pad, GstActivateMode mode) +gst_queue_sink_activate_push (GstPad * pad, gboolean active) { gboolean result = FALSE; GstQueue *queue; queue = GST_QUEUE (GST_OBJECT_PARENT (pad)); - switch (mode) { - case GST_ACTIVATE_PUSH: - queue->flushing = FALSE; - result = TRUE; - break; - case GST_ACTIVATE_PULL: - result = FALSE; - break; - case GST_ACTIVATE_NONE: - /* step 1, unblock chain and loop functions */ - GST_QUEUE_MUTEX_LOCK; - queue->flushing = TRUE; - gst_queue_locked_flush (queue); - g_cond_signal (queue->item_del); - GST_QUEUE_MUTEX_UNLOCK; + if (active) { + queue->flushing = FALSE; + result = TRUE; + } else { + /* step 1, unblock chain and loop functions */ + GST_QUEUE_MUTEX_LOCK; + queue->flushing = TRUE; + gst_queue_locked_flush (queue); + g_cond_signal (queue->item_del); + GST_QUEUE_MUTEX_UNLOCK; - /* step 2, make sure streaming finishes */ - result = gst_pad_stop_task (pad); - break; + /* step 2, make sure streaming finishes */ + result = gst_pad_stop_task (pad); } + return result; } static gboolean -gst_queue_src_activate (GstPad * pad, GstActivateMode mode) +gst_queue_src_activate_push (GstPad * pad, gboolean active) { gboolean result = FALSE; GstQueue *queue; queue = GST_QUEUE (GST_OBJECT_PARENT (pad)); - switch (mode) { - case GST_ACTIVATE_PUSH: - GST_QUEUE_MUTEX_LOCK; - queue->flushing = FALSE; - result = gst_pad_start_task (pad, (GstTaskFunction) gst_queue_loop, pad); - GST_QUEUE_MUTEX_UNLOCK; - break; - case GST_ACTIVATE_PULL: - result = FALSE; - break; - case GST_ACTIVATE_NONE: - /* step 1, unblock chain and loop functions */ - GST_QUEUE_MUTEX_LOCK; - queue->flushing = TRUE; - g_cond_signal (queue->item_add); - GST_QUEUE_MUTEX_UNLOCK; + if (active) { + GST_QUEUE_MUTEX_LOCK; + queue->flushing = FALSE; + result = gst_pad_start_task (pad, (GstTaskFunction) gst_queue_loop, pad); + GST_QUEUE_MUTEX_UNLOCK; + } else { + /* step 1, unblock chain and loop functions */ + GST_QUEUE_MUTEX_LOCK; + queue->flushing = TRUE; + g_cond_signal (queue->item_add); + GST_QUEUE_MUTEX_UNLOCK; - /* step 2, make sure streaming finishes */ - result = gst_pad_stop_task (pad); - break; + /* step 2, make sure streaming finishes */ + result = gst_pad_stop_task (pad); } + return result; } diff --git a/gst/gsttrace.c b/gst/gsttrace.c index 15e64ef..794e4bb 100644 --- a/gst/gsttrace.c +++ b/gst/gsttrace.c @@ -254,15 +254,34 @@ gst_alloc_trace_live_all (void) return num; } +static gint +compare_func (GstAllocTrace * a, GstAllocTrace * b) +{ + return strcmp (a->name, b->name); +} + +static GList * +gst_alloc_trace_list_sorted (void) +{ + GList *ret; + + ret = g_list_sort (g_list_copy (_gst_alloc_tracers), + (GCompareFunc) compare_func); + + return ret; +} + /** * gst_alloc_trace_print_all: * - * Print the status of all registered alloc trace objectes. + * Print the status of all registered alloc trace objects. */ void gst_alloc_trace_print_all (void) { - GList *walk = _gst_alloc_tracers; + GList *orig, *walk; + + orig = walk = gst_alloc_trace_list_sorted (); while (walk) { GstAllocTrace *trace = (GstAllocTrace *) walk->data; @@ -271,6 +290,33 @@ gst_alloc_trace_print_all (void) walk = g_list_next (walk); } + + g_list_free (orig); +} + +/** + * gst_alloc_trace_print_live: + * + * Print the status of all registered alloc trace objects, ignoring those + * without live objects. + */ +void +gst_alloc_trace_print_live (void) +{ + GList *orig, *walk; + + orig = walk = gst_alloc_trace_list_sorted (); + + while (walk) { + GstAllocTrace *trace = (GstAllocTrace *) walk->data; + + if (trace->live) + gst_alloc_trace_print (trace); + + walk = g_list_next (walk); + } + + g_list_free (orig); } /** @@ -336,27 +382,20 @@ gst_alloc_trace_print (const GstAllocTrace * trace) g_return_if_fail (trace != NULL); - g_print ("%s (%p): flags %d", trace->name, trace, trace->flags); - if (trace->flags & GST_ALLOC_TRACE_LIVE) { - g_print (", live %d", trace->live); + g_print ("%-22.22s : %d\n", trace->name, trace->live); + } else { + g_print ("%-22.22s : (no live count)\n", trace->name); } + if (trace->flags & GST_ALLOC_TRACE_MEM_LIVE) { mem_live = trace->mem_live; - if (!mem_live) { - g_print (", no live memory"); - } else { - g_print (", dumping live memory: "); - - while (mem_live) { - g_print ("%p ", mem_live->data); - mem_live = g_slist_next (mem_live); - } - g_print ("\ntotal %d", g_slist_length (trace->mem_live)); + while (mem_live) { + g_print ("%-22.22s : %p\n", "", mem_live->data); + mem_live = mem_live->next; } } - g_print ("\n"); } /** diff --git a/gst/gsttrace.h b/gst/gsttrace.h index 5a0cde3..c32dbbc 100644 --- a/gst/gsttrace.h +++ b/gst/gsttrace.h @@ -91,6 +91,7 @@ GstAllocTrace* _gst_alloc_trace_register (const gchar *name); int gst_alloc_trace_live_all (void); void gst_alloc_trace_print_all (void); +void gst_alloc_trace_print_live (void); void gst_alloc_trace_set_flags_all (GstAllocTraceFlags flags); GstAllocTrace* gst_alloc_trace_get (const gchar *name); diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index 4921178..081ca45 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -100,7 +100,8 @@ static GstElementStateReturn gst_basesink_change_state (GstElement * element); static GstFlowReturn gst_basesink_chain (GstPad * pad, GstBuffer * buffer); static void gst_basesink_loop (GstPad * pad); static GstFlowReturn gst_basesink_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_basesink_activate (GstPad * pad, GstActivateMode mode); +static gboolean gst_basesink_activate_push (GstPad * pad, gboolean active); +static gboolean gst_basesink_activate_pull (GstPad * pad, gboolean active); static gboolean gst_basesink_event (GstPad * pad, GstEvent * event); static inline GstFlowReturn gst_basesink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf); @@ -256,8 +257,10 @@ gst_basesink_finalize (GObject * object) static void gst_basesink_set_pad_functions (GstBaseSink * this, GstPad * pad) { - gst_pad_set_activate_function (pad, - GST_DEBUG_FUNCPTR (gst_basesink_activate)); + gst_pad_set_activatepush_function (pad, + GST_DEBUG_FUNCPTR (gst_basesink_activate_push)); + gst_pad_set_activatepull_function (pad, + GST_DEBUG_FUNCPTR (gst_basesink_activate_pull)); gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_basesink_event)); if (this->has_chain) @@ -824,51 +827,72 @@ paused: } static gboolean -gst_basesink_activate (GstPad * pad, GstActivateMode mode) +gst_basesink_deactivate (GstBaseSink * basesink, GstPad * pad) { gboolean result = FALSE; - GstBaseSink *basesink; GstBaseSinkClass *bclass; - basesink = GST_BASESINK (GST_OBJECT_PARENT (pad)); bclass = GST_BASESINK_GET_CLASS (basesink); - switch (mode) { - case GST_ACTIVATE_PUSH: - g_return_val_if_fail (basesink->has_chain, FALSE); - result = TRUE; - break; - case GST_ACTIVATE_PULL: - /* if we have a scheduler we can start the task */ - g_return_val_if_fail (basesink->has_loop, FALSE); - gst_pad_peer_set_active (pad, mode); - result = - gst_pad_start_task (pad, (GstTaskFunction) gst_basesink_loop, pad); - break; - case GST_ACTIVATE_NONE: - /* step 1, unblock clock sync (if any) or any other blocking thing */ - GST_PREROLL_LOCK (pad); - GST_LOCK (basesink); - if (basesink->clock_id) { - gst_clock_id_unschedule (basesink->clock_id); - } - GST_UNLOCK (basesink); + /* step 1, unblock clock sync (if any) or any other blocking thing */ + GST_PREROLL_LOCK (pad); + GST_LOCK (basesink); + if (basesink->clock_id) { + gst_clock_id_unschedule (basesink->clock_id); + } + GST_UNLOCK (basesink); - /* unlock any subclasses */ - if (bclass->unlock) - bclass->unlock (basesink); + /* unlock any subclasses */ + if (bclass->unlock) + bclass->unlock (basesink); - /* flush out the data thread if it's locked in finish_preroll */ - gst_basesink_preroll_queue_flush (basesink); - basesink->need_preroll = FALSE; - GST_PREROLL_SIGNAL (pad); - GST_PREROLL_UNLOCK (pad); + /* flush out the data thread if it's locked in finish_preroll */ + gst_basesink_preroll_queue_flush (basesink); + basesink->need_preroll = FALSE; + GST_PREROLL_SIGNAL (pad); + GST_PREROLL_UNLOCK (pad); - /* step 2, make sure streaming finishes */ - result = gst_pad_stop_task (pad); - break; + /* step 2, make sure streaming finishes */ + result = gst_pad_stop_task (pad); + + return result; +} + +static gboolean +gst_basesink_activate_push (GstPad * pad, gboolean active) +{ + gboolean result = FALSE; + GstBaseSink *basesink; + + basesink = GST_BASESINK (GST_OBJECT_PARENT (pad)); + + if (active) { + g_return_val_if_fail (basesink->has_chain, FALSE); + result = TRUE; + } else { + result = gst_basesink_deactivate (basesink, pad); + } + basesink->pad_mode = GST_ACTIVATE_PUSH; + + return result; +} + +/* this won't get called until we implement an activate function */ +static gboolean +gst_basesink_activate_pull (GstPad * pad, gboolean active) +{ + gboolean result = FALSE; + GstBaseSink *basesink; + + basesink = GST_BASESINK (GST_OBJECT_PARENT (pad)); + + if (active) { + /* if we have a scheduler we can start the task */ + g_return_val_if_fail (basesink->has_loop, FALSE); + result = gst_pad_start_task (pad, (GstTaskFunction) gst_basesink_loop, pad); + } else { + result = gst_basesink_deactivate (basesink, pad); } - basesink->pad_mode = mode; return result; } diff --git a/libs/gst/base/gstbasesrc.c b/libs/gst/base/gstbasesrc.c index 6600ade..4c3cb8d 100644 --- a/libs/gst/base/gstbasesrc.c +++ b/libs/gst/base/gstbasesrc.c @@ -82,7 +82,8 @@ gst_basesrc_get_type (void) return basesrc_type; } -static gboolean gst_basesrc_activate (GstPad * pad, GstActivateMode mode); +static gboolean gst_basesrc_activate_push (GstPad * pad, gboolean active); +static gboolean gst_basesrc_activate_pull (GstPad * pad, gboolean active); static void gst_basesrc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_basesrc_get_property (GObject * object, guint prop_id, @@ -158,7 +159,8 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class) pad = gst_pad_new_from_template (pad_template, "src"); - gst_pad_set_activate_function (pad, gst_basesrc_activate); + gst_pad_set_activatepush_function (pad, gst_basesrc_activate_push); + gst_pad_set_activatepull_function (pad, gst_basesrc_activate_pull); gst_pad_set_event_function (pad, gst_basesrc_event_handler); gst_pad_set_query_function (pad, gst_basesrc_query); @@ -729,54 +731,70 @@ gst_basesrc_stop (GstBaseSrc * basesrc) } static gboolean -gst_basesrc_activate (GstPad * pad, GstActivateMode mode) +gst_basesrc_deactivate (GstBaseSrc * basesrc, GstPad * pad) { gboolean result; + + GST_LIVE_LOCK (basesrc); + basesrc->live_running = TRUE; + GST_LIVE_SIGNAL (basesrc); + GST_LIVE_UNLOCK (basesrc); + + /* step 1, unblock clock sync (if any) */ + gst_basesrc_unlock (basesrc); + + /* step 2, make sure streaming finishes */ + result = gst_pad_stop_task (pad); + + return result; +} + +static gboolean +gst_basesrc_activate_push (GstPad * pad, gboolean active) +{ GstBaseSrc *basesrc; basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad)); /* prepare subclass first */ - switch (mode) { - case GST_ACTIVATE_PUSH: - case GST_ACTIVATE_PULL: - result = gst_basesrc_start (basesrc); - break; - default: - result = TRUE; - break; + if (active) { + if (!gst_basesrc_start (basesrc)) + goto error_start; + + return gst_pad_start_task (pad, (GstTaskFunction) gst_basesrc_loop, pad); + } else { + return gst_basesrc_deactivate (basesrc, pad); } - /* if that failed we can stop here */ - if (!result) - goto error_start; - result = FALSE; - switch (mode) { - case GST_ACTIVATE_PUSH: - result = - gst_pad_start_task (pad, (GstTaskFunction) gst_basesrc_loop, pad); - break; - case GST_ACTIVATE_PULL: - result = basesrc->seekable; - if (!result) - gst_basesrc_stop (basesrc); - break; - case GST_ACTIVATE_NONE: - GST_LIVE_LOCK (basesrc); - basesrc->live_running = TRUE; - GST_LIVE_SIGNAL (basesrc); - GST_LIVE_UNLOCK (basesrc); +error_start: + { + GST_DEBUG_OBJECT (basesrc, "failed to start"); + return FALSE; + } +} - /* step 1, unblock clock sync (if any) */ - gst_basesrc_unlock (basesrc); +static gboolean +gst_basesrc_activate_pull (GstPad * pad, gboolean active) +{ + GstBaseSrc *basesrc; - /* step 2, make sure streaming finishes */ - result = gst_pad_stop_task (pad); - break; + basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad)); + + /* prepare subclass first */ + if (active) { + if (!gst_basesrc_start (basesrc)) + goto error_start; + + if (!basesrc->seekable) { + gst_basesrc_stop (basesrc); + return FALSE; + } + + return TRUE; + } else { + return gst_basesrc_deactivate (basesrc, pad); } - return result; - /* ERROR */ error_start: { GST_DEBUG_OBJECT (basesrc, "failed to start"); diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c index 9bc705a..0a29b36 100644 --- a/libs/gst/base/gstbasetransform.c +++ b/libs/gst/base/gstbasetransform.c @@ -84,10 +84,10 @@ static void gst_base_transform_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_base_transform_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean gst_base_transform_src_activate (GstPad * pad, - GstActivateMode mode); -static gboolean gst_base_transform_sink_activate (GstPad * pad, - GstActivateMode mode); +static gboolean gst_base_transform_src_activate_pull (GstPad * pad, + gboolean active); +static gboolean gst_base_transform_sink_activate_push (GstPad * pad, + gboolean active); static GstElementStateReturn gst_base_transform_change_state (GstElement * element); @@ -157,8 +157,8 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class) GST_DEBUG_FUNCPTR (gst_base_transform_event)); gst_pad_set_chain_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_chain)); - gst_pad_set_activate_function (trans->sinkpad, - GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate)); + gst_pad_set_activatepush_function (trans->sinkpad, + GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push)); gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad); pad_template = @@ -169,8 +169,8 @@ gst_base_transform_init (GstBaseTransform * trans, gpointer g_class) GST_DEBUG_FUNCPTR (gst_base_transform_proxy_getcaps)); gst_pad_set_getrange_function (trans->srcpad, GST_DEBUG_FUNCPTR (gst_base_transform_getrange)); - gst_pad_set_activate_function (trans->srcpad, - GST_DEBUG_FUNCPTR (gst_base_transform_src_activate)); + gst_pad_set_activatepull_function (trans->srcpad, + GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull)); gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad); } @@ -344,7 +344,7 @@ gst_base_transform_get_property (GObject * object, guint prop_id, } static gboolean -gst_base_transform_sink_activate (GstPad * pad, GstActivateMode mode) +gst_base_transform_sink_activate_push (GstPad * pad, gboolean active) { gboolean result = TRUE; GstBaseTransform *trans; @@ -353,39 +353,31 @@ gst_base_transform_sink_activate (GstPad * pad, GstActivateMode mode) trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad)); bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); - switch (mode) { - case GST_ACTIVATE_PUSH: - case GST_ACTIVATE_PULL: - if (bclass->start) - result = bclass->start (trans); - break; - case GST_ACTIVATE_NONE: - break; + if (active) { + if (bclass->start) + result = bclass->start (trans); } return result; } static gboolean -gst_base_transform_src_activate (GstPad * pad, GstActivateMode mode) +gst_base_transform_src_activate_pull (GstPad * pad, gboolean active) { gboolean result = FALSE; GstBaseTransform *trans; + GstBaseTransformClass *bclass; trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad)); + bclass = GST_BASE_TRANSFORM_GET_CLASS (trans); - switch (mode) { - case GST_ACTIVATE_PUSH: - result = TRUE; - break; - case GST_ACTIVATE_PULL: - result = gst_pad_set_active (trans->sinkpad, mode); - result = gst_pad_peer_set_active (trans->sinkpad, mode); - break; - case GST_ACTIVATE_NONE: - result = TRUE; - break; + result = gst_pad_activate_pull (trans->sinkpad, active); + + if (active) { + if (result && bclass->start) + result &= bclass->start (trans); } + return result; } diff --git a/libs/gst/base/gsttypefindhelper.c b/libs/gst/base/gsttypefindhelper.c index d0edfba..884d7f9 100644 --- a/libs/gst/base/gsttypefindhelper.c +++ b/libs/gst/base/gsttypefindhelper.c @@ -130,5 +130,8 @@ gst_type_find_helper (GstPad * src, guint64 size) if (find.best_probability > 0) result = find.caps; + if (find.buffer) + gst_buffer_unref (find.buffer); + return result; } diff --git a/plugins/elements/gstqueue.c b/plugins/elements/gstqueue.c index 43645c5..dd17a3d 100644 --- a/plugins/elements/gstqueue.c +++ b/plugins/elements/gstqueue.c @@ -140,8 +140,8 @@ static GstPadLinkReturn gst_queue_link_sink (GstPad * pad, GstPad * peer); static GstPadLinkReturn gst_queue_link_src (GstPad * pad, GstPad * peer); static void gst_queue_locked_flush (GstQueue * queue); -static gboolean gst_queue_src_activate (GstPad * pad, GstActivateMode mode); -static gboolean gst_queue_sink_activate (GstPad * pad, GstActivateMode mode); +static gboolean gst_queue_src_activate_push (GstPad * pad, gboolean active); +static gboolean gst_queue_sink_activate_push (GstPad * pad, gboolean active); static GstElementStateReturn gst_queue_change_state (GstElement * element); @@ -300,8 +300,8 @@ gst_queue_init (GstQueue * queue) "sink"); gst_pad_set_chain_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_chain)); - gst_pad_set_activate_function (queue->sinkpad, - GST_DEBUG_FUNCPTR (gst_queue_sink_activate)); + gst_pad_set_activatepush_function (queue->sinkpad, + GST_DEBUG_FUNCPTR (gst_queue_sink_activate_push)); gst_pad_set_event_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_handle_sink_event)); gst_pad_set_link_function (queue->sinkpad, @@ -316,8 +316,8 @@ gst_queue_init (GstQueue * queue) gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate), "src"); gst_pad_set_loop_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_loop)); - gst_pad_set_activate_function (queue->srcpad, - GST_DEBUG_FUNCPTR (gst_queue_src_activate)); + gst_pad_set_activatepush_function (queue->srcpad, + GST_DEBUG_FUNCPTR (gst_queue_src_activate_push)); gst_pad_set_link_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_link_src)); gst_pad_set_getcaps_function (queue->srcpad, @@ -819,65 +819,55 @@ gst_queue_handle_src_query (GstPad * pad, GstQuery * query) } static gboolean -gst_queue_sink_activate (GstPad * pad, GstActivateMode mode) +gst_queue_sink_activate_push (GstPad * pad, gboolean active) { gboolean result = FALSE; GstQueue *queue; queue = GST_QUEUE (GST_OBJECT_PARENT (pad)); - switch (mode) { - case GST_ACTIVATE_PUSH: - queue->flushing = FALSE; - result = TRUE; - break; - case GST_ACTIVATE_PULL: - result = FALSE; - break; - case GST_ACTIVATE_NONE: - /* step 1, unblock chain and loop functions */ - GST_QUEUE_MUTEX_LOCK; - queue->flushing = TRUE; - gst_queue_locked_flush (queue); - g_cond_signal (queue->item_del); - GST_QUEUE_MUTEX_UNLOCK; + if (active) { + queue->flushing = FALSE; + result = TRUE; + } else { + /* step 1, unblock chain and loop functions */ + GST_QUEUE_MUTEX_LOCK; + queue->flushing = TRUE; + gst_queue_locked_flush (queue); + g_cond_signal (queue->item_del); + GST_QUEUE_MUTEX_UNLOCK; - /* step 2, make sure streaming finishes */ - result = gst_pad_stop_task (pad); - break; + /* step 2, make sure streaming finishes */ + result = gst_pad_stop_task (pad); } + return result; } static gboolean -gst_queue_src_activate (GstPad * pad, GstActivateMode mode) +gst_queue_src_activate_push (GstPad * pad, gboolean active) { gboolean result = FALSE; GstQueue *queue; queue = GST_QUEUE (GST_OBJECT_PARENT (pad)); - switch (mode) { - case GST_ACTIVATE_PUSH: - GST_QUEUE_MUTEX_LOCK; - queue->flushing = FALSE; - result = gst_pad_start_task (pad, (GstTaskFunction) gst_queue_loop, pad); - GST_QUEUE_MUTEX_UNLOCK; - break; - case GST_ACTIVATE_PULL: - result = FALSE; - break; - case GST_ACTIVATE_NONE: - /* step 1, unblock chain and loop functions */ - GST_QUEUE_MUTEX_LOCK; - queue->flushing = TRUE; - g_cond_signal (queue->item_add); - GST_QUEUE_MUTEX_UNLOCK; + if (active) { + GST_QUEUE_MUTEX_LOCK; + queue->flushing = FALSE; + result = gst_pad_start_task (pad, (GstTaskFunction) gst_queue_loop, pad); + GST_QUEUE_MUTEX_UNLOCK; + } else { + /* step 1, unblock chain and loop functions */ + GST_QUEUE_MUTEX_LOCK; + queue->flushing = TRUE; + g_cond_signal (queue->item_add); + GST_QUEUE_MUTEX_UNLOCK; - /* step 2, make sure streaming finishes */ - result = gst_pad_stop_task (pad); - break; + /* step 2, make sure streaming finishes */ + result = gst_pad_stop_task (pad); } + return result; } diff --git a/plugins/elements/gsttee.c b/plugins/elements/gsttee.c index 2b70a77..9b0bd65 100644 --- a/plugins/elements/gsttee.c +++ b/plugins/elements/gsttee.c @@ -75,7 +75,8 @@ static void gst_tee_get_property (GObject * object, guint prop_id, static GstFlowReturn gst_tee_chain (GstPad * pad, GstBuffer * buffer); static void gst_tee_loop (GstPad * pad); -static gboolean gst_tee_sink_activate (GstPad * pad, GstActivateMode mode); +static gboolean gst_tee_sink_activate_push (GstPad * pad, gboolean active); +static gboolean gst_tee_sink_activate_pull (GstPad * pad, gboolean active); static void @@ -153,8 +154,10 @@ gst_tee_init (GstTee * tee) static void gst_tee_update_pad_functions (GstTee * tee) { - gst_pad_set_activate_function (tee->sinkpad, - GST_DEBUG_FUNCPTR (gst_tee_sink_activate)); + gst_pad_set_activatepush_function (tee->sinkpad, + GST_DEBUG_FUNCPTR (gst_tee_sink_activate_push)); + gst_pad_set_activatepull_function (tee->sinkpad, + GST_DEBUG_FUNCPTR (gst_tee_sink_activate_pull)); if (tee->has_chain) gst_pad_set_chain_function (tee->sinkpad, @@ -348,27 +351,35 @@ pause_task: } static gboolean -gst_tee_sink_activate (GstPad * pad, GstActivateMode mode) +gst_tee_sink_activate_push (GstPad * pad, gboolean active) { - gboolean result = FALSE; GstTee *tee; tee = GST_TEE (GST_OBJECT_PARENT (pad)); - switch (mode) { - case GST_ACTIVATE_PUSH: - g_return_val_if_fail (tee->has_chain, FALSE); - result = TRUE; - break; - case GST_ACTIVATE_PULL: - g_return_val_if_fail (tee->has_sink_loop, FALSE); - result = gst_pad_start_task (pad, (GstTaskFunction) gst_tee_loop, pad); - break; - case GST_ACTIVATE_NONE: - result = gst_pad_stop_task (pad); - break; + tee->sink_mode = active && GST_ACTIVATE_PUSH; + + if (active) { + g_return_val_if_fail (tee->has_chain, FALSE); } - tee->sink_mode = mode; - return result; + return TRUE; +} + +/* won't be called until we implement an activate function */ +static gboolean +gst_tee_sink_activate_pull (GstPad * pad, gboolean active) +{ + GstTee *tee; + + tee = GST_TEE (GST_OBJECT_PARENT (pad)); + + tee->sink_mode = active && GST_ACTIVATE_PULL; + + if (active) { + g_return_val_if_fail (tee->has_sink_loop, FALSE); + return gst_pad_start_task (pad, (GstTaskFunction) gst_tee_loop, pad); + } else { + return gst_pad_stop_task (pad); + } } diff --git a/plugins/elements/gsttypefindelement.c b/plugins/elements/gsttypefindelement.c index 1eb7195..4fa1f34 100644 --- a/plugins/elements/gsttypefindelement.c +++ b/plugins/elements/gsttypefindelement.c @@ -133,8 +133,9 @@ static gboolean gst_type_find_element_checkgetrange (GstPad * srcpad); static GstElementStateReturn gst_type_find_element_change_state (GstElement * element); +static gboolean gst_type_find_element_activate (GstPad * pad); static gboolean -gst_type_find_element_activate (GstPad * pad, GstActivateMode mode); +gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active); static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 }; @@ -215,7 +216,8 @@ gst_type_find_element_init (GstTypeFindElement * typefind) typefind->src = gst_pad_new_from_template (gst_static_pad_template_get (&type_find_element_src_template), "src"); - gst_pad_set_activate_function (typefind->src, gst_type_find_element_activate); + gst_pad_set_activatepull_function (typefind->src, + gst_type_find_element_activate_src_pull); gst_pad_set_checkgetrange_function (typefind->src, gst_type_find_element_checkgetrange); gst_pad_set_getrange_function (typefind->src, gst_type_find_element_getrange); @@ -749,56 +751,80 @@ gst_type_find_element_getrange (GstPad * srcpad, } static gboolean -do_pull_typefind (GstTypeFindElement * typefind) +gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active) { - GstCaps *caps; - GstPad *peer; - gboolean res = FALSE; - - peer = gst_pad_get_peer (typefind->sink); - if (peer) { - if (gst_pad_peer_set_active (typefind->sink, GST_ACTIVATE_PULL)) { - gint64 size; - GstFormat format = GST_FORMAT_BYTES; - - gst_pad_query_position (peer, &format, NULL, &size); - caps = gst_type_find_helper (peer, (guint64) size); - if (caps) { - g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], - 0, 100, caps); - typefind->mode = MODE_NORMAL; - res = TRUE; - } - } else { - start_typefinding (typefind); - res = TRUE; - } + GstTypeFindElement *typefind; - gst_object_unref (GST_OBJECT (peer)); - } + typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad)); - return res; + return gst_pad_activate_pull (typefind->sink, active); } static gboolean -gst_type_find_element_activate (GstPad * pad, GstActivateMode mode) +gst_type_find_element_activate (GstPad * pad) { - gboolean result; + GstCaps *found_caps = NULL; GstTypeFindElement *typefind; typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad)); - switch (mode) { - case GST_ACTIVATE_PUSH: - case GST_ACTIVATE_PULL: - result = TRUE; - break; - default: - result = TRUE; - break; + /* 1. try to activate in pull mode. if not, switch to push and succeed. + 2. try to pull type find. + 3. deactivate pull mode. + 4. src pad might have been activated push by the state change. deactivate. + 5. if we didn't find any caps, fail. + 6. emit have-type; maybe the app connected the source pad to something. + 7. if the sink pad is activated, we are in pull mode. succeed. + otherwise activate both pads in push mode and succeed. + */ + + /* 1 */ + if (!gst_pad_activate_pull (pad, TRUE)) { + start_typefinding (typefind); + return gst_pad_activate_push (pad, TRUE); } - return result; + /* 2 */ + { + GstPad *peer; + + peer = gst_pad_get_peer (pad); + if (peer) { + gint64 size; + GstFormat format = GST_FORMAT_BYTES; + + gst_pad_query_position (peer, &format, NULL, &size); + found_caps = gst_type_find_helper (peer, (guint64) size); + gst_object_unref (GST_OBJECT (peer)); + } + } + + /* 3 */ + gst_pad_activate_pull (pad, FALSE); + + /* 4 */ + gst_pad_activate_push (typefind->src, FALSE); + + /* 5 */ + if (!found_caps) + return FALSE; + + /* 6 */ + g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], + 0, 100, found_caps); + typefind->mode = MODE_NORMAL; + /* FIXME see if I can unref the caps here */ + + /* 7 */ + if (gst_pad_is_active (pad)) + return TRUE; + else { + gboolean ret; + + ret = gst_pad_activate_push (typefind->src, TRUE); + ret &= gst_pad_activate_push (pad, TRUE); + return ret; + } } static GstElementStateReturn @@ -811,21 +837,11 @@ gst_type_find_element_change_state (GstElement * element) typefind = GST_TYPE_FIND_ELEMENT (element); transition = GST_STATE_TRANSITION (element); - switch (transition) { - case GST_STATE_READY_TO_PAUSED: - if (!do_pull_typefind (typefind)) - return GST_STATE_FAILURE; - //start_typefinding (typefind); - break; - default: - break; - } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); switch (transition) { case GST_STATE_PAUSED_TO_READY: - //stop_typefinding (typefind); gst_caps_replace (&typefind->caps, NULL); break; default: diff --git a/tests/check/gst/gstghostpad.c b/tests/check/gst/gstghostpad.c index 44f910f..5ebcdd3 100644 --- a/tests/check/gst/gstghostpad.c +++ b/tests/check/gst/gstghostpad.c @@ -90,6 +90,39 @@ START_TEST (test_ghost_pads) fail_unless (gst_element_set_state (b1, GST_STATE_NULL) == GST_STATE_SUCCESS); gst_object_unref (GST_OBJECT (b1)); + /* unreffing the bin will unref all elements, which will unlink and unparent + * all pads */ + + /* FIXME: ghost pads need to drop their internal pad in the unlink function, + * but can't right now. So internal pads have a ref from their parent, and the + * internal pads' targets have refs from the internals. When we do the last + * unref on the ghost pads, these refs should go away. + */ + + assert_gstrefcount (fsrc, 2); /* gisrc */ + assert_gstrefcount (gsink, 1); + assert_gstrefcount (gsrc, 1); + assert_gstrefcount (fsink, 2); /* gisink */ + + assert_gstrefcount (gisrc, 2); /* gsink -- fixme drop ref in unlink */ + assert_gstrefcount (isink, 2); /* gsink */ + assert_gstrefcount (gisink, 2); /* gsrc -- fixme drop ref in unlink */ + assert_gstrefcount (isrc, 2); /* gsrc */ + + /* while the fixme isn't fixed, check cleanup */ + gst_object_unref (GST_OBJECT (gsink)); + assert_gstrefcount (isink, 1); + assert_gstrefcount (gisrc, 1); + assert_gstrefcount (fsrc, 2); /* gisrc */ + gst_object_unref (GST_OBJECT (gisrc)); + assert_gstrefcount (fsrc, 1); + + gst_object_unref (GST_OBJECT (gsrc)); + assert_gstrefcount (isrc, 1); + assert_gstrefcount (gisink, 1); + assert_gstrefcount (fsink, 2); /* gisrc */ + gst_object_unref (GST_OBJECT (gisink)); + assert_gstrefcount (fsink, 1); } END_TEST Suite * gst_ghost_pad_suite (void) { diff --git a/tests/check/pipelines/simple-launch-lines.c b/tests/check/pipelines/simple-launch-lines.c index 3e3db26..6ebf387 100644 --- a/tests/check/pipelines/simple-launch-lines.c +++ b/tests/check/pipelines/simple-launch-lines.c @@ -99,8 +99,68 @@ START_TEST (test_2_elements) ASSERT_CRITICAL (run_pipeline (setup_pipeline (s), s, GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN)); */ } -END_TEST Suite * -simple_launch_lines_suite (void) +END_TEST static void +got_handoff (GstElement * sink, GstBuffer * buf, GstPad * pad, gpointer unused) +{ + gst_element_post_message + (sink, gst_message_new_application (gst_structure_new ("foo", NULL))); +} + +static void +assert_live_count (GType type, gint live) +{ + GstAllocTrace *trace; + const gchar *name; + + if (gst_alloc_trace_available ()) { + name = g_type_name (type); + g_assert (name); + trace = gst_alloc_trace_get (name); + if (trace) { + g_return_if_fail (trace->live == live); + } + } else { + g_print ("\nSkipping live count tests; recompile with traces to enable\n"); + } +} + +START_TEST (test_stop_from_app) +{ + GstElement *fakesrc, *fakesink, *pipeline; + GstBus *bus; + GstMessageType revent; + + assert_live_count (GST_TYPE_BUFFER, 0); + + fakesrc = gst_element_factory_make ("fakesrc", NULL); + fakesink = gst_element_factory_make ("fakesink", NULL); + pipeline = gst_element_factory_make ("pipeline", NULL); + + g_return_if_fail (fakesrc && fakesink && pipeline); + + gst_element_link (fakesrc, fakesink); + gst_bin_add_many (GST_BIN (pipeline), fakesrc, fakesink, NULL); + + g_object_set (fakesink, "signal-handoffs", (gboolean) TRUE, NULL); + g_signal_connect (fakesink, "handoff", G_CALLBACK (got_handoff), NULL); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + bus = gst_element_get_bus (pipeline); + g_assert (bus); + + /* will time out after half a second */ + revent = gst_bus_poll (bus, GST_MESSAGE_APPLICATION, GST_SECOND / 2); + + g_return_if_fail (revent == GST_MESSAGE_APPLICATION); + gst_message_unref (gst_bus_pop (bus)); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (GST_OBJECT (pipeline)); + + assert_live_count (GST_TYPE_BUFFER, 0); +} +END_TEST Suite * simple_launch_lines_suite (void) { Suite *s = suite_create ("Pipelines"); TCase *tc_chain = tcase_create ("linear"); @@ -110,6 +170,7 @@ simple_launch_lines_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_2_elements); + tcase_add_test (tc_chain, test_stop_from_app); return s; } diff --git a/tools/gst-launch.c b/tools/gst-launch.c index b2199f3..7206de8 100644 --- a/tools/gst-launch.c +++ b/tools/gst-launch.c @@ -523,7 +523,7 @@ main (int argc, char *argv[]) if (!gst_alloc_trace_available ()) { g_warning ("Trace not available (recompile with trace enabled)."); } - gst_alloc_trace_print_all (); + gst_alloc_trace_print_live (); } /* make a null-terminated version of argv */ @@ -643,7 +643,7 @@ end: gst_object_unref (GST_OBJECT (pipeline)); if (trace) - gst_alloc_trace_print_all (); + gst_alloc_trace_print_live (); return res; } -- 2.7.4