From 5b77a67125cc1e0a753f4ed46d32689460b2e15c Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Wed, 21 Sep 2005 12:21:10 +0000 Subject: [PATCH] check/gst/gstutils.c: New file. Original commit message from CVS: 2005-09-21 Andy Wingo * check/gst/gstutils.c: New file. (test_buffer_probe_n_times): A simple buffer probe test. More to come, foolios. * gst/gstutils.c (gst_pad_add_buffer_probe): Connect to have-data::buffer, not have-data. (gst_pad_add_event_probe): Likewise for have-data::event. (gst_pad_add_data_probe): More docs. The part about 'resolving the peer' isn't quite right yet though. (gst_pad_remove_buffer_probe, gst_pad_remove_event_probe) (gst_pad_remove_data_probe): Change to take the guint handler_id as their arg, not the function+data, which is more glib-like. * gst/gstpad.c (gst_pad_emit_have_data_signal): Add a detail to the signal emission to indicate if the data is a buffer or an event. (gst_pad_get_type): Initialize buffer and event quarks. (gst_pad_class_init): have-data is now a detailed signal, yes it is. --- check/Makefile.am | 1 + check/gst/gstutils.c | 96 ++++++++++++++++++++++++ docs/gst/tmpl/gstpad.sgml | 6 ++ docs/libs/tmpl/gstdataprotocol.sgml | 3 + gst/gstpad.c | 17 ++++- gst/gstutils.c | 110 +++++++++++++--------------- gst/gstutils.h | 12 +-- tests/check/Makefile.am | 1 + tests/check/gst/gstutils.c | 96 ++++++++++++++++++++++++ 9 files changed, 273 insertions(+), 69 deletions(-) create mode 100644 check/gst/gstutils.c create mode 100644 tests/check/gst/gstutils.c diff --git a/check/Makefile.am b/check/Makefile.am index bb2e54bc12..5140c986c6 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -45,6 +45,7 @@ check_PROGRAMS = \ gst/gstsystemclock \ gst/gststructure \ gst/gsttag \ + gst/gstutils \ gst/gstvalue \ elements/fakesrc \ elements/identity \ diff --git a/check/gst/gstutils.c b/check/gst/gstutils.c new file mode 100644 index 0000000000..7fa339e304 --- /dev/null +++ b/check/gst/gstutils.c @@ -0,0 +1,96 @@ +/* GStreamer + * Copyright (C) <2005> Thomas Vander Stichele + * + * gstutils.c: Unit test for functions in gstutils + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#define SPECIAL_POINTER (void*)19283847 +static int n_buffer_probes = 0; + +static gboolean +buffer_probe (GstPad * pad, GstBuffer * obj, gpointer data) +{ + n_buffer_probes++; + g_assert (data == SPECIAL_POINTER); + return TRUE; +} + +GST_START_TEST (test_buffer_probe_n_times) +{ + GstElement *pipeline, *fakesrc, *fakesink; + GstBus *bus; + GstMessage *message; + GstPad *pad; + guint id; + + pipeline = gst_element_factory_make ("pipeline", NULL); + fakesrc = gst_element_factory_make ("fakesrc", NULL); + fakesink = gst_element_factory_make ("fakesink", NULL); + + g_object_set (fakesrc, "num-buffers", (int) 10, NULL); + + gst_bin_add_many (GST_BIN (pipeline), fakesrc, fakesink, NULL); + gst_element_link (fakesrc, fakesink); + + pad = gst_element_get_pad (fakesink, "sink"); + id = gst_pad_add_buffer_probe (pad, G_CALLBACK (buffer_probe), + SPECIAL_POINTER); + gst_object_unref (pad); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + bus = gst_element_get_bus (pipeline); + message = gst_bus_poll (bus, GST_MESSAGE_EOS, -1); + gst_message_unref (message); + gst_object_unref (bus); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + + g_assert (n_buffer_probes == 10); +} GST_END_TEST; + +Suite * +gst_utils_suite (void) +{ + Suite *s = suite_create ("GstUtils"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_buffer_probe_n_times); + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = gst_utils_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/docs/gst/tmpl/gstpad.sgml b/docs/gst/tmpl/gstpad.sgml index 3c0d226a74..857f223d61 100644 --- a/docs/gst/tmpl/gstpad.sgml +++ b/docs/gst/tmpl/gstpad.sgml @@ -1306,6 +1306,8 @@ gst_element_request_pad_by_name() or gst_element_request_compatible_pad(). @pad: +@handler_id: + @handler: @data: @@ -1316,6 +1318,8 @@ gst_element_request_pad_by_name() or gst_element_request_compatible_pad(). @pad: +@handler_id: + @handler: @data: @@ -1326,6 +1330,8 @@ gst_element_request_pad_by_name() or gst_element_request_compatible_pad(). @pad: +@handler_id: + @handler: @data: diff --git a/docs/libs/tmpl/gstdataprotocol.sgml b/docs/libs/tmpl/gstdataprotocol.sgml index 0277c7c033..c5446c903f 100644 --- a/docs/libs/tmpl/gstdataprotocol.sgml +++ b/docs/libs/tmpl/gstdataprotocol.sgml @@ -27,6 +27,9 @@ network connections also need a protocol to do this. #GstBuffer, #GstCaps, #GstEvent + + + diff --git a/gst/gstpad.c b/gst/gstpad.c index 4315431b13..18f3d65da2 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -96,6 +96,9 @@ static xmlNodePtr gst_pad_save_thyself (GstObject * object, xmlNodePtr parent); static GstObjectClass *pad_parent_class = NULL; static guint gst_pad_signals[PAD_LAST_SIGNAL] = { 0 }; +static GQuark buffer_quark; +static GQuark event_quark; + GType gst_pad_get_type (void) { @@ -111,6 +114,9 @@ gst_pad_get_type (void) _gst_pad_type = g_type_register_static (GST_TYPE_OBJECT, "GstPad", &pad_info, 0); + buffer_quark = g_quark_from_static_string ("buffer"); + event_quark = g_quark_from_static_string ("event"); + GST_DEBUG_CATEGORY_INIT (debug_dataflow, "GST_DATAFLOW", GST_DEBUG_BOLD | GST_DEBUG_FG_GREEN, "dataflow inside pads"); } @@ -200,7 +206,8 @@ gst_pad_class_init (GstPadClass * klass) */ gst_pad_signals[PAD_HAVE_DATA] = g_signal_new ("have-data", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstPadClass, have_data), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + G_STRUCT_OFFSET (GstPadClass, have_data), _gst_do_pass_data_accumulator, NULL, gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, GST_TYPE_MINI_OBJECT); @@ -2888,6 +2895,7 @@ gst_pad_emit_have_data_signal (GstPad * pad, GstMiniObject * obj) GValue ret = { 0 }; GValue args[2] = { {0}, {0} }; gboolean res; + GQuark detail; /* init */ g_value_init (&ret, G_TYPE_BOOLEAN); @@ -2897,8 +2905,13 @@ gst_pad_emit_have_data_signal (GstPad * pad, GstMiniObject * obj) g_value_init (&args[1], GST_TYPE_MINI_OBJECT); // G_TYPE_POINTER); gst_value_set_mini_object (&args[1], obj); + if (GST_IS_EVENT (obj)) + detail = event_quark; + else + detail = buffer_quark; + /* actually emit */ - g_signal_emitv (args, gst_pad_signals[PAD_HAVE_DATA], 0, &ret); + g_signal_emitv (args, gst_pad_signals[PAD_HAVE_DATA], detail, &ret); res = g_value_get_boolean (&ret); /* clean up */ diff --git a/gst/gstutils.c b/gst/gstutils.c index 75abe3d9e4..d862495cc2 100644 --- a/gst/gstutils.c +++ b/gst/gstutils.c @@ -2431,13 +2431,29 @@ gst_atomic_int_set (gint * atomic_int, gint value) * @handler: function to call when data is passed over pad * @data: data to pass along with the handler * - * Connects a signal handler to the pad's have-data signal, and increases - * the do_{buffer,event}_signals number on the pads so that those - * signals are actually fired. + * Adds a "data probe" to a pad. This function will be called whenever data + * passes through a pad. In this case data means both events and buffers. The + * probe will be called with the data as an argument. Note that the data will + * have a reference count greater than 1, so it will be immutable -- you must + * not change it. * - * Returns: The handler id + * For source pads, the probe will be called after the blocking function, if any + * (see gst_pad_set_blocked_async()), but before looking up the peer to chain + * to. For sink pads, the probe function will be called before configuring the + * sink with new caps, if any, and before calling the pad's chain function. + * + * Your data probe should return TRUE to let the data continue to flow, or FALSE + * to drop it. Dropping data is rarely useful, but occasionally comes in handy + * with events. + * + * Although probes are implemeted internally by connecting @handler to the + * have-data signal on the pad, if you want to remove a probe it is insufficient + * to only call g_signal_handler_disconnect on the returned handler id. To + * remove a probe, use the appropriate function, such as + * gst_pad_remove_data_probe(). + * + * Returns: The handler id. */ - gulong gst_pad_add_data_probe (GstPad * pad, GCallback handler, gpointer data) { @@ -2464,13 +2480,11 @@ gst_pad_add_data_probe (GstPad * pad, GCallback handler, gpointer data) * @handler: function to call when data is passed over pad * @data: data to pass along with the handler * - * Connects a signal handler to the pad's have-data signal, and increases - * the do_event_signals number on the pads so that this signal - * is actually fired. + * Adds a probe that will be called for all events passing through a pad. See + * gst_pad_add_data_probe() for more information. * * Returns: The handler id */ - gulong gst_pad_add_event_probe (GstPad * pad, GCallback handler, gpointer data) { @@ -2480,7 +2494,7 @@ gst_pad_add_event_probe (GstPad * pad, GCallback handler, gpointer data) g_return_val_if_fail (handler != NULL, 0); GST_LOCK (pad); - sigid = g_signal_connect (pad, "have-data", handler, data); + sigid = g_signal_connect (pad, "have-data::event", handler, data); GST_PAD_DO_EVENT_SIGNALS (pad)++; GST_DEBUG ("adding event probe to pad %s:%s, now %d probes", GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_EVENT_SIGNALS (pad)); @@ -2495,13 +2509,11 @@ gst_pad_add_event_probe (GstPad * pad, GCallback handler, gpointer data) * @handler: function to call when data is passed over pad * @data: data to pass along with the handler * - * Connects a signal handler to the pad's have-data signal, and increases - * the do_buffer_signals number on the pads so that this signal - * is actually fired. + * Adds a probe that will be called for all buffers passing through a pad. See + * gst_pad_add_data_probe() for more information. * * Returns: The handler id */ - gulong gst_pad_add_buffer_probe (GstPad * pad, GCallback handler, gpointer data) { @@ -2511,7 +2523,7 @@ gst_pad_add_buffer_probe (GstPad * pad, GCallback handler, gpointer data) g_return_val_if_fail (handler != NULL, 0); GST_LOCK (pad); - sigid = g_signal_connect (pad, "have-data", handler, data); + sigid = g_signal_connect (pad, "have-data::buffer", handler, data); GST_PAD_DO_BUFFER_SIGNALS (pad)++; GST_DEBUG ("adding buffer probe to pad %s:%s, now %d probes", GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_BUFFER_SIGNALS (pad)); @@ -2523,29 +2535,23 @@ gst_pad_add_buffer_probe (GstPad * pad, GCallback handler, gpointer data) /** * gst_pad_remove_data_probe: * @pad: pad to remove the data probe handler from - * @handler: function that was assigned to the signal - * @data: data that was assigned to the signal handler + * @handler_id: handler id returned from gst_pad_add_data_probe * - * Unconnects a signal handler to the pad's have-data signal, and decreases - * the do_{buffer,event}_signals number on the pads so that those - * signals are actually no more fired if no signals are connected. + * Removes a data probe from @pad. */ - void -gst_pad_remove_data_probe (GstPad * pad, GCallback handler, gpointer data) +gst_pad_remove_data_probe (GstPad * pad, guint handler_id) { - guint count; - g_return_if_fail (GST_IS_PAD (pad)); - g_return_if_fail (handler != NULL); + g_return_if_fail (handler_id > 0); GST_LOCK (pad); - count = g_signal_handlers_disconnect_by_func (pad, handler, data); - GST_PAD_DO_BUFFER_SIGNALS (pad) -= count; - GST_PAD_DO_EVENT_SIGNALS (pad) -= count; + g_signal_handler_disconnect (pad, handler_id); + GST_PAD_DO_BUFFER_SIGNALS (pad)--; + GST_PAD_DO_EVENT_SIGNALS (pad)--; GST_DEBUG - ("removing %d data probes from pad %s:%s, now %d event, %d buffer probes", - count, GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_EVENT_SIGNALS (pad), + ("removed data probe from pad %s:%s, now %d event, %d buffer probes", + GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_EVENT_SIGNALS (pad), GST_PAD_DO_BUFFER_SIGNALS (pad)); GST_UNLOCK (pad); } @@ -2553,54 +2559,42 @@ gst_pad_remove_data_probe (GstPad * pad, GCallback handler, gpointer data) /** * gst_pad_remove_event_probe: * @pad: pad to remove the event probe handler from - * @handler: function that was assigned to the signal - * @data: data that was assigned to the signal handler + * @handler_id: handler id returned from gst_pad_add_event_probe * - * Unconnects a signal handler to the pad's have-data signal, and decreases - * the do_event_signals number on the pads so that this signal is - * actually no more fired if no signals are connected. + * Removes an event probe from @pad. */ - void -gst_pad_remove_event_probe (GstPad * pad, GCallback handler, gpointer data) +gst_pad_remove_event_probe (GstPad * pad, guint handler_id) { - guint count; - g_return_if_fail (GST_IS_PAD (pad)); - g_return_if_fail (handler != NULL); + g_return_if_fail (handler_id > 0); GST_LOCK (pad); - count = g_signal_handlers_disconnect_by_func (pad, handler, data); - GST_PAD_DO_EVENT_SIGNALS (pad) -= count; - GST_DEBUG ("removing %d event probes from pad %s:%s, now %d event probes", - count, GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_EVENT_SIGNALS (pad)); + g_signal_handler_disconnect (pad, handler_id); + GST_PAD_DO_EVENT_SIGNALS (pad)--; + GST_DEBUG ("removed event probe from pad %s:%s, now %d event probes", + GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_EVENT_SIGNALS (pad)); GST_UNLOCK (pad); } /** * gst_pad_remove_buffer_probe: * @pad: pad to remove the buffer probe handler from - * @handler: function that was assigned to the signal - * @data: data that was assigned to the signal handler + * @handler_id: handler id returned from gst_pad_add_buffer_probe * - * Unconnects a signal handler to the pad's have-data signal, and decreases - * the emit_buffer_signals number on the pads so that this signal is - * actually no more fired if no signals are connected. + * Removes a buffer probe from @pad. */ - void -gst_pad_remove_buffer_probe (GstPad * pad, GCallback handler, gpointer data) +gst_pad_remove_buffer_probe (GstPad * pad, guint handler_id) { - guint count; - g_return_if_fail (GST_IS_PAD (pad)); - g_return_if_fail (handler != NULL); + g_return_if_fail (handler_id > 0); GST_LOCK (pad); - count = g_signal_handlers_disconnect_by_func (pad, handler, data); - GST_PAD_DO_BUFFER_SIGNALS (pad) -= count; - GST_DEBUG ("removing %d buffer probes from pad %s:%s, now %d buffer probes", - count, GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_BUFFER_SIGNALS (pad)); + g_signal_handler_disconnect (pad, handler_id); + GST_PAD_DO_BUFFER_SIGNALS (pad)--; + GST_DEBUG ("removed buffer probe from pad %s:%s, now %d buffer probes", + GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_BUFFER_SIGNALS (pad)); GST_UNLOCK (pad); } diff --git a/gst/gstutils.h b/gst/gstutils.h index 2c25b48a72..f59547c4a4 100644 --- a/gst/gstutils.h +++ b/gst/gstutils.h @@ -366,21 +366,15 @@ void gst_atomic_int_set (gint * atomic_int, gint gulong gst_pad_add_data_probe (GstPad * pad, GCallback handler, gpointer data); -void gst_pad_remove_data_probe (GstPad * pad, - GCallback handler, - gpointer data); +void gst_pad_remove_data_probe (GstPad * pad, guint handler_id); gulong gst_pad_add_event_probe (GstPad * pad, GCallback handler, gpointer data); -void gst_pad_remove_event_probe (GstPad * pad, - GCallback handler, - gpointer data); +void gst_pad_remove_event_probe (GstPad * pad, guint handler_id); gulong gst_pad_add_buffer_probe (GstPad * pad, GCallback handler, gpointer data); -void gst_pad_remove_buffer_probe (GstPad * pad, - GCallback handler, - gpointer data); +void gst_pad_remove_buffer_probe (GstPad * pad, guint handler_id); /* tag emission utility functions */ void gst_element_found_tags_for_pad (GstElement * element, diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index bb2e54bc12..5140c986c6 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -45,6 +45,7 @@ check_PROGRAMS = \ gst/gstsystemclock \ gst/gststructure \ gst/gsttag \ + gst/gstutils \ gst/gstvalue \ elements/fakesrc \ elements/identity \ diff --git a/tests/check/gst/gstutils.c b/tests/check/gst/gstutils.c new file mode 100644 index 0000000000..7fa339e304 --- /dev/null +++ b/tests/check/gst/gstutils.c @@ -0,0 +1,96 @@ +/* GStreamer + * Copyright (C) <2005> Thomas Vander Stichele + * + * gstutils.c: Unit test for functions in gstutils + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#define SPECIAL_POINTER (void*)19283847 +static int n_buffer_probes = 0; + +static gboolean +buffer_probe (GstPad * pad, GstBuffer * obj, gpointer data) +{ + n_buffer_probes++; + g_assert (data == SPECIAL_POINTER); + return TRUE; +} + +GST_START_TEST (test_buffer_probe_n_times) +{ + GstElement *pipeline, *fakesrc, *fakesink; + GstBus *bus; + GstMessage *message; + GstPad *pad; + guint id; + + pipeline = gst_element_factory_make ("pipeline", NULL); + fakesrc = gst_element_factory_make ("fakesrc", NULL); + fakesink = gst_element_factory_make ("fakesink", NULL); + + g_object_set (fakesrc, "num-buffers", (int) 10, NULL); + + gst_bin_add_many (GST_BIN (pipeline), fakesrc, fakesink, NULL); + gst_element_link (fakesrc, fakesink); + + pad = gst_element_get_pad (fakesink, "sink"); + id = gst_pad_add_buffer_probe (pad, G_CALLBACK (buffer_probe), + SPECIAL_POINTER); + gst_object_unref (pad); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + bus = gst_element_get_bus (pipeline); + message = gst_bus_poll (bus, GST_MESSAGE_EOS, -1); + gst_message_unref (message); + gst_object_unref (bus); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + + g_assert (n_buffer_probes == 10); +} GST_END_TEST; + +Suite * +gst_utils_suite (void) +{ + Suite *s = suite_create ("GstUtils"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_buffer_probe_n_times); + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = gst_utils_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +}