+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),
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)
{
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");
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;
}
</para>
+<!-- ##### ARG GstFakeSrc:is-live ##### -->
+<para>
+
+</para>
+
<!-- ##### ARG GstFakeSrc:last-message ##### -->
<para>
@acceptcapsfunc:
@fixatecapsfunc:
@activatefunc:
+@activatepushfunc:
+@activatepullfunc:
@linkfunc:
@unlinkfunc:
@peer:
</para>
@pad:
-@mode:
+@active:
@Returns:
<!-- # Unused Parameters # -->
-@active:
+@mode:
<!-- ##### FUNCTION gst_pad_is_active ##### -->
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);
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)
}
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;
}
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,
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);
}
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");
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);
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 =
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);
}
}
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;
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;
}
if (find.best_probability > 0)
result = find.caps;
+ if (find.buffer)
+ gst_buffer_unref (find.buffer);
+
return result;
}
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
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,
}
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);
+ }
}
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 };
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);
}
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
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:
#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);
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
GstBusSource *bsource = (GstBusSource *) source;
gst_object_unref (GST_OBJECT_CAST (bsource->bus));
+ bsource->bus = NULL;
}
static GSourceFuncs gst_bus_source_funcs = {
*
* 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.
*/
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:
}
}
-/* 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 */
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);
#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);
_gst_event_initialize (void)
{
gst_event_get_type ();
-
-#ifndef GST_DISABLE_TRACE
- _event_trace = gst_alloc_trace_register (GST_EVENT_TRACE_NAME);
-#endif
}
GType
}
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
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);
"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)
{
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); */
}
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);
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));
}
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 */
}
#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)
{
* 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
#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"
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;
}
}
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 *
/* 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
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);
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);
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;
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;
}
}
* @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)
}
/**
+ * 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.
#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);
GstPadFixateCapsFunction fixatecapsfunc;
GstPadActivateFunction activatefunc;
+ GstPadActivateModeFunction activatepushfunc;
+ GstPadActivateModeFunction activatepullfunc;
/* pad link */
GstPadLinkFunction linkfunc;
#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)
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);
/* 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);
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);
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
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);
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);
"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,
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,
}
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;
}
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;
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);
}
/**
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");
}
/**
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);
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);
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)
}
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;
}
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,
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);
}
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");
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);
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 =
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);
}
}
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;
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;
}
if (find.best_probability > 0)
result = find.caps;
+ if (find.buffer)
+ gst_buffer_unref (find.buffer);
+
return result;
}
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);
"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,
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,
}
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;
}
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
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,
}
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);
+ }
}
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 };
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);
}
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
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:
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)
{
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");
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;
}
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 */
gst_object_unref (GST_OBJECT (pipeline));
if (trace)
- gst_alloc_trace_print_all ();
+ gst_alloc_trace_print_live ();
return res;
}