gst/base/gsttypefindhelper.c (gst_type_find_helper): Unref any remaining buffer.

Original commit message from CVS:
2005-06-27  Andy Wingo  <wingo@pobox.com>

* 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.
This commit is contained in:
Andy Wingo 2005-06-27 18:35:05 +00:00
parent adbd17c378
commit f2cf753b17
36 changed files with 1405 additions and 725 deletions

View file

@ -1,3 +1,79 @@
2005-06-27 Andy Wingo <wingo@pobox.com>
* 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 <wim@fluendo.com>
* gst/gstbin.c: (gst_bin_get_state), (gst_bin_iterate_state_order),

View file

@ -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)
{

View file

@ -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;
}

View file

@ -63,6 +63,11 @@ GstFakeSrc
</para>
<!-- ##### ARG GstFakeSrc:is-live ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:last-message ##### -->
<para>

View file

@ -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.
</para>
@pad:
@mode:
@active:
@Returns:
<!-- # Unused Parameters # -->
@active:
@mode:
<!-- ##### FUNCTION gst_pad_is_active ##### -->

View file

@ -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;
GstBaseSinkClass *bclass;
bclass = GST_BASESINK_GET_CLASS (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);
/* 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);
return result;
}
static gboolean
gst_basesink_activate_push (GstPad * pad, gboolean active)
{
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);
/* 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);
/* step 2, make sure streaming finishes */
result = gst_pad_stop_task (pad);
break;
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;
}

View file

@ -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);
/* step 1, unblock clock sync (if any) */
gst_basesrc_unlock (basesrc);
/* step 2, make sure streaming finishes */
result = gst_pad_stop_task (pad);
break;
error_start:
{
GST_DEBUG_OBJECT (basesrc, "failed to start");
return FALSE;
}
}
static gboolean
gst_basesrc_activate_pull (GstPad * pad, gboolean active)
{
GstBaseSrc *basesrc;
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");

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 = mode;
tee->sink_mode = active && GST_ACTIVATE_PUSH;
return result;
if (active) {
g_return_val_if_fail (tee->has_chain, FALSE);
}
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);
}
}

View file

@ -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;
}
gst_object_unref (GST_OBJECT (peer));
}
return res;
}
static gboolean
gst_type_find_element_activate (GstPad * pad, GstActivateMode mode)
{
gboolean result;
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;
return gst_pad_activate_pull (typefind->sink, active);
}
static gboolean
gst_type_find_element_activate (GstPad * pad)
{
GstCaps *found_caps = NULL;
GstTypeFindElement *typefind;
typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
/* 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:

View file

@ -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

View file

@ -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 = {

View file

@ -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:
}
}
/* gst_iterator_fold functions for pads_activate */
static gboolean
activate_pads (GstPad * pad, GValue * ret, gboolean * active)
{
if (!gst_pad_set_active (pad, *active))
g_value_set_boolean (ret, FALSE);
gst_object_unref (GST_OBJECT (pad));
return TRUE;
}
/* 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;
while (1) {
ires = gst_iterator_fold (iter, func, ret, user_data);
switch (ires) {
case GST_ITERATOR_RESYNC:
break;
case GST_ITERATOR_DONE:
res = TRUE;
goto done;
default:
res = FALSE;
goto done;
}
}
done:
return res;
}
/* 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?
*/
static gboolean
gst_element_pads_activate (GstElement * element, gboolean active)
{
GList *pads;
gboolean result;
guint32 cookie;
GValue ret = { 0, };
GstIterator *iter;
gboolean fold_ok;
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;
/* no need to unset this later, it's just a boolean */
g_value_init (&ret, G_TYPE_BOOLEAN);
g_value_set_boolean (&ret, TRUE);
pad = GST_PAD (pads->data);
gst_object_ref (GST_OBJECT (pad));
GST_UNLOCK (element);
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;
if (active) {
pad_get = GST_PAD_IS_SINK (pad) && gst_pad_check_pull_range (pad);
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;
/* 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_DEBUG ("pad %s:%s: get: %d, loop: %d",
GST_DEBUG_PAD_NAME (pad), pad_get, pad_loop);
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));
}
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));
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));
result &= gst_pad_set_active (pad, GST_ACTIVATE_NONE);
}
gst_object_unref (GST_OBJECT_CAST (pad));
GST_LOCK (element);
if (cookie != element->pads_cookie)
goto restart;
}
GST_UNLOCK (element);
return result;
return TRUE;
}
/* is called with STATE_LOCK */

View file

@ -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);

View file

@ -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

View file

@ -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 */
}

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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. Must be called with STATE_LOCK.
*/
gboolean
gst_pad_set_active (GstPad * pad, gboolean active)
{
GstActivateMode old;
gboolean ret;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
GST_LOCK (pad);
old = GST_PAD_ACTIVATE_MODE (pad);
GST_UNLOCK (pad);
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;
}
}
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_set_active (GstPad * pad, GstActivateMode mode)
gst_pad_activate_pull (GstPad * pad, gboolean active)
{
GstActivateMode old;
GstPadActivateFunction activatefunc;
gboolean active, oldactive;
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))
if ((active && old == GST_ACTIVATE_PULL)
|| (!active && old == GST_ACTIVATE_NONE))
goto was_ok;
/* FIXME, no mode switching yet, need more design docs first */
#if 0
if (G_UNLIKELY (old == mode))
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) {
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;
g_return_val_if_fail (old == GST_ACTIVATE_NONE, FALSE);
} else {
g_return_val_if_fail (old == GST_ACTIVATE_PULL, FALSE);
}
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;
pre_activate_switch (pad, active);
GST_CAT_DEBUG (GST_CAT_PADS,
"calling activate function on pad %s:%s with mode %d",
GST_DEBUG_PAD_NAME (pad), mode);
/* 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 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.
* Activates or deactivates the given pad in push mode via dispatching to the
* pad's activatepushfunc. For use from within pad activation functions only.
*
* 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)
@ -734,6 +832,45 @@ gst_pad_set_activate_function (GstPad * pad, GstPadActivateFunction activate)
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (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.

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -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");
}
/**

View file

@ -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);

View file

@ -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;
GstBaseSinkClass *bclass;
bclass = GST_BASESINK_GET_CLASS (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);
/* 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);
return result;
}
static gboolean
gst_basesink_activate_push (GstPad * pad, gboolean active)
{
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);
/* 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);
/* step 2, make sure streaming finishes */
result = gst_pad_stop_task (pad);
break;
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;
}

View file

@ -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);
/* step 1, unblock clock sync (if any) */
gst_basesrc_unlock (basesrc);
/* step 2, make sure streaming finishes */
result = gst_pad_stop_task (pad);
break;
error_start:
{
GST_DEBUG_OBJECT (basesrc, "failed to start");
return FALSE;
}
}
static gboolean
gst_basesrc_activate_pull (GstPad * pad, gboolean active)
{
GstBaseSrc *basesrc;
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");

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 = mode;
tee->sink_mode = active && GST_ACTIVATE_PUSH;
return result;
if (active) {
g_return_val_if_fail (tee->has_chain, FALSE);
}
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);
}
}

View file

@ -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;
}
gst_object_unref (GST_OBJECT (peer));
}
return res;
}
static gboolean
gst_type_find_element_activate (GstPad * pad, GstActivateMode mode)
{
gboolean result;
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;
return gst_pad_activate_pull (typefind->sink, active);
}
static gboolean
gst_type_find_element_activate (GstPad * pad)
{
GstCaps *found_caps = NULL;
GstTypeFindElement *typefind;
typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
/* 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:

View file

@ -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)
{

View file

@ -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;
}

View file

@ -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;
}