From: <wt...@fr...> - 2005-03-08 15:57:31
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Tue Mar 08 2005 07:57:28 PST Log message: * check/gst/gstobject.c: (START_TEST), (gst_object_suite): * gst/gstthread.c: (gst_thread_release_children_locks): Added parentage check. Fix build og GstThread again. Modified files: . : ChangeLog check/gst : gstobject.c gst : gstthread.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.981&r2=1.982 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/gst/gstobject.c.diff?r1=1.2&r2=1.3 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstthread.c.diff?r1=1.142&r2=1.143 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.981 retrieving revision 1.982 diff -u -d -r1.981 -r1.982 --- ChangeLog 8 Mar 2005 14:38:05 -0000 1.981 +++ ChangeLog 8 Mar 2005 15:57:15 -0000 1.982 @@ -1,5 +1,12 @@ 2005-03-08 Wim Taymans <wi...@fl...> + * check/gst/gstobject.c: (START_TEST), (gst_object_suite): + * gst/gstthread.c: (gst_thread_release_children_locks): + Added parentage check. + Fix build og GstThread again. + +2005-03-08 Wim Taymans <wi...@fl...> * docs/design/part-MT-refcounting.txt: * docs/design/part-conventions.txt: * docs/design/part-gstobject.txt: Index: gstobject.c RCS file: /cvs/gstreamer/gstreamer/check/gst/gstobject.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- gstobject.c 7 Mar 2005 18:33:37 -0000 1.2 +++ gstobject.c 8 Mar 2005 15:57:15 -0000 1.3 @@ -327,6 +327,111 @@ } END_TEST +/* parentage test on GstFakeObject */ +START_TEST (test_fake_object_parentage) +{ + GstObject *object1, *object2; + GstObject *parent; + gboolean result; + /* create new object */ + object1 = g_object_new (gst_fake_object_get_type (), NULL); + fail_if (object1 == NULL, "Failed to create instance of GstFakeObject"); + fail_unless (GST_IS_OBJECT (object1), + "GstFakeObject instance is not a GstObject"); + fail_unless (GST_OBJECT_IS_FLOATING (object1), + "GstFakeObject instance is not floating"); + /* check the parent */ + parent = gst_object_get_parent (object1); + fail_if (parent != NULL, "GstFakeObject has parent"); + /* try to set a NULL parent, this should give a warning */ + ASSERT_CRITICAL (result = gst_object_set_parent (object1, NULL)); + fail_if (result == TRUE, "GstFakeObject accepted NULL parent"); + /* try to set itself as parent, we expect a warning here */ + ASSERT_CRITICAL (result = gst_object_set_parent (object1, object1)); + fail_if (result == TRUE, "GstFakeObject accepted itself as parent"); + /* should still be floating */ + /* create another object */ + object2 = g_object_new (gst_fake_object_get_type (), NULL); + fail_if (object2 == NULL, + "Failed to create another instance of GstFakeObject"); + fail_unless (GST_IS_OBJECT (object2), + "second GstFakeObject instance is not a GstObject"); + /* try to set other object as parent */ + result = gst_object_set_parent (object1, object2); + fail_if (result == FALSE, + "GstFakeObject could not accept other object as parent"); + /* should not be floating anymore */ + fail_if (GST_OBJECT_IS_FLOATING (object1), + "GstFakeObject instance is still floating"); + /* parent should still be floating */ + fail_unless (GST_OBJECT_IS_FLOATING (object2), + fail_if (parent != object2, "GstFakeObject has wrong parent"); + gst_object_unref (parent); + /* try to set other object as parent again */ + fail_if (result == TRUE, "GstFakeObject could set parent twice"); + /* ref before unparenting */ + gst_object_ref (object1); + /* clear parent of object */ + gst_object_unparent (object1); + /* object should not be floating */ + "GstFakeObject instance is floating again"); + gst_object_unref (object1); + gst_object_unref (object2); +} +END_TEST +/* parentage test dispose on GstFakeObject, since our testcase + * does not handle the parent relation completely, the parent does + * not hold a ref to the child, we cannot dispose the parent to + * dipose the child as well. This test needs to be run with DEBUG + * info to check if the finalize methods are called correctly. */ +START_TEST (test_fake_object_parentage_dispose) + fail_if (object2 == NULL, "Failed to create instance of GstFakeObject"); + "GstFakeObject could not aIndex: gstthread.c RCS file: /cvs/gstreamer/gstreamer/gst/gstthread.c,v retrieving revision 1.142 retrieving revision 1.143 diff -u -d -r1.142 -r1.143 --- gstthread.c 7 Mar 2005 18:27:39 -0000 1.142 +++ gstthread.c 8 Mar 2005 15:57:15 -0000 1.143 @@ -26,6 +26,7 @@ #include "gstthread.h" #include "gstmarshal.h" #include "gstscheduler.h" +#include "gstutils.h" #include "gstinfo.h" #define GST_CAT_DEFAULT GST_CAT_THREAD ccept other object as parent"); + /* now dispose parent */ /* test: try renaming a parented object, make sure it fails */ Suite * gst_object_suite (void) { @@ -339,6 +444,8 @@ tcase_add_test (tc_chain, test_fake_object_name_threaded_wrong); tcase_add_test (tc_chain, test_fake_object_name_threaded_right); tcase_add_test (tc_chain, test_fake_object_name_threaded_unique); + tcase_add_test (tc_chain, test_fake_object_parentage); + tcase_add_test (tc_chain, test_fake_object_parentage_dispose); //tcase_add_checked_fixture (tc_chain, setup, teardown); /* SEGV tests go last so we can debug the others */ |
From: <wt...@fr...> - 2005-07-16 13:51:23
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Sat Jul 16 2005 06:50:50 PDT Log message: * check/gst/gstbin.c: (GST_START_TEST): Make elements silent as the deep_notify refs the parent, which might make the test fail. * gst/gstghostpad.c: (gst_ghost_pad_do_activate_push): Don't hold the lock for too long. Modified files: . : ChangeLog check/gst : gstbin.c gst : gstghostpad.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.1271&r2=1.1272 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/gst/gstbin.c.diff?r1=1.11&r2=1.12 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstghostpad.c.diff?r1=1.13&r2=1.14 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.1271 retrieving revision 1.1272 diff -u -d -r1.1271 -r1.1272 --- ChangeLog 16 Jul 2005 12:33:12 -0000 1.1271 +++ ChangeLog 16 Jul 2005 13:50:36 -0000 1.1272 @@ -1,3 +1,12 @@ +2005-07-16 Wim Taymans <wi...@fl...> + + * check/gst/gstbin.c: (GST_START_TEST): + Make elements silent as the deep_notify refs the + parent, which might make the test fail. + * gst/gstghostpad.c: (gst_ghost_pad_do_activate_push): + Don't hold the lock for too long. 2005-07-16 Tim-Philipp Müller <tim at centricular dot net> * gst/base/gstbasesrc.c: (gst_base_src_default_negotiate): Index: gstbin.c RCS file: /cvs/gstreamer/gstreamer/check/gst/gstbin.c,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- gstbin.c 12 Jul 2005 13:26:21 -0000 1.11 +++ gstbin.c 16 Jul 2005 13:50:37 -0000 1.12 @@ -205,9 +205,15 @@ src = gst_element_factory_make ("fakesrc", NULL); fail_if (src == NULL, "Could not create fakesrc"); + /* need to silence the element as the deep_notify refcounts the + * parents while running */ + g_object_set (G_OBJECT (src), "silent", TRUE, NULL); gst_bin_add (GST_BIN (pipeline), src); sink = gst_element_factory_make ("fakesink", NULL); + g_object_set (G_OBJECT (sink), "silent", TRUE, NULL); fail_if (sink == NULL, "Could not create fakesink"); gst_bin_add (GST_BIN (pipeline), sink); Index: gstghostpad.c RCS file: /cvs/gstreamer/gstreamer/gst/gstghostpad.c,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- gstghostpad.c 14 Jul 2005 18:10:04 -0000 1.13 +++ gstghostpad.c 16 Jul 2005 13:50:37 -0000 1.14 @@ -515,13 +515,14 @@ ret = gst_proxy_pad_do_activatepush (pad, active); GST_LOCK (pad); + if ((internal = GST_GHOST_PAD (pad)->internal)) + gst_object_ref (internal); + GST_UNLOCK (pad); - internal = GST_GHOST_PAD (pad)->internal; - - if (internal) + if (internal) { ret &= gst_pad_activate_push (internal, active); - GST_UNLOCK (pad); + gst_object_unref (internal); + } return ret; } |
From: <wt...@fr...> - 2005-07-29 19:22:47
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Fri Jul 29 2005 12:22:40 PDT Log message: * check/gst/gstghostpad.c: (GST_START_TEST), (gst_ghost_pad_suite): Added test for removing an element with ghostpad from a bin. Fixed test as current implementation does the right thing. * gst/gstghostpad.c: (gst_proxy_pad_class_init), (gst_proxy_pad_do_query_type), (gst_proxy_pad_do_event), (gst_proxy_pad_do_query), (gst_proxy_pad_do_internal_link), (gst_proxy_pad_do_bufferalloc), (gst_proxy_pad_do_activate), (gst_proxy_pad_do_activatepull), (gst_proxy_pad_do_activatepush), (gst_proxy_pad_do_chain), (gst_proxy_pad_do_getrange), (gst_proxy_pad_do_checkgetrange), (gst_proxy_pad_do_getcaps), (gst_proxy_pad_do_acceptcaps), (gst_proxy_pad_do_fixatecaps), (gst_proxy_pad_do_setcaps), (gst_proxy_pad_set_target), (gst_proxy_pad_get_target), (gst_proxy_pad_init), (gst_proxy_pad_dispose), (gst_proxy_pad_finalize), (gst_ghost_pad_class_init), (gst_ghost_pad_do_activate_push), (gst_ghost_pad_do_link), (gst_ghost_pad_do_unlink), (gst_ghost_pad_set_internal), (gst_ghost_pad_dispose), (gst_ghost_pad_new_notarget), (gst_ghost_pad_new), (gst_ghost_pad_get_target), (gst_ghost_pad_set_target): * gst/gstghostpad.h: Clean up ghostpads, remove properties for internal stuff. Make threadsafe. Fix refcounting. Prepare for switching targets, not all use cases work yet. Modified files: . : ChangeLog check/gst : gstghostpad.c gst : gstghostpad.c gstghostpad.h Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.1316&r2=1.1317 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/gst/gstghostpad.c.diff?r1=1.6&r2=1.7 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstghostpad.c.diff?r1=1.15&r2=1.16 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstghostpad.h.diff?r1=1.1&r2=1.2 ====Begin Diffs==== Index: gstghostpad.c =================================================================== RCS file: /cvs/gstreamer/gstreamer/gst/gstghostpad.c,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- gstghostpad.c 18 Jul 2005 12:49:52 -0000 1.15 +++ gstghostpad.c 29 Jul 2005 19:22:28 -0000 1.16 @@ -37,21 +37,18 @@ typedef struct _GstProxyPad GstProxyPad; typedef struct _GstProxyPadClass GstProxyPadClass; - -enum -{ - PROXY_PROP_0, - PROXY_PROP_TARGET -}; +#define GST_PROXY_GET_LOCK(pad) (GST_PROXY_PAD (pad)->proxy_lock) +#define GST_PROXY_LOCK(pad) (g_mutex_lock (GST_PROXY_GET_LOCK (pad))) +#define GST_PROXY_UNLOCK(pad) (g_mutex_unlock (GST_PROXY_GET_LOCK (pad))) struct _GstProxyPad { GstPad pad; + /* with PROXY_LOCK */ + GMutex *proxy_lock; GstPad *target; - GMutex *property_lock; /*< private > */ gpointer _gst_reserved[1]; }; @@ -67,12 +64,9 @@ G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD); +static GstPad *gst_proxy_pad_get_target (GstPad * pad); static void gst_proxy_pad_dispose (GObject * object); -static void gst_proxy_pad_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_proxy_pad_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); static void gst_proxy_pad_finalize (GObject * object); #ifndef GST_DISABLE_LOADSAVE @@ -88,12 +82,6 @@ gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_proxy_pad_dispose); gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_proxy_pad_finalize); - gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_proxy_pad_set_property); - gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_proxy_pad_get_property); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROXY_PROP_TARGET, - g_param_spec_object ("target", "Target", "The proxy pad's target", - GST_TYPE_PAD, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); { @@ -108,41 +96,57 @@ const GstQueryType * gst_proxy_pad_do_query_type (GstPad * pad) - GstPad *target = GST_PROXY_PAD_TARGET (pad); + GstPad *target = gst_proxy_pad_get_target (pad); + const GstQueryType *res; g_return_val_if_fail (target != NULL, NULL); - return gst_pad_get_query_types (target); + res = gst_pad_get_query_types (target); + gst_object_unref (target); + + return res; } static gboolean gst_proxy_pad_do_event (GstPad * pad, GstEvent * event) + gboolean res; g_return_val_if_fail (target != NULL, FALSE); - return gst_pad_send_event (target, event); + res = gst_pad_send_event (target, event); gst_proxy_pad_do_query (GstPad * pad, GstQuery * query) - return gst_pad_query (target, query); + res = gst_pad_query (target, query); static GList * gst_proxy_pad_do_internal_link (GstPad * pad) + GList *res; - return gst_pad_get_internal_links (target); + res = gst_pad_get_internal_links (target); static GstFlowReturn @@ -150,7 +154,7 @@ GstCaps * caps, GstBuffer ** buf) GstFlowReturn result; GstPad *peer; g_return_val_if_fail (target != NULL, GST_FLOW_NOT_LINKED); @@ -166,24 +170,27 @@ result = GST_FLOW_NOT_LINKED; } return result; gst_proxy_pad_do_activate (GstPad * pad) - g_return_val_if_fail (target != NULL, FALSE); + res = gst_pad_activate_push (pad, TRUE); - return gst_pad_activate_push (pad, TRUE); gst_proxy_pad_do_activatepull (GstPad * pad, gboolean active) GstActivateMode old; @@ -193,16 +200,20 @@ if ((active && old == GST_ACTIVATE_PULL) || (!active && old == GST_ACTIVATE_NONE)) - return TRUE; + res = TRUE; else - return gst_pad_activate_pull (target, active); + res = gst_pad_activate_pull (target, active); gst_proxy_pad_do_activatepush (GstPad * pad, gboolean active) @@ -212,40 +223,52 @@ if ((active && old == GST_ACTIVATE_PUSH) - return gst_pad_activate_push (target, active); + res = gst_pad_activate_push (target, active); gst_proxy_pad_do_chain (GstPad * pad, GstBuffer * buffer) + GstFlowReturn res; - return gst_pad_chain (target, buffer); + res = gst_pad_chain (target, buffer); gst_proxy_pad_do_getrange (GstPad * pad, guint64 offset, guint size, GstBuffer ** buffer) - return gst_pad_get_range (target, offset, size, buffer); + res = gst_pad_get_range (target, offset, size, buffer); gst_proxy_pad_do_checkgetrange (GstPad * pad) gboolean result; peer = gst_pad_get_peer (target); if (peer) { result = gst_pad_check_pull_range (peer); @@ -253,115 +276,126 @@ } else { result = FALSE; static GstCaps * gst_proxy_pad_do_getcaps (GstPad * pad) + GstCaps *res; - return gst_pad_get_caps (target); + res = gst_pad_get_caps (target); gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps) - return gst_pad_accept_caps (target, caps); + res = gst_pad_accept_caps (target, caps); static void gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps) g_return_if_fail (target != NULL); gst_pad_fixate_caps (target, caps); gst_proxy_pad_do_setcaps (GstPad * pad, GstCaps * caps) - return gst_pad_set_caps (target, caps); + res = gst_pad_set_caps (target, caps); #define SETFUNC(member, kind) \ if (target->member) \ gst_pad_set_##kind##_function (pad, gst_proxy_pad_do_##kind) -static void -gst_proxy_pad_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) +static gboolean +gst_proxy_pad_set_target (GstPad * pad, GstPad * target) - GstPad *pad = GST_PAD (object); - switch (prop_id) { - case PROXY_PROP_TARGET:{ - GstPad *target; - target = GST_PAD_CAST (gst_object_ref - (GST_OBJECT_CAST (g_value_get_object (value)))); - GST_PROXY_PAD_TARGET (object) = target; + GST_PROXY_LOCK (pad); + /* clear old target */ + if (GST_PROXY_PAD_TARGET (pad)) { + gst_object_unref (GST_PROXY_PAD_TARGET (pad)); + GST_PROXY_PAD_TARGET (pad) = NULL; + } - /* really, all these should have default implementations so I can set them - * in the _init() instead of here */ - SETFUNC (querytypefunc, query_type); - SETFUNC (eventfunc, event); - SETFUNC (queryfunc, query); - SETFUNC (intlinkfunc, internal_link); - SETFUNC (activatefunc, activate); - SETFUNC (activatepullfunc, activatepull); - SETFUNC (activatepushfunc, activatepush); - SETFUNC (getcapsfunc, getcaps); - SETFUNC (acceptcapsfunc, acceptcaps); - SETFUNC (fixatecapsfunc, fixatecaps); - SETFUNC (setcapsfunc, setcaps); + if (target) { + /* set and ref new target if any */ + GST_PROXY_PAD_TARGET (pad) = gst_object_ref (target); - if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { - SETFUNC (bufferallocfunc, bufferalloc); - SETFUNC (chainfunc, chain); - } else { - SETFUNC (getrangefunc, getrange); - SETFUNC (checkgetrangefunc, checkgetrange); - } + /* really, all these should have default implementations so I can set them + * in the _init() instead of here */ + SETFUNC (querytypefunc, query_type); + SETFUNC (eventfunc, event); + SETFUNC (queryfunc, query); + SETFUNC (intlinkfunc, internal_link); + SETFUNC (activatefunc, activate); + SETFUNC (activatepullfunc, activatepull); + SETFUNC (activatepushfunc, activatepush); + SETFUNC (getcapsfunc, getcaps); + SETFUNC (acceptcapsfunc, acceptcaps); + SETFUNC (fixatecapsfunc, fixatecaps); + SETFUNC (setcapsfunc, setcaps); - break; + if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { + SETFUNC (bufferallocfunc, bufferalloc); + SETFUNC (chainfunc, chain); + } else { + SETFUNC (getrangefunc, getrange); + SETFUNC (checkgetrangefunc, checkgetrange); } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + GST_PROXY_UNLOCK (pad); + return TRUE; -gst_proxy_pad_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) +static GstPad * +gst_proxy_pad_get_target (GstPad * pad) - case PROXY_PROP_TARGET: - g_value_set_object (value, GST_PROXY_PAD_TARGET (object)); - } + GstPad *target; + target = GST_PROXY_PAD_TARGET (pad); + gst_object_ref (target); + return target; gst_proxy_pad_init (GstProxyPad * pad) - pad->property_lock = g_mutex_new (); + pad->proxy_lock = g_mutex_new (); @@ -369,9 +403,9 @@ GstPad *pad = GST_PAD (object); - if (GST_PROXY_PAD_TARGET (pad)) { - gst_object_replace ((GstObject **) & GST_PROXY_PAD_TARGET (pad), NULL); + gst_object_replace ((GstObject **) & GST_PROXY_PAD_TARGET (pad), NULL); G_OBJECT_CLASS (gst_proxy_pad_parent_class)->dispose (object); @@ -381,8 +415,8 @@ GstProxyPad *pad = GST_PROXY_PAD (object); - g_mutex_free (pad->property_lock); - pad->property_lock = NULL; + g_mutex_free (pad->proxy_lock); + pad->proxy_lock = NULL; G_OBJECT_CLASS (gst_proxy_pad_parent_class)->finalize (object); @@ -422,16 +456,11 @@ */ - GHOST_PROP_0, - GHOST_PROP_INTERNAL struct _GstGhostPad GstProxyPad pad; GstPad *internal; gulong notify_id; @@ -450,13 +479,10 @@ G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD); +static gboolean gst_ghost_pad_set_internal (GstGhostPad * pad, + GstPad * internal); static void gst_ghost_pad_dispose (GObject * object); -static void gst_ghost_pad_set_property (GObject * object, guint prop_id, -static void gst_ghost_pad_get_property (GObject * object, guint prop_id, /* Work around g_logv's use of G_GNUC_PRINTF because gcc chokes on %P, which we * use for GST_PTR_FORMAT. */ @@ -476,12 +502,6 @@ GObjectClass *gobject_class = (GObjectClass *) klass; gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ghost_pad_dispose); - gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_ghost_pad_set_property); - gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_ghost_pad_get_property); - g_object_class_install_property (G_OBJECT_CLASS (klass), GHOST_PROP_INTERNAL, - g_param_spec_object ("internal", "Internal", - "The ghost pad's internal pad", GST_TYPE_PAD, G_PARAM_READWRITE)); /* will only be called for src pads (afaict) */ @@ -511,10 +531,10 @@ ret = gst_proxy_pad_do_activatepush (pad, active); - GST_LOCK (pad); if ((internal = GST_GHOST_PAD (pad)->internal)) gst_object_ref (internal); - GST_UNLOCK (pad); if (internal) { ret &= gst_pad_activate_push (internal, active); @@ -528,41 +548,49 @@ gst_ghost_pad_do_link (GstPad * pad, GstPad * peer) GstPad *internal, *target; + GstPadLinkReturn ret; + target = gst_proxy_pad_get_target (pad); - target = GST_PROXY_PAD_TARGET (pad); g_return_val_if_fail (target != NULL, GST_PAD_LINK_NOSCHED); /* proxy the peer into the bin */ internal = g_object_new (GST_TYPE_PROXY_PAD, "name", NULL, "direction", GST_PAD_DIRECTION (peer), - "template", GST_PAD_PAD_TEMPLATE (peer), "target", peer, NULL); - g_object_set (pad, "internal", internal, NULL); + "template", GST_PAD_PAD_TEMPLATE (peer), NULL); - if ((GST_PAD_IS_SRC (internal) && - gst_pad_link (internal, target) == GST_PAD_LINK_OK) || - (GST_PAD_IS_SINK (internal) && - (gst_pad_link (target, internal) == GST_PAD_LINK_OK))) { + gst_proxy_pad_set_target (internal, peer); + gst_ghost_pad_set_internal (GST_GHOST_PAD (pad), internal); + if (GST_PAD_IS_SRC (internal)) + ret = gst_pad_link (internal, target); + else + ret = gst_pad_link (target, internal); + if (ret == GST_PAD_LINK_OK) gst_pad_set_active (internal, GST_PAD_ACTIVATE_MODE (pad)); - return GST_PAD_LINK_OK; - } else { - g_object_set (pad, "internal", NULL, NULL); - return GST_PAD_LINK_REFUSED; + gst_ghost_pad_set_internal (GST_GHOST_PAD (pad), NULL); + return ret; gst_ghost_pad_do_unlink (GstPad * pad) if (target->unlinkfunc) target->unlinkfunc (target); - /* FIXME: should do this here, but locks in deep_notify prevent it */ - /* g_object_set (pad, "internal", NULL, NULL); */ + gst_ghost_pad_set_internal (GST_GHOST_PAD (pad), NULL); @@ -581,84 +609,57 @@ gst_caps_unref (caps); -gst_ghost_pad_set_property (GObject * object, guint prop_id, +gst_ghost_pad_set_internal (GstGhostPad * pad, GstPad * internal) - GstGhostPad *pad = GST_GHOST_PAD (object); - case GHOST_PROP_INTERNAL:{ - GstPad *internal; - g_mutex_lock (GST_PROXY_PAD (pad)->property_lock); - 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); - if (intpeer) { - if (GST_PAD_IS_SRC (pad->internal)) { - gst_pad_unlink (pad->internal, intpeer); - } else { - gst_pad_unlink (intpeer, pad->internal); - } - gst_object_unref (intpeer); - } - /* should dispose it */ - gst_object_unparent (GST_OBJECT_CAST (pad->internal)); + /* first remove old internal pad */ + if (pad->internal) { + GstPad *intpeer; - internal = g_value_get_object (value); /* no extra refcount... */ + gst_pad_set_activatepull_function (pad->internal, NULL); - if (internal) { - if (!gst_object_set_parent (GST_OBJECT_CAST (internal), - GST_OBJECT_CAST (pad))) { - gst_critical ("Could not set internal pad %" GST_PTR_FORMAT, - internal); - g_mutex_unlock (GST_PROXY_PAD (pad)->property_lock); - return; + g_signal_handler_disconnect (pad->internal, pad->notify_id); - /* could be more general here, iterating over all writable properties... - * taking the short road for now tho */ - 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); + intpeer = gst_pad_get_peer (pad->internal); + if (intpeer) { + if (GST_PAD_IS_SRC (pad->internal)) + gst_pad_unlink (pad->internal, intpeer); + else + gst_pad_unlink (intpeer, pad->internal); + gst_object_unref (intpeer); + } + /* should dispose it */ + gst_object_unparent (GST_OBJECT_CAST (pad->internal)); - /* a ref was taken by set_parent */ + /* then set new internal pad */ + if (internal) { + if (!gst_object_set_parent (GST_OBJECT_CAST (internal), + GST_OBJECT_CAST (pad))) + goto could_not_set; - pad->internal = internal; + /* could be more general here, iterating over all writable properties... + * taking the short road for now tho */ + 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 */ + pad->internal = internal; - g_mutex_unlock (GST_PROXY_PAD (pad)->property_lock); - } -} -gst_ghost_pad_get_property (GObject * object, guint prop_id, - case GHOST_PROP_INTERNAL: - g_value_set_object (value, GST_GHOST_PAD (object)->internal); + /* ERRORS */ +could_not_set: + { + gst_critical ("Could not set internal pad %" GST_PTR_FORMAT, internal); + GST_PROXY_UNLOCK (pad); + return FALSE; @@ -671,16 +672,46 @@ gst_ghost_pad_dispose (GObject * object) - g_object_set (object, "internal", NULL, NULL); + gst_ghost_pad_set_internal (GST_GHOST_PAD (object), NULL); G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object); /** + * gst_ghost_pad_new_notarget: + * @name: the name of the new pad, or NULL to assign a default name. + * @dir: the direction of the ghostpad + * + * Create a new ghostpad without a target with the given direction. + * A target can be set on the ghostpad later with the + * #gst_ghost_pad_set_target() function. + * The created ghostpad will not have a padtemplate. + * Returns: a new #GstPad, or NULL in case of an error. + */ +GstPad * +gst_ghost_pad_new_notarget (const gchar * name, GstPadDirection dir) +{ + GstPad *ret; + ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name, "direction", dir, NULL); + gst_pad_set_activatepush_function (ret, gst_ghost_pad_do_activate_push); + gst_pad_set_link_function (ret, gst_ghost_pad_do_link); + gst_pad_set_unlink_function (ret, gst_ghost_pad_do_unlink); +} +/** * gst_ghost_pad_new: * @name: the name of the new pad, or NULL to assign a default name. * @target: the pad to ghost. * + * Create a new ghostpad with @target as the target. The direction and + * padtemplate will be taken from the target pad. * Will ref the target. * Returns: a new #GstPad, or NULL in case of an error. @@ -691,16 +722,47 @@ GstPad *ret; g_return_val_if_fail (GST_IS_PAD (target), NULL); - g_return_val_if_fail (!GST_PAD_IS_LINKED (target), NULL); + g_return_val_if_fail (!gst_pad_is_linked (target), NULL); - ret = g_object_new (GST_TYPE_GHOST_PAD, - "name", name, - "direction", GST_PAD_DIRECTION (target), - "template", GST_PAD_PAD_TEMPLATE (target), "target", target, NULL); + if ((ret = gst_ghost_pad_new_notarget (name, GST_PAD_DIRECTION (target)))) { + g_object_set (G_OBJECT (ret), + "template", GST_PAD_PAD_TEMPLATE (target), NULL); + gst_ghost_pad_set_target (GST_GHOST_PAD (ret), target); - gst_pad_set_activatepush_function (ret, gst_ghost_pad_do_activate_push); - gst_pad_set_link_function (ret, gst_ghost_pad_do_link); - gst_pad_set_unlink_function (ret, gst_ghost_pad_do_unlink); + * gst_ghost_pad_get_target: + * @gpad: the #GstGhostpad + * Get the target pad of #gpad. Unref after usage. + * Returns: the target #GstPad, can be NULL if the ghostpad + * has no target set. Unref after usage. +gst_ghost_pad_get_target (GstGhostPad * gpad) + g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL); - return ret; + return gst_proxy_pad_get_target (GST_PAD_CAST (gpad)); + * gst_ghost_pad_set_target: + * @newtarget: the new pad target + * Set the new target of the ghostpad @gpad. Any existing target + * is unlinked. + * Returns: TRUE if the new target could be set, FALSE otherwise. +gboolean +gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget) + g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE); + return gst_proxy_pad_set_target (GST_PAD_CAST (gpad), newtarget); Index: gstghostpad.h RCS file: /cvs/gstreamer/gstreamer/gst/gstghostpad.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- gstghostpad.h 8 Jun 2005 22:16:27 -0000 1.1 +++ gstghostpad.h 29 Jul 2005 19:22:28 -0000 1.2 @@ -31,23 +31,23 @@ G_BEGIN_DECLS #define GST_TYPE_GHOST_PAD (gst_ghost_pad_get_type ()) #define GST_IS_GHOST_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GHOST_PAD)) #define GST_IS_GHOST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GHOST_PAD)) #define GST_GHOST_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GHOST_PAD, GstGhostPad)) #define GST_GHOST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GHOST_PAD, GstGhostPadClass)) typedef struct _GstGhostPad GstGhostPad; typedef struct _GstGhostPadClass GstGhostPadClass; GType gst_ghost_pad_get_type (void); GstPad* gst_ghost_pad_new (const gchar *name, GstPad *target); +GstPad* gst_ghost_pad_new_notarget (const gchar *name, GstPadDirection dir); +GstPad* gst_ghost_pad_get_target (GstGhostPad *gpad); +gboolean gst_ghost_pad_set_target (GstGhostPad *gpad, GstPad *newtarget); G_END_DECLS #endif /* __GST_GHOST_PAD_H__ */ Index: ChangeLog RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.1316 retrieving revision 1.1317 diff -u -d -r1.1316 -r1.1317 --- ChangeLog 29 Jul 2005 19:19:29 -0000 1.1316 +++ ChangeLog 29 Jul 2005 19:22:27 -0000 1.1317 @@ -1,5 +1,33 @@ 2005-07-29 Wim Taymans <wi...@fl...> + * check/gst/gstghostpad.c: (GST_START_TEST), (gst_ghost_pad_suite): + Added test for removing an element with ghostpad from a bin. + Fixed test as current implementation does the right thing. + * gst/gstghostpad.c: (gst_proxy_pad_class_init), + (gst_proxy_pad_do_query_type), (gst_proxy_pad_do_event), + (gst_proxy_pad_do_query), (gst_proxy_pad_do_internal_link), + (gst_proxy_pad_do_bufferalloc), (gst_proxy_pad_do_activate), + (gst_proxy_pad_do_activatepull), (gst_proxy_pad_do_activatepush), + (gst_proxy_pad_do_chain), (gst_proxy_pad_do_getrange), + (gst_proxy_pad_do_checkgetrange), (gst_proxy_pad_do_getcaps), + (gst_proxy_pad_do_acceptcaps), (gst_proxy_pad_do_fixatecaps), + (gst_proxy_pad_do_setcaps), (gst_proxy_pad_set_target), + (gst_proxy_pad_get_target), (gst_proxy_pad_init), + (gst_proxy_pad_dispose), (gst_proxy_pad_finalize), + (gst_ghost_pad_class_init), (gst_ghost_pad_do_activate_push), + (gst_ghost_pad_do_link), (gst_ghost_pad_do_unlink), + (gst_ghost_pad_set_internal), (gst_ghost_pad_dispose), + (gst_ghost_pad_new_notarget), (gst_ghost_pad_new), + (gst_ghost_pad_get_target), (gst_ghost_pad_set_target): + * gst/gstghostpad.h: + Clean up ghostpads, remove properties for internal stuff. + Make threadsafe. + Fix refcounting. + Prepare for switching targets, not all use cases work yet. +2005-07-29 Wim Taymans <wi...@fl...> * docs/design/part-gstghostpad.txt: Small update. RCS file: /cvs/gstreamer/gstreamer/check/gst/gstghostpad.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- gstghostpad.c 28 Jul 2005 11:24:33 -0000 1.6 +++ gstghostpad.c 29 Jul 2005 19:22:28 -0000 1.7 @@ -70,6 +70,46 @@ GST_END_TEST; +/* test if removing a bin also cleans up the ghostpads +GST_START_TEST (test_remove2) + GstElement *b1, *b2, *src, *sink; + GstPad *srcpad, *sinkpad; + b1 = gst_element_factory_make ("pipeline", NULL); + b2 = gst_element_factory_make ("bin", NULL); + src = gst_element_factory_make ("fakesrc", NULL); + sink = gst_element_factory_make ("fakesink", NULL); + fail_unless (gst_bin_add (GST_BIN (b2), sink)); + fail_unless (gst_bin_add (GST_BIN (b1), src)); + fail_unless (gst_bin_add (GST_BIN (b1), b2)); + sinkpad = gst_element_get_pad (sink, "sink"); + gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad)); + gst_object_unref (sinkpad); + srcpad = gst_element_get_pad (src, "src"); + /* get the ghostpad */ + sinkpad = gst_element_get_pad (b2, "sink"); + ret = gst_pad_link (srcpad, sinkpad); + fail_unless (ret == GST_PAD_LINK_OK); + gst_object_unref (srcpad); + /* now remove the sink from the bin */ + gst_bin_remove (GST_BIN (b2), sink); + /* pad is still linked to ghostpad */ + fail_if (!gst_pad_is_linked (srcpad)); +GST_END_TEST; /* test if linking fails over different bins using a pipeline * like this: @@ -186,23 +226,16 @@ /* 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 (gisrc, 1); /* gsink */ assert_gstrefcount (isink, 2); /* gsink */ - assert_gstrefcount (gisink, 2); /* gsrc -- fixme drop ref in unlink */ + assert_gstrefcount (gisink, 1); /* gsrc */ assert_gstrefcount (isrc, 2); /* gsrc */ - /* while the fixme isn't fixed, check cleanup */ gst_object_unref (gsink); assert_gstrefcount (isink, 1); assert_gstrefcount (gisrc, 1); @@ -216,6 +249,11 @@ assert_gstrefcount (fsink, 2); /* gisrc */ gst_object_unref (gisink); assert_gstrefcount (fsink, 1); + gst_object_unref (fsrc); + gst_object_unref (isrc); + gst_object_unref (isink); + gst_object_unref (fsink); @@ -228,6 +266,7 @@ suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_remove1); + tcase_add_test (tc_chain, test_remove2); tcase_add_test (tc_chain, test_link); tcase_add_test (tc_chain, test_ghost_pads); |
From: <wt...@fr...> - 2005-09-27 16:16:56
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Tue Sep 27 2005 09:16:51 PDT Log message: * check/gst/gstbin.c: (GST_START_TEST): Enable check that works now. * gst/gstbin.c: (add_to_queue), (clear_queue), (reset_outdegree), (update_outdegree), (find_element), (gst_bin_sort_iterator_next), (gst_bin_sort_iterator_resync), (gst_bin_sort_iterator_free), (gst_bin_iterate_sorted), (gst_bin_element_set_state), (gst_bin_change_state): * gst/gstbin.h: Redid the state change algorithm using a topological sort algo. Handles all cases correctly. Exposed iterator for state change order. * gst/gstelement.h: Temp storage for state changes. Need to get rid of this soon. Modified files: . : ChangeLog check/gst : gstbin.c gst : gstbin.c gstbin.h gstelement.h Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.1578&r2=1.1579 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/gst/gstbin.c.diff?r1=1.28&r2=1.29 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstbin.c.diff?r1=1.265&r2=1.266 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstbin.h.diff?r1=1.78&r2=1.79 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstelement.h.diff?r1=1.208&r2=1.209 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.1578 retrieving revision 1.1579 diff -u -d -r1.1578 -r1.1579 --- ChangeLog 27 Sep 2005 15:37:39 -0000 1.1578 +++ ChangeLog 27 Sep 2005 16:16:38 -0000 1.1579 @@ -1,5 +1,23 @@ 2005-09-27 Wim Taymans <wi...@fl...> + * check/gst/gstbin.c: (GST_START_TEST): + Enable check that works now. + + * gst/gstbin.c: (add_to_queue), (clear_queue), (reset_outdegree), + (update_outdegree), (find_element), (gst_bin_sort_iterator_next), + (gst_bin_sort_iterator_resync), (gst_bin_sort_iterator_free), + (gst_bin_iterate_sorted), (gst_bin_element_set_state), + (gst_bin_change_state): + * gst/gstbin.h: + Redid the state change algorithm using a topological sort algo. + Handles all cases correctly. + Exposed iterator for state change order. + * gst/gstelement.h: + Temp storage for state changes. Need to get rid of this soon. +2005-09-27 Wim Taymans <wi...@fl...> * gst/elements/gsttee.c: (gst_tee_init), (gst_tee_do_push): * gst/gstutils.c: (intersect_caps_func), (gst_pad_proxy_getcaps), (link_fold_func), (gst_pad_proxy_setcaps): Index: gstbin.c RCS file: /cvs/gstreamer/gstreamer/check/gst/gstbin.c,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- gstbin.c 26 Sep 2005 18:22:07 -0000 1.28 +++ gstbin.c 27 Sep 2005 16:16:38 -0000 1.29 @@ -630,8 +630,6 @@ GST_START_TEST (test_children_state_change_order_two_sink) { - /* current algorithm does not handle these state changes correct */ -#if 0 GstElement *src, *tee, *identity, *sink1, *sink2, *pipeline; GstStateChangeReturn ret; GstBus *bus; @@ -721,7 +719,6 @@ ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1); gst_object_unref (pipeline); -#endif } GST_END_TEST; RCS file: /cvs/gstreamer/gstreamer/gst/gstbin.c,v retrieving revision 1.265 retrieving revision 1.266 diff -u -d -r1.265 -r1.266 --- gstbin.c 27 Sep 2005 09:57:19 -0000 1.265 +++ gstbin.c 27 Sep 2005 16:16:39 -0000 1.266 @@ -824,62 +824,6 @@ return is_sink ? 0 : 1; -/* returns 0 when TRUE because this is a GCompareFunc. - * This function returns elements that have no connected srcpads and - * are therefore not reachable from a real sink. */ -/* MT safe */ -static gint -bin_element_is_semi_sink (GstElement * child, GstBin * bin) -{ - int ret = 1; - - /* we lock the child here for the remainder of the function to - * get its pads and name safely. */ - GST_LOCK (child); - /* check if this is a sink element, these are the elements - * without (linked) source pads. */ - if (child->numsrcpads == 0) { - /* shortcut */ - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin, - "adding child %s as sink", GST_OBJECT_NAME (child)); - ret = 0; - } else { - /* loop over all pads, try to figure out if this element - * is a semi sink because it has no linked source pads */ - GList *pads; - gboolean connected_src = FALSE; - for (pads = child->srcpads; pads; pads = g_list_next (pads)) { - GstPad *peer; - GST_DEBUG ("looking at pad %p", pads->data); - if ((peer = gst_pad_get_peer (GST_PAD_CAST (pads->data)))) { - connected_src = - gst_object_has_ancestor (GST_OBJECT_CAST (peer), - GST_OBJECT_CAST (bin)); - gst_object_unref (peer); - if (connected_src) { - break; - } - } - } - if (connected_src) { - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin, - "not adding child %s as sink: linked source pads", - GST_OBJECT_NAME (child)); - } else { - "adding child %s as sink since it has unlinked source pads in this bin", - ret = 0; - } - GST_UNLOCK (child); - return ret; -} static gint sink_iterator_filter (GstElement * child, GstBin * bin) @@ -1106,90 +1050,272 @@ return ret; +/*********************************************** + * Topologically sorted iterator + * see http://en.wikipedia.org/wiki/Topological_sorting + */ +typedef struct _GstBinSortIterator +{ + GstIterator it; + GQueue *queue; + GstBin *bin; + gint mode; + GstElement *best; +} GstBinSortIterator; +/* add element to queue of next elements in the iterator. + * We push at the tail to give higher priority elements a + * chance first */ +static void +add_to_queue (GQueue * queue, GstElement * element) + GST_DEBUG ("%s add to queue", GST_ELEMENT_NAME (element)); + gst_object_ref (element); + g_queue_push_tail (queue, element); + element->outdegree = -1; +} +/* clear the queue, unref all objects as we took a ref when + * we added them to the queue */ +clear_queue (GQueue * queue) + gpointer p; + while ((p = g_queue_pop_head (queue))) + gst_object_unref (p); +/* set all outdegrees to 0. Elements marked as a sink are + * added to the queue immediatly. */ +reset_outdegree (GstElement * element, GstBinSortIterator * bit) + /* sinks are added right away */ + if (GST_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK)) { + add_to_queue (bit->queue, element); + } else { + /* others are marked with 0 and handled when sinks are done */ + element->outdegree = 0; + } +/* adjust the outdegree of all elements connected to the given + * element. If an outdegree of an element drops to 0, it is + * added to the queue of elements to schedule next. + * + * We have to make sure not to cross the bin boundary this element + * belongs to. +update_outdegree (GstElement * element, GstBinSortIterator * bit) + gboolean linked = FALSE; + GST_LOCK (element); + /* don't touch outdegree is element has no sourcepads */ + if (element->numsinkpads != 0) { + /* loop over all sinkpads, decrement outdegree for all connected + * elements in this bin */ + GList *pads; + for (pads = element->sinkpads; pads; pads = g_list_next (pads)) { + GstPad *peer; + if ((peer = gst_pad_get_peer (GST_PAD_CAST (pads->data)))) { + GstElement *peer_element; + if ((peer_element = gst_pad_get_parent_element (peer))) { + GST_LOCK (peer_element); + if (GST_OBJECT_CAST (peer_element)->parent == + GST_OBJECT_CAST (bit->bin)) { + GST_DEBUG ("change element %s, degree %d->%d, linked to %s", + GST_ELEMENT_NAME (peer_element), + peer_element->outdegree, peer_element->outdegree + bit->mode, + GST_ELEMENT_NAME (element)); + /* update outdegree */ + peer_element->outdegree += bit->mode; + if (peer_element->outdegree == 0) { + /* outdegree hit 0, add to queue */ + add_to_queue (bit->queue, peer_element); + } + linked = TRUE; + } + GST_UNLOCK (peer_element); + gst_object_unref (peer_element); + } + gst_object_unref (peer); + } + } + if (!linked) { + GST_DEBUG ("element %s not linked to anything", GST_ELEMENT_NAME (element)); + GST_UNLOCK (element); +/* find the next best element not handled yet. This is the one + * with the lowest non-negative outdegree */ +find_element (GstElement * element, GstBinSortIterator * bit) + gint outdegree; + /* element is already handled */ + if ((outdegree = element->outdegree) < 0) + return; + /* first element or element with smaller outdegree */ + if (bit->best == NULL || bit->best->outdegree > outdegree) { + bit->best = element; +/* get next element in iterator. the returned element has the + * refcount increased */ +static GstIteratorResult +gst_bin_sort_iterator_next (GstBinSortIterator * bit, gpointer * result) + /* empty queue, we have to find a next best element */ + if (g_queue_is_empty (bit->queue)) { + bit->best = NULL; + g_list_foreach (bit->bin->children, (GFunc) find_element, bit); + if (bit->best) { + if (bit->best->outdegree != 0) { + /* we don't fail on this one yet */ + g_warning ("loop detected in the graph !!"); + /* best unhandled elements, add to queue */ + GST_DEBUG ("queue empty, next best: %s", GST_ELEMENT_NAME (bit->best)); + gst_object_ref (bit->best); + bit->best->outdegree = -1; + *result = bit->best; + } else { + GST_DEBUG ("queue empty, elements exhausted"); + /* no more unhandled elements, we are done */ + return GST_ITERATOR_DONE; + /* everything added to the queue got reffed */ + *result = g_queue_pop_head (bit->queue); + GST_DEBUG ("queue head gives %s", GST_ELEMENT_NAME (*result)); + /* update outdegrees of linked elements */ + update_outdegree (GST_ELEMENT_CAST (*result), bit); + return GST_ITERATOR_OK; +/* clear queues, recalculate the outdegrees and restart. */ +gst_bin_sort_iterator_resync (GstBinSortIterator * bit) + clear_queue (bit->queue); + /* reset outdegrees */ + g_list_foreach (bit->bin->children, (GFunc) reset_outdegree, bit); + /* calc outdegrees, incrementing */ + bit->mode = 1; + g_list_foreach (bit->bin->children, (GFunc) update_outdegree, bit); + /* for the rest of the function we decrement the outdegrees */ + bit->mode = -1; +/* clear queues, unref bin and free iterator. */ +gst_bin_sort_iterator_free (GstBinSortIterator * bit) + g_queue_free (bit->queue); + gst_object_unref (bit->bin); + g_free (bit); /** - * gst_bin_iterate_state_order: + * gst_bin_iterate_sorted: * @bin: #Gstbin to iterate on * - * Get an iterator for the elements in this bin in the order - * in which a state change should be performed on them. This - * means that first the sinks and then the other elements will - * be returned. + * Get an iterator for the elements in this bin in topologically + * sorted order. This means that the elements are returned from + * the most downstream elements (sinks) to the sources. + * This function is used internally to perform the state changes + * of the bin elements. * Each element will have its refcount increased, so unref * after use. - * Not implemented yet. + * MT safe. - * MT safe. + * FIXME: No two iterators can run at the same time since the iterators + * use a shared element field. * Returns: a #GstIterator of #GstElements. gst_iterator_free after use. */ GstIterator * -gst_bin_iterate_state_order (GstBin * bin) +gst_bin_iterate_sorted (GstBin * bin) - GstIterator *result; + GstBinSortIterator *result; g_return_val_if_fail (GST_IS_BIN (bin), NULL); - result = NULL; + GST_LOCK (bin); + gst_object_ref (bin); + /* we don't need a NextFunction because we ref the items in the _next + * method already */ + result = (GstBinSortIterator *) + gst_iterator_new (sizeof (GstBinSortIterator), + GST_GET_LOCK (bin), + &bin->children_cookie, + (GstIteratorNextFunction) gst_bin_sort_iterator_next, + (GstIteratorItemFunction) NULL, + (GstIteratorResyncFunction) gst_bin_sort_iterator_resync, + (GstIteratorFreeFunction) gst_bin_sort_iterator_free); + result->queue = g_queue_new (); + result->bin = bin; + gst_bin_sort_iterator_resync (result); + GST_UNLOCK (bin); - return result; + return (GstIterator *) result; -static void -clear_queue (GQueue * queue, gboolean unref) +static GstStateChangeReturn +gst_bin_element_set_state (GstBin * bin, GstElement * element, GstState pending) - gpointer p; - while ((p = g_queue_pop_head (queue))) - if (unref) - gst_object_unref (p); + GstStateChangeReturn ret; + gboolean locked; -remove_all_from_queue (GQueue * queue, gpointer elem, gboolean unref) + /* peel off the locked flag */ + locked = GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE); - while ((p = g_queue_find (queue, elem))) { - gst_object_unref (elem); - g_queue_delete_link (queue, p); + /* skip locked elements */ + if (G_UNLIKELY (locked)) { + ret = GST_STATE_CHANGE_SUCCESS; + goto done; } + /* change state */ + ret = gst_element_set_state (element, pending); +done: + return ret; -/* this function is called with the STATE_LOCK held. It works - * as follows: - * - * 1) put all sink elements on the queue. - * 2) put all semisink elements on the queue. - * 3) change state of elements in queue, put linked elements to queue. - * 4) while queue not empty goto 3) - * This will effectively change the state of all elements in the bin - * from the sinks to the sources. We have to change the states this - * way so that when a source element pushes data, the downstream element - * is in the right state to receive the data. - */ -/* FIXME, make me more elegant, want to use a topological sort algorithm - * based on indegrees (or outdegrees in our case) */ static GstStateChangeReturn gst_bin_change_state (GstElement * element, GstStateChange transition) GstBin *bin; GstState old_state, pending; - gboolean have_async = FALSE; - gboolean have_no_preroll = FALSE; - GList *children; - guint32 children_cookie; - GQueue *elem_queue; /* list of elements waiting for a state change */ - GQueue *semi_queue; /* list of elements with no connected srcpads */ - GQueue *temp; /* queue of leftovers */ + gboolean have_async; + gboolean have_no_preroll; GstClockTime base_time; - bin = GST_BIN (element); + GstIterator *it; + gboolean done; /* we don't need to take the STATE_LOCK, it is already taken */ old_state = GST_STATE (element); @@ -1203,220 +1329,84 @@ if (pending == GST_STATE_VOID_PENDING) return GST_STATE_CHANGE_SUCCESS; + bin = GST_BIN_CAST (element); /* Clear eosed element list on READY-> PAUSED */ if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) { g_list_free (bin->eosed); bin->eosed = NULL; - /* all elements added to these queues should have their refcount - * incremented */ - elem_queue = g_queue_new (); - semi_queue = g_queue_new (); - temp = g_queue_new (); - /* first step, find all sink elements, these are the elements - GST_LOCK (bin); + /* iterate in state change order */ + it = gst_bin_iterate_sorted (bin); restart: /* take base time */ base_time = element->base_time; - /* make sure queues are empty, they could be filled when - * restarting. */ - clear_queue (elem_queue, TRUE); - clear_queue (semi_queue, TRUE); - clear_queue (temp, TRUE); - children = bin->children; - children_cookie = bin->children_cookie; - GST_DEBUG_OBJECT (bin, "reffing and examining children"); - while (children) { - GstElement *child = GST_ELEMENT_CAST (children->data); - gst_object_ref (child); - GST_UNLOCK (bin); - if (bin_element_is_sink (child, bin) == 0) { - g_queue_push_tail (elem_queue, child); - } else if (bin_element_is_semi_sink (child, bin) == 0) { - g_queue_push_tail (semi_queue, child); - g_queue_push_tail (temp, child); - GST_LOCK (bin); - if (G_UNLIKELY (children_cookie != bin->children_cookie)) { - GST_INFO_OBJECT (bin, "bin->children_cookie changed, restarting"); - /* restart will unref the children in the queues so that we don't - * leak refcounts. */ - goto restart; - children = g_list_next (children); - GST_DEBUG_OBJECT (bin, "reffed and examined children"); - GST_UNLOCK (bin); - /* after this point new elements can be added/removed from the - * bin. We operate on the snapshot taken above. Applications - * should serialize their add/remove and set_state. */ - /* if we don't have real sinks, we continue with the other elements, there - * has to be at least one element in the semi queue. */ - if (g_queue_is_empty (elem_queue) && !g_queue_is_empty (semi_queue)) { - GQueue *q = elem_queue; - /* we swap the queues as oposed to copy them over */ - elem_queue = semi_queue; - semi_queue = q; - /* second step, change state of elements in the queue */ - GST_DEBUG_OBJECT (bin, "change state of elements in the queue"); - while (!g_queue_is_empty (elem_queue)) { - GstElement *qelement; - gboolean locked; - /* take element */ - qelement = g_queue_pop_head (elem_queue); - /* we don't need any duplicates in the other queue anymore */ - remove_all_from_queue (semi_queue, qelement, TRUE); - remove_all_from_queue (temp, qelement, TRUE); - /* queue all elements connected to the sinkpads of this element */ - GST_LOCK (qelement); - pads = qelement->sinkpads; - while (pads) { - GstPad *pad = GST_PAD_CAST (pads->data); - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "found sinkpad %s:%s", GST_DEBUG_PAD_NAME (pad)); + have_async = FALSE; + have_no_preroll = FALSE; - peer = gst_pad_get_peer (pad); - if (peer) { - GstObject *peer_parent; + done = FALSE; + while (!done) { + gpointer data; - /* get parent */ - peer_parent = gst_object_get_parent (GST_OBJECT (peer)); + switch (gst_iterator_next (it, &data)) { + case GST_ITERATOR_OK: + { + GstElement *element; - /* if we have an element parent, follow it */ - if (peer_parent && GST_IS_ELEMENT (peer_parent)) { - GstObject *parent; + element = GST_ELEMENT_CAST (data); - /* see if this element is in the bin we are currently handling */ - parent = gst_object_get_parent (peer_parent); - if (parent) { - if (parent == GST_OBJECT_CAST (bin)) { - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "adding element %s to queue", GST_ELEMENT_NAME (peer_parent)); + /* set base time on element */ + gst_element_set_base_time (element, base_time); - /* make sure we don't have duplicates */ - remove_all_from_queue (semi_queue, peer_parent, TRUE); - remove_all_from_queue (elem_queue, peer_parent, TRUE); - remove_all_from_queue (temp, peer_parent, TRUE); + /* set state now */ + ret = gst_bin_element_set_state (bin, element, pending); - /* was reffed before pushing on the queue by the - * gst_object_get_parent() call we used to get the element. */ - g_queue_push_tail (elem_queue, peer_parent); - /* so that we don't unref it */ - peer_parent = NULL; - } else { - "not adding element %s to queue, it is in another bin", - GST_ELEMENT_NAME (peer_parent)); - } - gst_object_unref (parent); - } + switch (ret) { + case GST_STATE_CHANGE_SUCCESS: + GST_CAT_DEBUG (GST_CAT_STATES, + "child '%s' changed state to %d(%s) successfully", + GST_ELEMENT_NAME (element), pending, + gst_element_state_get_name (pending)); + break; + case GST_STATE_CHANGE_ASYNC: + GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, + "child '%s' is changing state asynchronously", + have_async = TRUE; + case GST_STATE_CHANGE_FAILURE: + "child '%s' failed to go to state %d(%s)", + GST_ELEMENT_NAME (element), + pending, gst_element_state_get_name (pending)); + gst_object_unref (element); + goto done; + case GST_STATE_CHANGE_NO_PREROLL: + "child '%s' changed state to %d(%s) successfully without preroll", + have_no_preroll = TRUE; + default: + g_assert_not_reached (); } - if (peer_parent) - gst_object_unref (peer_parent); - } else { - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "pad %s:%s does not have a peer", GST_DEBUG_PAD_NAME (pad)); - pads = g_list_next (pads); - /* peel off the locked flag and release the element lock */ - locked = GST_FLAG_IS_SET (qelement, GST_ELEMENT_LOCKED_STATE); - GST_UNLOCK (qelement); - /* skip locked elements */ - if (G_UNLIKELY (locked)) - goto next_element; - /* set base time on element */ - gst_element_set_base_time (qelement, base_time); - /* then change state */ - ret = gst_element_set_state (qelement, pending); - /* the set state could have cause elements to be added/removed, - * we support that. */ - gst_object_unref (qelement); - switch (ret) { - case GST_STATE_CHANGE_SUCCESS: - GST_CAT_DEBUG (GST_CAT_STATES, - "child '%s' changed state to %d(%s) successfully", - GST_ELEMENT_NAME (qelement), pending, - gst_element_state_get_name (pending)); - break; - case GST_STATE_CHANGE_ASYNC: - GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, - "child '%s' is changing state asynchronously", - GST_ELEMENT_NAME (qelement)); - have_async = TRUE; + gst_object_unref (element); break; - case GST_STATE_CHANGE_FAILURE: - "child '%s' failed to go to state %d(%s)", - GST_ELEMENT_NAME (qelement), - pending, gst_element_state_get_name (pending)); - ret = GST_STATE_CHANGE_FAILURE; - /* release refcount of element we popped off the queue */ - gst_object_unref (qelement); - goto exit; - case GST_STATE_CHANGE_NO_PREROLL: - "child '%s' changed state to %d(%s) successfully without preroll", - have_no_preroll = TRUE; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (it); + goto restart; default: - g_assert_not_reached (); + case GST_ITERATOR_DONE: + done = TRUE; } - next_element: - gst_object_unref (qelement); - /* if queue is empty now, continue with a non-sink */ - if (g_queue_is_empty (elem_queue)) { - GstElement *non_sink; - GST_DEBUG ("sinks and upstream elements exhausted"); - non_sink = g_queue_pop_head (semi_queue); - if (non_sink) { - GST_DEBUG ("found lefover semi-sink %s", GST_OBJECT_NAME (non_sink)); - g_queue_push_tail (elem_queue, non_sink); - non_sink = g_queue_pop_head (temp); - if (non_sink) { - GST_DEBUG ("found lefover non-sink %s", GST_OBJECT_NAME (non_sink)); - g_queue_push_tail (elem_queue, non_sink); if (have_no_preroll) { @@ -1427,21 +1417,14 @@ ret = parent_class->change_state (element, transition); GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "done changing bin's state from %s to %s, now in %s, ret %d", gst_element_state_get_name (old_state), gst_element_state_get_name (pending), gst_element_state_get_name (GST_STATE (element)), ret); -exit: - /* release refcounts in queue, should normally be empty unless we - * had an error. */ - g_queue_free (elem_queue); - g_queue_free (semi_queue); - g_queue_free (temp); + gst_iterator_free (it); Index: gstbin.h RCS file: /cvs/gstreamer/gstreamer/gst/gstbin.h,v retrieving revision 1.78 retrieving revision 1.79 diff -u -d -r1.78 -r1.79 --- gstbin.h 11 Sep 2005 12:57:36 -0000 1.78 +++ gstbin.h 27 Sep 2005 16:16:39 -0000 1.79 @@ -127,6 +127,7 @@ /* retrieve multiple children */ GstIterator* gst_bin_iterate_elements (GstBin *bin); +GstIterator* gst_bin_iterate_sorted (GstBin *bin); GstIterator* gst_bin_iterate_recurse (GstBin *bin); GstIterator* gst_bin_iterate_sinks (GstBin *bin); Index: gstelement.h RCS file: /cvs/gstreamer/gstreamer/gst/gstelement.h,v retrieving revision 1.208 retrieving revision 1.209 diff -u -d -r1.208 -r1.209 --- gstelement.h 23 Sep 2005 16:35:43 -0000 1.208 +++ gstelement.h 27 Sep 2005 16:16:39 -0000 1.209 @@ -304,6 +304,10 @@ GList *sinkpads; guint32 pads_cookie; + /* used in bin state change to calculate number of connections + * on the srcpad */ + gint outdegree; /*< private >*/ gpointer _gst_reserved[GST_PADDING]; }; |
From: <wt...@fr...> - 2005-09-29 09:39:49
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Thu Sep 29 2005 02:39:48 PDT Log message: * check/gst/gstbin.c: (GST_START_TEST): Add bus to bin. * gst/gstbin.c: (gst_bin_class_init), (gst_bin_init), (add_to_queue), (clear_queue), (reset_degree), (update_degree), (find_element), (gst_bin_sort_iterator_next), (gst_bin_sort_iterator_resync), (gst_bin_sort_iterator_free), (gst_bin_iterate_sorted), (gst_bin_element_set_state), (gst_bin_change_state), (gst_bin_dispose): A bin does not have a bus, it gets the bus from the parent. * gst/gstelement.c: (gst_element_requires_clock), (gst_element_provides_clock), (gst_element_is_indexable), (gst_element_is_locked_state), (gst_element_change_state), (gst_element_set_bus_func): Small cleanups. * gst/gstpipeline.c: (gst_pipeline_class_init), (gst_pipeline_init), (gst_pipeline_provide_clock_func): The pipeline provides a bus. Modified files: . : ChangeLog check/gst : gstbin.c gst : gstbin.c gstelement.c gstpipeline.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.1594&r2=1.1595 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/gst/gstbin.c.diff?r1=1.29&r2=1.30 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstbin.c.diff?r1=1.270&r2=1.271 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstelement.c.diff?r1=1.368&r2=1.369 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstpipeline.c.diff?r1=1.111&r2=1.112 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.1594 retrieving revision 1.1595 diff -u -d -r1.1594 -r1.1595 --- ChangeLog 29 Sep 2005 02:32:37 -0000 1.1594 +++ ChangeLog 29 Sep 2005 09:39:35 -0000 1.1595 @@ -1,3 +1,26 @@ +2005-09-29 Wim Taymans <wi...@fl...> + + * check/gst/gstbin.c: (GST_START_TEST): + Add bus to bin. + * gst/gstbin.c: (gst_bin_class_init), (gst_bin_init), + (add_to_queue), (clear_queue), (reset_degree), (update_degree), + (find_element), (gst_bin_sort_iterator_next), + (gst_bin_sort_iterator_resync), (gst_bin_sort_iterator_free), + (gst_bin_iterate_sorted), (gst_bin_element_set_state), + (gst_bin_change_state), (gst_bin_dispose): + A bin does not have a bus, it gets the bus from the parent. + * gst/gstelement.c: (gst_element_requires_clock), + (gst_element_provides_clock), (gst_element_is_indexable), + (gst_element_is_locked_state), (gst_element_change_state), + (gst_element_set_bus_func): + Small cleanups. + * gst/gstpipeline.c: (gst_pipeline_class_init), + (gst_pipeline_init), (gst_pipeline_provide_clock_func): + The pipeline provides a bus. 2005-09-28 Johan Dahlin <jo...@gn...> * gst/gstmessage.c (gst_message_parse_state_changed): Use Index: gstbin.c RCS file: /cvs/gstreamer/gstreamer/check/gst/gstbin.c,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- gstbin.c 27 Sep 2005 16:16:38 -0000 1.29 +++ gstbin.c 29 Sep 2005 09:39:36 -0000 1.30 @@ -114,7 +114,8 @@ fail_unless (bin != NULL, "Could not create bin"); ASSERT_OBJECT_REFCOUNT (bin, "bin", 1); - bus = GST_ELEMENT_BUS (bin); + bus = g_object_new (gst_bus_get_type (), NULL); + gst_element_set_bus (GST_ELEMENT_CAST (bin), bus); /* change state, spawning a message, causing an incref on the bin */ gst_element_set_state (GST_ELEMENT (bin), GST_STATE_READY); @@ -132,6 +133,7 @@ /* clean up */ + gst_object_unref (bus); gst_object_unref (bin); } @@ -148,14 +150,15 @@ src = gst_element_factory_make ("fakesrc", NULL); fail_if (src == NULL, "Could not create fakesrc"); gst_bin_add (bin, src); ASSERT_OBJECT_REFCOUNT (src, "src", 1); - /* change state, spawning two messages: * - first for fakesrc, forwarded to bin's bus, causing incref on fakesrc * - second for bin, causing an incref on the bin */ @@ -189,6 +192,7 @@ @@ -224,7 +228,7 @@ ASSERT_OBJECT_REFCOUNT (sink, "sink", 1); - bus = GST_ELEMENT_BUS (pipeline); + bus = gst_pipeline_get_bus (pipeline); /* change state to READY, spawning three messages */ GST_DEBUG ("setting pipeline to READY"); @@ -232,7 +236,7 @@ == GST_STATE_CHANGE_SUCCESS); /* each object is referenced by a message */ - ASSERT_OBJECT_REFCOUNT (bus, "bus", 1); + ASSERT_OBJECT_REFCOUNT (bus, "bus", 2); ASSERT_OBJECT_REFCOUNT (src, "src", 2); ASSERT_OBJECT_REFCOUNT (sink, "sink", 2); ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 2); @@ -240,7 +244,7 @@ pop_messages (bus, 3); fail_if ((gst_bus_pop (bus)) != NULL); ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1); @@ -260,7 +264,7 @@ @@ -279,7 +283,7 @@ /* sink might have an extra reference if it's still blocked on preroll */ ASSERT_OBJECT_REFCOUNT_BETWEEN (sink, "sink", 1, 2); @@ -311,6 +315,7 @@ gst_object_unref (pipeline); @@ -324,6 +329,9 @@ bin = gst_element_factory_make ("bin", NULL); sink = gst_element_factory_make ("fakesink", NULL); @@ -334,15 +342,13 @@ fail_unless (gst_element_link (src, sink), "could not link src and sink"); /* change state, spawning two times three messages, minus one async */ fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED) == GST_STATE_CHANGE_ASYNC); pop_messages (bus, 5); - fail_unless (gst_bus_have_pending (bus, GST_MESSAGE_ANY) == FALSE, + fail_unless (gst_bus_have_pending (bus) == FALSE, "Unexpected messages on bus"); gst_bin_watch_for_state_change (GST_BIN (bin)); @@ -350,7 +356,7 @@ /* should get the bin's state change message now */ pop_messages (bus, 1); fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING) @@ -365,7 +371,7 @@ /* setting bin to NULL flushes the bus automatically */ @@ -373,6 +379,7 @@ @@ -458,7 +465,7 @@ pipeline = gst_pipeline_new (NULL); fail_unless (pipeline != NULL, "Could not create pipeline"); + bus = gst_element_get_bus (pipeline); fail_unless (bus != NULL, "Pipeline has no bus?!"); @@ -531,6 +538,7 @@ @@ -548,7 +556,7 @@ @@ -623,6 +631,7 @@ @@ -637,7 +646,7 @@ @@ -718,6 +727,7 @@ ASSERT_OBJECT_REFCOUNT (sink2, "sink2", 1); RCS file: /cvs/gstreamer/gstreamer/gst/gstbin.c,v retrieving revision 1.270 retrieving revision 1.271 diff -u -d -r1.270 -r1.271 --- gstbin.c 28 Sep 2005 13:41:27 -0000 1.270 +++ gstbin.c 29 Sep 2005 09:39:36 -0000 1.271 @@ -273,16 +273,10 @@ bin->children_cookie = 0; bin->eosed = NULL; - /* Set up a bus for listening to child elements, - * and one for sending messages up the hierarchy */ + /* Set up a bus for listening to child elements */ bus = g_object_new (gst_bus_get_type (), NULL); bin->child_bus = bus; gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bin_bus_handler, bin); - bus = g_object_new (gst_bus_get_type (), NULL); - gst_element_set_bus (GST_ELEMENT (bin), bus); - /* set_bus refs the bus via gst_object_replace, we drop our ref */ - gst_object_unref (bus); /** @@ -1466,7 +1460,6 @@ gst_object_unref (bin->child_bus); bin->child_bus = NULL; - gst_element_set_bus (GST_ELEMENT (bin), NULL); while (bin->children) { gst_bin_remove (bin, GST_ELEMENT (bin->children->data)); Index: gstelement.c RCS file: /cvs/gstreamer/gstreamer/gst/gstelement.c,v retrieving revision 1.368 retrieving revision 1.369 diff -u -d -r1.368 -r1.369 --- gstelement.c 28 Sep 2005 13:41:27 -0000 1.368 +++ gstelement.c 29 Sep 2005 09:39:36 -0000 1.369 @@ -30,8 +30,8 @@ * * The name of a GstElement can be get with gst_element_get_name() and set with * gst_element_set_name(). For speed, GST_ELEMENT_NAME() can be used in the - * core. Do not use this in plug-ins or applications in order to retain ABI - * compatibility. + * core when using the appropriate locking. Do not use this in plug-ins or + * applications in order to retain ABI compatibility. * All elements have pads (of the type #GstPad). These pads link to pads on * other elements. Buffers flow between these linked pads. @@ -308,9 +308,9 @@ gboolean gst_element_requires_clock (GstElement * element) { - gboolean result = FALSE; + gboolean result; - g_return_val_if_fail (GST_IS_ELEMENT (element), result); + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); result = (GST_ELEMENT_GET_CLASS (element)->set_clock != NULL); @@ -330,7 +330,7 @@ gst_element_provides_clock (GstElement * element) g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); @@ -346,7 +346,7 @@ * Get the clock provided by the given element. * * Returns: the GstClock provided by the element or NULL - * if no clock could be provided. + * if no clock could be provided. Unref after usage. * MT safe. */ @@ -479,9 +479,9 @@ gst_element_is_indexable (GstElement * element) result = (GST_ELEMENT_GET_CLASS (element)->set_index != NULL); @@ -493,7 +493,8 @@ * @element: a #GstElement. * @index: a #GstIndex. - * Set the specified GstIndex on the element. + * Set the specified GstIndex on the element. The refcount of the index + * will be increased, any previously set index is unreffed. @@ -547,7 +548,8 @@ * see gst_object_set_parent() for refcounting information. * Pads are not automatically activated so elements should perform the needed - * steps to activate the pad. + * steps to activate the pad in case this pad is added in the PAUSED or PLAYING + * state. * The pad and the element should be unlocked when calling this function. @@ -912,7 +914,7 @@ return pad; -GstIteratorItem +static GstIteratorItem iterate_pad (GstIterator * it, GstPad * pad) gst_object_ref (pad); @@ -923,7 +925,8 @@ * gst_element_iterate_pads: * @element: a #GstElement to iterate pads of. - * Retrieves an iterattor of @element's pads. + * Retrieves an iterattor of @element's pads. The iterator should + * be freed after usage. * Returns: the #GstIterator of #GstPad. Unref each pad after use. @@ -1488,7 +1491,7 @@ gst_element_is_locked_state (GstElement * element) @@ -2038,15 +2041,8 @@ pending = GST_STATE_PENDING (element); /* if the element already is in the given state, we just return success */ - if (pending == GST_STATE_VOID_PENDING || state == GST_STATE_PENDING (element)) { - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "element is already in the %s state", - gst_element_state_get_name (state)); - if (GST_STATE_NO_PREROLL (element)) - return GST_STATE_CHANGE_NO_PREROLL; - else - return GST_STATE_CHANGE_SUCCESS; - } + if (pending == GST_STATE_VOID_PENDING || state == GST_STATE_PENDING (element)) + goto was_ok; GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "default handler tries setting state from %s to %s (%04x)", @@ -2072,9 +2068,7 @@ if (!gst_element_pads_activate (element, FALSE)) { result = GST_STATE_CHANGE_FAILURE; } else { - GST_LOCK (element); - element->base_time = 0; - GST_UNLOCK (element); + gst_element_set_base_time (element, 0); } break; default: @@ -2088,8 +2082,19 @@ gst_element_state_get_name (pending)); } return result; +was_ok: + { + GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, + "element is already in the %s state", + gst_element_state_get_name (state)); + if (GST_STATE_NO_PREROLL (element)) + return GST_STATE_CHANGE_NO_PREROLL; + else + return GST_STATE_CHANGE_SUCCESS; + } @@ -2098,7 +2103,8 @@ * Retrieves the factory that was used to create this element. - * Returns: the #GstElementFactory used for creating this element. + * Returns: the #GstElementFactory used for creating this element. + * no refcounting is needed. GstElementFactory * gst_element_get_factory (GstElement * element) @@ -2298,7 +2304,7 @@ GST_LOCK (element); gst_object_replace ((GstObject **) & GST_ELEMENT_BUS (element), - GST_OBJECT (bus)); + GST_OBJECT_CAST (bus)); GST_UNLOCK (element); Index: gstpipeline.c RCS file: /cvs/gstreamer/gstreamer/gst/gstpipeline.c,v retrieving revision 1.111 retrieving revision 1.112 diff -u -d -r1.111 -r1.112 --- gstpipeline.c 28 Sep 2005 13:41:27 -0000 1.111 +++ gstpipeline.c 29 Sep 2005 09:39:36 -0000 1.112 @@ -153,9 +153,14 @@ gst_pipeline_init (GTypeInstance * instance, gpointer g_class) GstPipeline *pipeline = GST_PIPELINE (instance); + GstBus *bus; pipeline->delay = DEFAULT_DELAY; pipeline->play_timeout = DEFAULT_PLAY_TIMEOUT; + gst_element_set_bus (GST_ELEMENT_CAST (pipeline), bus); static void |
From: <wt...@fr...> - 2005-09-29 13:08:14
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Thu Sep 29 2005 06:07:49 PDT Log message: * check/gst/gstbin.c: (GST_START_TEST): Change for new bus API. * check/gst/gstbus.c: (message_func_eos), (message_func_app), (send_messages), (GST_START_TEST), (gstbus_suite): Change for new bus signal API. * gst/gstbus.c: (gst_bus_class_init), (gst_bus_have_pending), (gst_bus_source_prepare), (gst_bus_source_check), (gst_bus_create_watch), (gst_bus_add_watch_full), (gst_bus_add_watch), (gst_bus_poll), (gst_bus_async_signal_func), (gst_bus_sync_signal_handler), (gst_bus_add_signal_watch): * gst/gstbus.h: Remove support for multiple GSources operating on different message types as it is too complex and unneeded when using signals. Added support for receiving signals from the bus. Modified files: . : ChangeLog check/gst : gstbin.c gstbus.c gst : gstbus.c gstbus.h Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.1599&r2=1.1600 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/gst/gstbin.c.diff?r1=1.31&r2=1.32 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/gst/gstbus.c.diff?r1=1.7&r2=1.8 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstbus.c.diff?r1=1.32&r2=1.33 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstbus.h.diff?r1=1.10&r2=1.11 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.1599 retrieving revision 1.1600 diff -u -d -r1.1599 -r1.1600 --- ChangeLog 29 Sep 2005 12:37:38 -0000 1.1599 +++ ChangeLog 29 Sep 2005 13:07:36 -0000 1.1600 @@ -1,3 +1,23 @@ +2005-09-29 Wim Taymans <wi...@fl...> + + * check/gst/gstbin.c: (GST_START_TEST): + Change for new bus API. + * check/gst/gstbus.c: (message_func_eos), (message_func_app), + (send_messages), (GST_START_TEST), (gstbus_suite): + Change for new bus signal API. + * gst/gstbus.c: (gst_bus_class_init), (gst_bus_have_pending), + (gst_bus_source_prepare), (gst_bus_source_check), + (gst_bus_create_watch), (gst_bus_add_watch_full), + (gst_bus_add_watch), (gst_bus_poll), (gst_bus_async_signal_func), + (gst_bus_sync_signal_handler), (gst_bus_add_signal_watch): + * gst/gstbus.h: + Remove support for multiple GSources operating on different + message types as it is too complex and unneeded when using + signals. + Added support for receiving signals from the bus. 2005-09-29 Thomas Vander Stichele <thomas at apestaart dot org> * docs/libs/tmpl/gstdataprotocol.sgml: Index: gstbus.c RCS file: /cvs/gstreamer/gstreamer/gst/gstbus.c,v retrieving revision 1.32 retrieving revision 1.33 diff -u -d -r1.32 -r1.33 --- gstbus.c 28 Sep 2005 16:43:20 -0000 1.32 +++ gstbus.c 29 Sep 2005 13:07:37 -0000 1.33 @@ -174,7 +174,7 @@ marshal_VOID__MINIOBJECT, G_TYPE_NONE, 1, GST_TYPE_MESSAGE); /** - * GstBus::async-message: + * GstBus::message: * @bus: the object which received the signal * @message: the message that has been posted asynchronously * @@ -182,9 +182,9 @@ * GSource added to the mainloop. */ gst_bus_signals[ASYNC_MESSAGE] = - g_signal_new ("async-message", G_TYPE_FROM_CLASS (klass), + g_signal_new ("message", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - G_STRUCT_OFFSET (GstBusClass, async_message), NULL, NULL, + G_STRUCT_OFFSET (GstBusClass, message), NULL, NULL, } @@ -381,10 +381,8 @@ /** * gst_bus_have_pending: * @bus: a #GstBus to check - * @events: a mask of #GstMessageType, representing the set of message types to - * watch for. * - * Check if there are pending messages on the bus of the given types that + * Check if there are pending messages on the bus that * should be handled. * Returns: TRUE if there are messages on the bus to be handled. @@ -392,21 +390,15 @@ * MT safe. */ gboolean -gst_bus_have_pending (GstBus * bus, GstMessageType events) +gst_bus_have_pending (GstBus * bus) { - GstMessage *message; gboolean result; g_return_val_if_fail (GST_IS_BUS (bus), FALSE); g_mutex_lock (bus->queue_lock); - /* see if there is a message on the bus that satisfies the - * event mask */ - message = g_queue_peek_head (bus->queue); - if (message) - result = (GST_MESSAGE_TYPE (message) & events) != 0; - else - result = FALSE; + /* see if there is a message on the bus */ + result = !g_queue_is_empty (bus->queue); g_mutex_unlock (bus->queue_lock); return result; @@ -537,7 +529,6 @@ GSource source; GstBus *bus; - GstMessageType events; } GstBusSource; static gboolean @@ -546,7 +537,7 @@ GstBusSource *bsrc = (GstBusSource *) source; *timeout = -1; - return gst_bus_have_pending (bsrc->bus, bsrc->events); + return gst_bus_have_pending (bsrc->bus); @@ -554,7 +545,7 @@ @@ -616,19 +607,15 @@ * gst_bus_create_watch: * @bus: a #GstBus to create the watch for - * Create watch for this bus. The source will only act on messages of the - * given types, messages of other types will simply remain on the bus and - * this GSource will not be dispatched again before the message is popped off - * the bus. For this reason one typically has a low priority GSource that - * pops all remaining messages from the bus not handled by the other GSources. + * Create watch for this bus. The GSource will be dispatched whenever + * a message is on the bus. After the GSource is dispatched, the + * message is popped off the bus and unreffed. * Returns: A #GSource that can be added to a mainloop. GSource * -gst_bus_create_watch (GstBus * bus, GstMessageType events) +gst_bus_create_watch (GstBus * bus) GstBusSource *source; @@ -638,7 +625,6 @@ sizeof (GstBusSource)); gst_object_ref (bus); source->bus = bus; - source->events = events; return (GSource *) source; @@ -647,8 +633,6 @@ * gst_bus_add_watch_full: * @bus: a #GstBus to create the watch for. * @priority: The priority of the watch. * @func: A function to call when a message is received. * @user_data: user data passed to @func. * @notify: the function to call when the source is removed. @@ -666,7 +650,7 @@ guint -gst_bus_add_watch_full (GstBus * bus, gint priority, GstMessageType events, +gst_bus_add_watch_full (GstBus * bus, gint priority, GstBusFunc func, gpointer user_data, GDestroyNotify notify) guint id; @@ -674,7 +658,7 @@ g_return_val_if_fail (GST_IS_BUS (bus), 0); - source = gst_bus_create_watch (bus, events); + source = gst_bus_create_watch (bus); if (priority != G_PRIORITY_DEFAULT) g_source_set_priority (source, priority); @@ -691,8 +675,6 @@ * gst_bus_add_watch: @@ -705,10 +687,9 @@ -gst_bus_add_watch (GstBus * bus, GstMessageType events, GstBusFunc func, - gpointer user_data) +gst_bus_add_watch (GstBus * bus, GstBusFunc func, gpointer user_data) - return gst_bus_add_watch_full (bus, G_PRIORITY_DEFAULT, events, func, + return gst_bus_add_watch_full (bus, G_PRIORITY_DEFAULT, func, user_data, NULL); @@ -811,7 +792,7 @@ else poll_data->timeout_id = 0; - id = gst_bus_add_watch_full (bus, G_PRIORITY_DEFAULT, GST_MESSAGE_ANY, + id = gst_bus_add_watch_full (bus, G_PRIORITY_DEFAULT, (GstBusFunc) poll_func, poll_data, (GDestroyNotify) poll_destroy); GST_DEBUG ("running mainloop %p", poll_data->loop); @@ -847,6 +828,9 @@ GQuark detail = 0; + g_return_val_if_fail (GST_IS_BUS (bus), TRUE); + g_return_val_if_fail (message != NULL, TRUE); detail = gst_message_type_to_quark (GST_MESSAGE_TYPE (message)); g_signal_emit (bus, gst_bus_signals[ASYNC_MESSAGE], detail, message); @@ -871,9 +855,34 @@ + g_return_val_if_fail (GST_IS_BUS (bus), GST_BUS_DROP); + g_return_val_if_fail (message != NULL, GST_BUS_DROP); g_signal_emit (bus, gst_bus_signals[SYNC_MESSAGE], detail, message); return GST_BUS_PASS; +/** + * gst_bus_add_signal_watch: + * @bus: a #GstBus to create the watch for + * + * Adds a bus signal watch to the default main context with the default priority. + * After calling this statement, the bus will emit the message signal for each + * message posted on the bus. + * The watch can be removed using #g_source_remove(). + * Returns: The event source id. + * MT safe. + */ +guint +gst_bus_add_signal_watch (GstBus * bus) +{ + g_return_val_if_fail (GST_IS_BUS (bus), 0); + return gst_bus_add_watch (bus, gst_bus_async_signal_func, NULL); +} Index: gstbus.h RCS file: /cvs/gstreamer/gstreamer/gst/gstbus.h,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- gstbus.h 28 Sep 2005 16:43:20 -0000 1.10 +++ gstbus.h 29 Sep 2005 13:07:37 -0000 1.11 @@ -103,8 +103,8 @@ GstObjectClass parent_class; /* signals */ - void (*sync_message) (GstBus *bus, GstMessage *message); - void (*async_message) (GstBus *bus, GstMessage *message); + void (*message) (GstBus *bus, GstMessage *message); + void (*sync_message) (GstBus *bus, GstMessage *message); /*< private > */ gpointer _gst_reserved[GST_PADDING]; @@ -116,7 +116,7 @@ gboolean gst_bus_post (GstBus * bus, GstMessage * message); -gboolean gst_bus_have_pending (GstBus * bus, GstMessageType events); +gboolean gst_bus_have_pending (GstBus * bus); GstMessage * gst_bus_peek (GstBus * bus); GstMessage * gst_bus_pop (GstBus * bus); void gst_bus_set_flushing (GstBus * bus, gboolean flushing); @@ -125,15 +125,13 @@ void gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func, gpointer data); /* GSource based dispatching */ -GSource * gst_bus_create_watch (GstBus * bus, GstMessageType events); +GSource * gst_bus_create_watch (GstBus * bus); guint gst_bus_add_watch_full (GstBus * bus, gint priority, - GstMessageType events, GstBusFunc func, gpointer user_data, GDestroyNotify notify); guint gst_bus_add_watch (GstBus * bus, gpointer user_data); @@ -146,6 +144,8 @@ gpointer data); GstBusSyncReply gst_bus_sync_signal_handler (GstBus *bus, GstMessage *message, +/* add watch that dispatches signals */ +guint gst_bus_add_signal_watch (GstBus * bus); G_END_DECLS Index: gstbin.c RCS file: /cvs/gstreamer/gstreamer/check/gst/gstbin.c,v retrieving revision 1.31 diff -u -d -r1.31 -r1.32 --- gstbin.c 29 Sep 2005 09:42:15 -0000 1.31 +++ gstbin.c 29 Sep 2005 13:07:37 -0000 1.32 @@ -348,7 +348,7 @@ pop_messages (bus, 5); - fail_unless (gst_bus_have_pending (bus, GST_MESSAGE_ANY) == FALSE, + fail_unless (gst_bus_have_pending (bus) == FALSE, "Unexpected messages on bus"); gst_bin_watch_for_state_change (GST_BIN (bin)); @@ -356,7 +356,7 @@ /* should get the bin's state change message now */ pop_messages (bus, 1); fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING) @@ -371,7 +371,7 @@ pop_messages (bus, 3); /* setting bin to NULL flushes the bus automatically */ RCS file: /cvs/gstreamer/gstreamer/check/gst/gstbus.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- gstbus.c 19 Sep 2005 11:18:03 -0000 1.7 +++ gstbus.c 29 Sep 2005 13:07:37 -0000 1.8 @@ -152,27 +152,27 @@ return FALSE; -/* test id adding two watches for different message types calls the +/* test if adding a signal watch for different message types calls the * respective callbacks. */ GST_START_TEST (test_watch) - guint id1, id2; + guint id; test_bus = gst_bus_new (); main_loop = g_main_loop_new (NULL, FALSE); - id2 = gst_bus_add_watch (test_bus, GST_MESSAGE_EOS, message_func_eos, NULL); - id1 = - gst_bus_add_watch (test_bus, GST_MESSAGE_APPLICATION, message_func_app, + id = gst_bus_add_watch (test_bus, gst_bus_async_signal_func, NULL); + g_signal_connect (test_bus, "message::eos", (GCallback) message_func_eos, NULL); + g_signal_connect (test_bus, "message::application", + (GCallback) message_func_app, NULL); g_idle_add ((GSourceFunc) send_messages, NULL); while (g_main_context_pending (NULL)) g_main_context_iteration (NULL, FALSE); - g_source_remove (id1); - g_source_remove (id2); + g_source_remove (id); g_main_loop_unref (main_loop); gst_object_unref ((GstObject *) test_bus); |
From: <wt...@fr...> - 2005-11-10 09:19:27
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Thu Nov 10 2005 01:19:24 PST Log message: * check/gst/gstghostpad.c: (GST_START_TEST), (gst_ghost_pad_suite): Added check for bug #317341 * gst/gstbuffer.c: * gst/gstbuffer.h: Some more spiffifying. * gst/gstghostpad.c: (gst_ghost_pad_do_link): Call peer linkfunction if we are a source pad. Totally fixes #317341 * gst/gstpad.c: Update docs, source pads should call the peer linkfunction so they can atomically perform the pad link. Modified files: . : ChangeLog check/gst : gstghostpad.c gst : gstbuffer.c gstbuffer.h gstghostpad.c gstpad.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.1859&r2=1.1860 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/gst/gstghostpad.c.diff?r1=1.13&r2=1.14 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstbuffer.c.diff?r1=1.114&r2=1.115 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstbuffer.h.diff?r1=1.99&r2=1.100 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstghostpad.c.diff?r1=1.25&r2=1.26 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstpad.c.diff?r1=1.471&r2=1.472 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.1859 retrieving revision 1.1860 diff -u -d -r1.1859 -r1.1860 --- ChangeLog 9 Nov 2005 18:10:53 -0000 1.1859 +++ ChangeLog 10 Nov 2005 09:19:12 -0000 1.1860 @@ -1,3 +1,20 @@ +2005-11-10 Wim Taymans <wi...@fl...> + + * check/gst/gstghostpad.c: (GST_START_TEST), (gst_ghost_pad_suite): + Added check for bug #317341 + * gst/gstbuffer.c: + * gst/gstbuffer.h: + Some more spiffifying. + * gst/gstghostpad.c: (gst_ghost_pad_do_link): + Call peer linkfunction if we are a source pad. Totally fixes + #317341 + * gst/gstpad.c: + Update docs, source pads should call the peer linkfunction + so they can atomically perform the pad link. 2005-11-09 Wim Taymans <wi...@fl...> * gst/gstbuffer.c: Index: gstbuffer.c RCS file: /cvs/gstreamer/gstreamer/gst/gstbuffer.c,v retrieving revision 1.114 retrieving revision 1.115 diff -u -d -r1.114 -r1.115 --- gstbuffer.c 9 Nov 2005 18:10:53 -0000 1.114 +++ gstbuffer.c 10 Nov 2005 09:19:12 -0000 1.115 @@ -25,7 +25,7 @@ * @short_description: Data-passing buffer type, supporting sub-buffers. * @see_also: #GstPad, #GstMiniObject * - * Buffers are the basic unit of data transfer in GStreamer. The GstBuffer type + * Buffers are the basic unit of data transfer in GStreamer. The #GstBuffer type * provides all the state necessary to define a region of memory as part of a * stream. Sub-buffers are also supported, allowing a smaller region of a * buffer to become its own buffer, with mechanisms in place to ensure that Index: gstbuffer.h RCS file: /cvs/gstreamer/gstreamer/gst/gstbuffer.h,v retrieving revision 1.99 retrieving revision 1.100 diff -u -d -r1.99 -r1.100 --- gstbuffer.h 9 Nov 2005 18:10:53 -0000 1.99 +++ gstbuffer.h 10 Nov 2005 09:19:12 -0000 1.100 @@ -209,9 +209,9 @@ * @mini_object: the parent structure * @data: pointer to the buffer data * @size: size of buffer data - * @timestamp: timestamp of the buffer, can be GST_CLOCK_TIME_NONE when the + * @timestamp: timestamp of the buffer, can be #GST_CLOCK_TIME_NONE when the * timestamp is not known or relevant. - * @duration: duration in time of the buffer data, can be GST_CLOCK_TIME_NONE + * @duration: duration in time of the buffer data, can be #GST_CLOCK_TIME_NONE * when the duration is not known or relevant. * @caps: the #GstCaps describing the data format in this buffer * @offset: a media specific offset for the buffer data. Index: gstghostpad.c RCS file: /cvs/gstreamer/gstreamer/gst/gstghostpad.c,v retrieving revision 1.25 retrieving revision 1.26 diff -u -d -r1.25 -r1.26 --- gstghostpad.c 9 Nov 2005 17:55:13 -0000 1.25 +++ gstghostpad.c 10 Nov 2005 09:19:12 -0000 1.26 @@ -615,6 +615,13 @@ else ret = gst_pad_link (target, internal); + /* if we are a source pad, we should call the peer link function + * if the peer has one */ + if (GST_PAD_IS_SRC (pad)) { + if (GST_PAD_LINKFUNC (peer) && ret == GST_PAD_LINK_OK) + ret = GST_PAD_LINKFUNC (peer) (peer, pad); + } gst_object_unref (target); if (ret == GST_PAD_LINK_OK) Index: gstpad.c RCS file: /cvs/gstreamer/gstreamer/gst/gstpad.c,v retrieving revision 1.471 retrieving revision 1.472 diff -u -d -r1.471 -r1.472 --- gstpad.c 9 Nov 2005 17:55:13 -0000 1.471 +++ gstpad.c 10 Nov 2005 09:19:12 -0000 1.472 @@ -1208,11 +1208,14 @@ * Sets the given link function for the pad. It will be called when * the pad is linked with another pad. - * The return value GST_PAD_LINK_OK should be used when the connection can be + * The return value #GST_PAD_LINK_OK should be used when the connection can be * made. - * The return value GST_PAD_LINK_REFUSED should be used when the connection + * The return value #GST_PAD_LINK_REFUSED should be used when the connection * cannot be made for some reason. + * + * If @link is installed on a source pad, it should call the #GstPadLinkFunction + * of the peer sink pad, if present. */ void gst_pad_set_link_function (GstPad * pad, GstPadLinkFunction link) RCS file: /cvs/gstreamer/gstreamer/check/gst/gstghostpad.c,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- gstghostpad.c 19 Oct 2005 11:43:42 -0000 1.13 +++ gstghostpad.c 10 Nov 2005 09:19:12 -0000 1.14 @@ -104,7 +104,7 @@ #if 0 /* test if a ghost pad without a target can be linked - * + * It can't because it has incompatible caps... GST_START_TEST (test_ghost_pad_notarget) { @@ -287,6 +287,46 @@ GST_END_TEST; +GST_START_TEST (test_ghost_pads_bin) +{ + GstBin *pipeline; + GstBin *srcbin; + GstBin *sinkbin; + GstElement *src; + GstElement *sink; + GstPad *srcghost; + GstPad *sinkghost; + pipeline = GST_BIN (gst_pipeline_new ("pipe")); + srcbin = GST_BIN (gst_bin_new ("srcbin")); + gst_bin_add (pipeline, GST_ELEMENT (srcbin)); + sinkbin = GST_BIN (gst_bin_new ("sinkbin")); + gst_bin_add (pipeline, GST_ELEMENT (sinkbin)); + src = gst_element_factory_make ("fakesrc", "src"); + gst_bin_add (srcbin, src); + srcghost = gst_ghost_pad_new ("src", gst_element_get_pad (src, "src")); + gst_element_add_pad (GST_ELEMENT (srcbin), srcghost); + sink = gst_element_factory_make ("fakesink", "sink"); + gst_bin_add (sinkbin, sink); + sinkghost = gst_ghost_pad_new ("sink", gst_element_get_pad (sink, "sink")); + gst_element_add_pad (GST_ELEMENT (sinkbin), sinkghost); + gst_element_link (GST_ELEMENT (srcbin), GST_ELEMENT (sinkbin)); + fail_unless (GST_PAD_PEER (srcghost) != NULL); + fail_unless (GST_PAD_PEER (sinkghost) != NULL); + fail_unless (GST_PAD_PEER (gst_ghost_pad_get_target (GST_GHOST_PAD + (srcghost))) != NULL); + (sinkghost))) != NULL); +} +GST_END_TEST; Suite * gst_ghost_pad_suite (void) @@ -298,6 +338,7 @@ tcase_add_test (tc_chain, test_remove2); tcase_add_test (tc_chain, test_link); tcase_add_test (tc_chain, test_ghost_pads); + tcase_add_test (tc_chain, test_ghost_pads_bin); /* tcase_add_test (tc_chain, test_ghost_pad_notarget); */ return s; |
From: <wt...@fr...> - 2005-11-24 17:45:13
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Thu Nov 24 2005 09:45:09 PST Log message: * check/gst/gstutils.c: (GST_START_TEST), (gst_utils_suite): Added test for scaling. * gst/gstclock.h: Small doc fix. * gst/gstutils.c: (gst_util_uint64_scale_int): Implemented high precision scaling code. Modified files: . : ChangeLog check/gst : gstutils.c gst : gstclock.h gstutils.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.2011&r2=1.2012 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/gst/gstutils.c.diff?r1=1.3&r2=1.4 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstclock.h.diff?r1=1.57&r2=1.58 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstutils.c.diff?r1=1.120&r2=1.121 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.2011 retrieving revision 1.2012 diff -u -d -r1.2011 -r1.2012 --- ChangeLog 24 Nov 2005 16:56:28 -0000 1.2011 +++ ChangeLog 24 Nov 2005 17:44:57 -0000 1.2012 @@ -1,3 +1,14 @@ +2005-11-24 Wim Taymans <wi...@fl...> + + * check/gst/gstutils.c: (GST_START_TEST), (gst_utils_suite): + Added test for scaling. + * gst/gstclock.h: + Small doc fix. + * gst/gstutils.c: (gst_util_uint64_scale_int): + Implemented high precision scaling code. 2005-11-24 Stefan Kost <en...@us...> * gst/gstinfo.h: Index: gstutils.c RCS file: /cvs/gstreamer/gstreamer/check/gst/gstutils.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- gstutils.c 21 Sep 2005 13:24:33 -0000 1.3 +++ gstutils.c 24 Nov 2005 17:44:57 -0000 1.4 @@ -167,6 +167,37 @@ g_assert (n_data_probes_once == 1); /* let's hit it and quit!!! */ } GST_END_TEST; +GST_START_TEST (test_math_scale) +{ + fail_if (gst_util_uint64_scale_int (1, 1, 1) != 1); + fail_if (gst_util_uint64_scale_int (10, 10, 1) != 100); + fail_if (gst_util_uint64_scale_int (10, 10, 2) != 50); + fail_if (gst_util_uint64_scale_int (0, 10, 2) != 0); + fail_if (gst_util_uint64_scale_int (0, 0, 2) != 0); + fail_if (gst_util_uint64_scale_int (G_MAXUINT32, 5, 1) != G_MAXUINT32 * 5LL); + fail_if (gst_util_uint64_scale_int (G_MAXUINT32, 10, 2) != G_MAXUINT32 * 5LL); + fail_if (gst_util_uint64_scale_int (G_MAXUINT32, 1, 5) != G_MAXUINT32 / 5LL); + fail_if (gst_util_uint64_scale_int (G_MAXUINT32, 2, 10) != G_MAXUINT32 / 5LL); + /* not quite overflow */ + fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, 10, + 10) != G_MAXUINT64 - 1); + fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, G_MAXINT32, + G_MAXINT32) != G_MAXUINT64 - 1); + fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 100, G_MAXINT32, + G_MAXINT32) != G_MAXUINT64 - 100); + /* overflow */ + fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, 10, 1) != G_MAXUINT64); + 1) != G_MAXUINT64); +} GST_END_TEST; Suite * gst_utils_suite (void) { @@ -176,6 +207,7 @@ suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_buffer_probe_n_times); tcase_add_test (tc_chain, test_buffer_probe_once); + tcase_add_test (tc_chain, test_math_scale); return s; } Index: gstclock.h RCS file: /cvs/gstreamer/gstreamer/gst/gstclock.h,v retrieving revision 1.57 retrieving revision 1.58 diff -u -d -r1.57 -r1.58 --- gstclock.h 23 Nov 2005 12:36:00 -0000 1.57 +++ gstclock.h 24 Nov 2005 17:44:57 -0000 1.58 @@ -63,7 +63,7 @@ /** * GstClockID: * - * A datatype to hold the handle to an outstanding async clock callback. + * A datatype to hold the handle to an outstanding sync or async clock callback. */ typedef gpointer GstClockID; RCS file: /cvs/gstreamer/gstreamer/gst/gstutils.c,v retrieving revision 1.120 retrieving revision 1.121 diff -u -d -r1.120 -r1.121 --- gstutils.c 23 Nov 2005 13:22:21 -0000 1.120 +++ gstutils.c 24 Nov 2005 17:44:57 -0000 1.121 @@ -340,6 +340,22 @@ #endif +/* convenience struct for getting high an low uint32 parts of + * a guint64 */ +typedef union + guint64 ll; + struct + { +#if G_BYTE_ORDER == G_BIG_ENDIAN + guint32 high, low; +#else + guint32 low, high; +#endif + } l; +} GstUInt64; * gst_util_uint64_scale: * @val: the number to scale @@ -360,19 +376,54 @@ * gst_util_uint64_scale_int: - * @val: GstClockTime to scale. + * @val: guint64 (such as a #GstClockTime) to scale. * @num: numerator of the scale factor. * @denom: denominator of the scale factor. - * Scale a clocktime by a factor expressed as a fraction (num/denom), avoiding + * Scale a guint64 by a factor expressed as a fraction (num/denom), avoiding * overflows and loss of precision. + * @num and @denom must be positive integers. @denom cannot be 0. + * * Returns: @val * @num / @denom, avoiding overflow and loss of precision guint64 gst_util_uint64_scale_int (guint64 val, gint num, gint denom) - return val * num / denom; + GstUInt64 result; + g_return_val_if_fail (denom > 0, G_MAXUINT64); + g_return_val_if_fail (num >= 0, G_MAXUINT64); + if (val <= G_MAXUINT32) { + /* simple case */ + result.ll = val * num / denom; + } else { + GstUInt64 gval, low, high, temp; + /* do 96 bits mult/div */ + gval.ll = val; + low.ll = ((guint64) gval.l.low) * num; + high.ll = ((guint64) gval.l.high) * num + (low.l.high); + result.ll = (high.ll / denom); + temp.l.high = (high.ll % denom); + temp.l.low = (low.l.low); + temp.ll /= denom; + /* avoid overflow */ + if (result.ll + temp.l.high > G_MAXUINT32) + goto overflow; + result.l.high = result.l.low; + result.l.low = 0; + result.ll += temp.ll; + } + return result.ll; +overflow: + return G_MAXUINT64; /* ----------------------------------------------------- |
From: <wt...@fr...> - 2005-11-25 00:02:19
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Thu Nov 24 2005 16:02:17 PST Log message: * check/gst/gstutils.c: (GST_START_TEST), (gst_utils_suite): Added more checks for the high precision uint64 cases. * gst/gstutils.c: (gst_util_uint64_scale_int64), (gst_util_uint64_scale), (gst_util_uint64_scale_int): Implement high precission (guint64 * guint64) / guint64. Modified files: . : ChangeLog check/gst : gstutils.c gst : gstutils.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.2015&r2=1.2016 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/gst/gstutils.c.diff?r1=1.4&r2=1.5 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstutils.c.diff?r1=1.123&r2=1.124 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.2015 retrieving revision 1.2016 diff -u -d -r1.2015 -r1.2016 --- ChangeLog 24 Nov 2005 19:06:58 -0000 1.2015 +++ ChangeLog 25 Nov 2005 00:02:04 -0000 1.2016 @@ -1,3 +1,12 @@ +2005-11-25 Wim Taymans <wi...@fl...> + + * check/gst/gstutils.c: (GST_START_TEST), (gst_utils_suite): + Added more checks for the high precision uint64 cases. + * gst/gstutils.c: (gst_util_uint64_scale_int64), + (gst_util_uint64_scale), (gst_util_uint64_scale_int): + Implement high precission (guint64 * guint64) / guint64. 2005-11-24 Wim Taymans <wi...@fl...> * gst/base/gstbasesrc.c: (gst_base_src_query): Index: gstutils.c RCS file: /cvs/gstreamer/gstreamer/check/gst/gstutils.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- gstutils.c 24 Nov 2005 17:44:57 -0000 1.4 +++ gstutils.c 25 Nov 2005 00:02:05 -0000 1.5 @@ -192,12 +192,49 @@ G_MAXINT32) != G_MAXUINT64 - 100); /* overflow */ - fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, 10, 1) != G_MAXUINT64); - fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, G_MAXINT32, + ASSERT_WARNING (gst_util_uint64_scale_int (G_MAXUINT64 - 1, 10, + 1) != G_MAXUINT64); + ASSERT_WARNING (gst_util_uint64_scale_int (G_MAXUINT64 - 1, G_MAXINT32, 1) != G_MAXUINT64); } GST_END_TEST; +GST_START_TEST (test_math_scale_uint64) +{ + fail_if (gst_util_uint64_scale (1, 1, 1) != 1); + fail_if (gst_util_uint64_scale (10, 10, 1) != 100); + fail_if (gst_util_uint64_scale (10, 10, 2) != 50); + fail_if (gst_util_uint64_scale (0, 10, 2) != 0); + fail_if (gst_util_uint64_scale (0, 0, 2) != 0); + fail_if (gst_util_uint64_scale (G_MAXUINT32, 5, 1) != G_MAXUINT32 * 5LL); + fail_if (gst_util_uint64_scale (G_MAXUINT32, 10, 2) != G_MAXUINT32 * 5LL); + fail_if (gst_util_uint64_scale (G_MAXUINT32, 1, 5) != G_MAXUINT32 / 5LL); + fail_if (gst_util_uint64_scale (G_MAXUINT32, 2, 10) != G_MAXUINT32 / 5LL); + /* not quite overflow */ + fail_if (gst_util_uint64_scale (G_MAXUINT64 - 1, 10, 10) != G_MAXUINT64 - 1); + fail_if (gst_util_uint64_scale (G_MAXUINT64 - 1, G_MAXUINT32, + G_MAXUINT32) != G_MAXUINT64 - 1); + fail_if (gst_util_uint64_scale (G_MAXUINT64 - 100, G_MAXUINT32, + G_MAXUINT32) != G_MAXUINT64 - 100); + fail_if (gst_util_uint64_scale (G_MAXUINT64 - 1, G_MAXUINT64, + G_MAXUINT64) != G_MAXUINT64 - 1); + fail_if (gst_util_uint64_scale (G_MAXUINT64 - 100, G_MAXUINT64, + G_MAXUINT64) != G_MAXUINT64 - 100); + /* overflow */ + ASSERT_WARNING (gst_util_uint64_scale (G_MAXUINT64 - 1, 10, + ASSERT_WARNING (gst_util_uint64_scale (G_MAXUINT64 - 1, G_MAXUINT64, +} GST_END_TEST; Suite * gst_utils_suite (void) { @@ -208,6 +245,7 @@ tcase_add_test (tc_chain, test_buffer_probe_n_times); tcase_add_test (tc_chain, test_buffer_probe_once); tcase_add_test (tc_chain, test_math_scale); + tcase_add_test (tc_chain, test_math_scale_uint64); return s; } RCS file: /cvs/gstreamer/gstreamer/gst/gstutils.c,v retrieving revision 1.123 retrieving revision 1.124 diff -u -d -r1.123 -r1.124 --- gstutils.c 24 Nov 2005 19:06:58 -0000 1.123 +++ gstutils.c 25 Nov 2005 00:02:05 -0000 1.124 @@ -356,6 +356,89 @@ } l; } GstUInt64; +static guint64 +gst_util_uint64_scale_int64 (guint64 val, guint64 num, guint64 denom) + GstUInt64 a0, a1, b0, b1, c0, ct, c1, result; + GstUInt64 v, n, d; + /* prepare input */ + v.ll = val; + n.ll = num; + d.ll = denom; + /* do 128 bits multiply + * nh nl + * * vh vl + * ---------- + * a0 = vl * nl + * a1 = vl * nh + * b0 = vh * nl + * b1 = + vh * nh + * ------------------- + * c1,c0 + */ + a0.ll = (guint64) v.l.low * n.l.low; + a1.ll = (guint64) v.l.low * n.l.high; + b0.ll = (guint64) v.l.high * n.l.low; + b1.ll = (guint64) v.l.high * n.l.high; + /* and sum together with carry into 128 bits c1, c0 */ + c0.l.low = a0.l.low; + ct.ll = (guint64) a0.l.high + a1.l.low + b0.l.low; + c0.l.high = ct.l.low; + c1.ll = (guint64) a1.l.high + b0.l.high + ct.l.high + b1.ll; + /* if high bits bigger than denom, we overflow */ + if (c1.ll >= denom) + goto overflow; + /* and 128/64 bits division, result fits 64 bits */ + if (denom <= G_MAXUINT32) { + guint32 den = (guint32) denom; + /* easy case, (c1,c0)128/(den)32 division */ + c1.l.high %= den; + c1.l.high = c1.ll % den; + c1.l.low = c0.l.high; + c0.l.high = c1.ll % den; + result.l.high = c1.ll / den; + result.l.low = c0.ll / den; + } else { + gint i; + gint64 mask; + /* full 128/64 case, very slow... */ + /* quotient is c1, c0 */ + a0.ll = 0; /* remainder a0 */ + /* This can be done faster, inspiration in Hacker's Delight p152 */ + for (i = 0; i < 128; i++) { + /* shift 192 bits remainder:quotient, we only need to + * check the top bit since denom is only 64 bits. */ + /* sign extend top bit into mask */ + mask = ((gint32) a0.l.high) >> 31; + mask |= (a0.ll = (a0.ll << 1) | (c1.l.high >> 31)); + c1.ll = (c1.ll << 1) | (c0.l.high >> 31); + c0.ll <<= 1; + /* if remainder >= denom or top bit was set */ + if (mask >= denom) { + a0.ll -= denom; + c0.ll += 1; + } + } + result.ll = c0.ll; + } + return result.ll; +overflow: + { + g_warning ("int64 scaling overflow"); + return G_MAXUINT64; +} /** * gst_util_uint64_scale: * @val: the number to scale @@ -364,6 +447,8 @@ * * Scale @val by @num / @denom, trying to avoid overflows. + * This function can potentially be very slow if denom > G_MAXUINT32. + * * Returns: @val * @num / @denom, trying to avoid overflows. */ guint64 @@ -390,9 +475,8 @@ return gst_util_uint64_scale_int (val, (gint) num, (gint) denom); do_int64: - /* implement me with fixed point, if you care */ - return gst_gdouble_to_guint64 (gst_guint64_to_gdouble (val) * - ((gst_guint64_to_gdouble (num)) / gst_guint64_to_gdouble (denom))); + /* to the more heavy implementations... */ + return gst_util_uint64_scale_int64 (val, num, denom); @@ -443,6 +527,7 @@ overflow: { + g_warning ("int scaling overflow"); return G_MAXUINT64; } |
From: <wt...@fr...> - 2005-11-28 16:06:34
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Mon Nov 28 2005 08:05:47 PST Log message: * check/gst/gstutils.c: (GST_START_TEST), (gst_utils_suite): More checks. * gst/gstclock.c: (gst_clock_finalize), (gst_clock_set_master), (do_linear_regression), (gst_clock_add_observation): Cleanups. Release lock when the clock cannot be slaved. Catch the case where the regression returned an invalid denominator. * gst/gstutils.c: (gst_util_div128_64_iterate), (gst_util_div128_64), (gst_util_uint64_scale_int64), (gst_util_uint64_scale), (gst_util_uint64_scale_int): Add protentially more performant non-iterative 128/64 divide function that unfortunatly does not work yet. Shortcut the trivial 0/X = 0 case. Remove the warnings on overflow. Modified files: . : ChangeLog check/gst : gstutils.c gst : gstclock.c gstutils.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.2033&r2=1.2034 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/gst/gstutils.c.diff?r1=1.5&r2=1.6 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstclock.c.diff?r1=1.77&r2=1.78 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstutils.c.diff?r1=1.125&r2=1.126 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.2033 retrieving revision 1.2034 diff -u -d -r1.2033 -r1.2034 --- ChangeLog 28 Nov 2005 14:18:22 -0000 1.2033 +++ ChangeLog 28 Nov 2005 16:05:34 -0000 1.2034 @@ -1,3 +1,22 @@ +2005-11-28 Wim Taymans <wi...@fl...> + + * check/gst/gstutils.c: (GST_START_TEST), (gst_utils_suite): + More checks. + * gst/gstclock.c: (gst_clock_finalize), (gst_clock_set_master), + (do_linear_regression), (gst_clock_add_observation): + Cleanups. + Release lock when the clock cannot be slaved. + Catch the case where the regression returned an invalid denominator. + * gst/gstutils.c: (gst_util_div128_64_iterate), + (gst_util_div128_64), (gst_util_uint64_scale_int64), + (gst_util_uint64_scale), (gst_util_uint64_scale_int): + Add protentially more performant non-iterative 128/64 divide function + that unfortunatly does not work yet. + Shortcut the trivial 0/X = 0 case. + Remove the warnings on overflow. 2005-11-28 Thomas Vander Stichele <thomas at apestaart dot org> * gst/gstplugin.c: (gst_plugin_register_func): Index: gstutils.c RCS file: /cvs/gstreamer/gstreamer/check/gst/gstutils.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- gstutils.c 25 Nov 2005 00:02:05 -0000 1.5 +++ gstutils.c 28 Nov 2005 16:05:35 -0000 1.6 @@ -192,9 +192,8 @@ G_MAXINT32) != G_MAXUINT64 - 100); /* overflow */ - ASSERT_WARNING (gst_util_uint64_scale_int (G_MAXUINT64 - 1, 10, - 1) != G_MAXUINT64); - ASSERT_WARNING (gst_util_uint64_scale_int (G_MAXUINT64 - 1, G_MAXINT32, + fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, 10, 1) != G_MAXUINT64); + fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, G_MAXINT32, 1) != G_MAXUINT64); } GST_END_TEST; @@ -229,12 +228,34 @@ G_MAXUINT64) != G_MAXUINT64 - 100); - ASSERT_WARNING (gst_util_uint64_scale (G_MAXUINT64 - 1, 10, - ASSERT_WARNING (gst_util_uint64_scale (G_MAXUINT64 - 1, G_MAXUINT64, + fail_if (gst_util_uint64_scale (G_MAXUINT64 - 1, 10, 1) != G_MAXUINT64); + fail_if (gst_util_uint64_scale (G_MAXUINT64 - 1, G_MAXUINT64, +GST_START_TEST (test_math_scale_random) +{ + guint64 val, num, denom, res;; + GRand *rand; + gint i; + rand = g_rand_new (); + i = 1000; + while (i--) { + val = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand); + num = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand); + denom = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand); + res = gst_util_uint64_scale (val, num, denom); + } + g_rand_free (rand); +} +GST_END_TEST; Suite * gst_utils_suite (void) { @@ -246,6 +267,7 @@ tcase_add_test (tc_chain, test_buffer_probe_once); tcase_add_test (tc_chain, test_math_scale); tcase_add_test (tc_chain, test_math_scale_uint64); + tcase_add_test (tc_chain, test_math_scale_random); return s; } Index: gstclock.c RCS file: /cvs/gstreamer/gstreamer/gst/gstclock.c,v retrieving revision 1.77 retrieving revision 1.78 diff -u -d -r1.77 -r1.78 --- gstclock.c 24 Nov 2005 09:44:06 -0000 1.77 +++ gstclock.c 28 Nov 2005 16:05:35 -0000 1.78 @@ -589,19 +589,17 @@ GstClock *clock = GST_CLOCK (object); - GST_OBJECT_LOCK (clock); + GST_CLOCK_SLAVE_LOCK (clock); if (clock->clockid) { gst_clock_id_unschedule (clock->clockid); gst_clock_id_unref (clock->clockid); clock->clockid = NULL; } - - g_cond_free (clock->entries_changed); g_free (clock->times); clock->times = NULL; - GST_OBJECT_UNLOCK (clock); + GST_CLOCK_SLAVE_UNLOCK (clock); + g_cond_free (clock->entries_changed); g_mutex_free (clock->slave_lock); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -883,18 +881,15 @@ g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE); GST_OBJECT_LOCK (clock); /* we always allow setting the master to NULL */ if (master && !GST_OBJECT_FLAG_IS_SET (clock, GST_CLOCK_FLAG_CAN_SET_MASTER)) goto not_supported; GST_DEBUG_OBJECT (clock, "slaving to master clock %p", master); gst_object_replace ((GstObject **) & clock->master, (GstObject *) master); GST_OBJECT_UNLOCK (clock); GST_CLOCK_SLAVE_LOCK (clock); @@ -910,7 +905,6 @@ gst_clock_id_wait_async (clock->clockid, (GstClockCallback) gst_clock_slave_callback, clock); GST_CLOCK_SLAVE_UNLOCK (clock); return TRUE; @@ -918,6 +912,7 @@ not_supported: { GST_DEBUG_OBJECT (clock, "cannot be slaved to a master clock"); + GST_OBJECT_UNLOCK (clock); return FALSE; @@ -1034,6 +1029,9 @@ sxy += newx4 * newy4 - xbar4 * ybar4; + if (sxx == 0) + goto invalid; *m_num = sxy; *m_denom = sxx; *xbase = xmin; @@ -1046,6 +1044,11 @@ DEBUG (" r2 = %g", *r_squared); +invalid: + { + return FALSE; /** @@ -1088,7 +1091,8 @@ if (clock->filling && clock->time_index < clock->window_threshold) goto filling; - do_linear_regression (clock, &m_num, &m_denom, &b, &xbase, r_squared); + if (!do_linear_regression (clock, &m_num, &m_denom, &b, &xbase, r_squared)) @@ -1096,6 +1100,7 @@ "adjusting clock to m=%" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT ", b=%" G_GUINT64_FORMAT " (rsquared=%g)", m_num, m_denom, b, *r_squared); + /* if we have a valid regression, adjust the clock */ gst_clock_set_calibration (clock, xbase, b, m_num, m_denom); @@ -1103,9 +1108,14 @@ filling: GST_CLOCK_SLAVE_UNLOCK (clock); + /* no valid regression has been done, ignore the result then */ + GST_CLOCK_SLAVE_UNLOCK (clock); + return TRUE; static void RCS file: /cvs/gstreamer/gstreamer/gst/gstutils.c,v retrieving revision 1.125 retrieving revision 1.126 diff -u -d -r1.125 -r1.126 --- gstutils.c 25 Nov 2005 11:38:38 -0000 1.125 +++ gstutils.c 28 Nov 2005 16:05:35 -0000 1.126 @@ -357,6 +357,102 @@ } GstUInt64; static guint64 +gst_util_div128_64_iterate (GstUInt64 c1, GstUInt64 c0, guint64 denom) + gint64 mask; + GstUInt64 a0; + /* full 128/64 case, very slow... */ + /* quotient is c1, c0 */ + a0.ll = 0; /* remainder a0 */ + /* This can be done faster, inspiration in Hacker's Delight p152 */ + for (i = 0; i < 128; i++) { + /* shift 192 bits remainder:quotient, we only need to + * check the top bit since denom is only 64 bits. */ + /* sign extend top bit into mask */ + mask = ((gint32) a0.l.high) >> 31; + mask |= (a0.ll = (a0.ll << 1) | (c1.l.high >> 31)); + c1.ll = (c1.ll << 1) | (c0.l.high >> 31); + c0.ll <<= 1; + /* if remainder >= denom or top bit was set */ + if (mask >= denom) { + a0.ll -= denom; + c0.ll += 1; + } + return c0.ll; +/* based on Hacker's Delight p152 */ +static guint64 +gst_util_div128_64 (GstUInt64 c1, GstUInt64 c0, guint64 denom) + GstUInt64 q1, q0, rhat; + GstUInt64 v, cmp1, cmp2; + guint s; + v.ll = denom; + /* count number of leading zeroes, we know they must be in the high + * part of denom since denom > G_MAXUINT32. */ + s = v.l.high | (v.l.high >> 1); + s |= (s >> 2); + s |= (s >> 4); + s |= (s >> 8); + s = ~(s | (s >> 16)); + s = s - ((s >> 1) & 0x55555555); + s = (s & 0x33333333) + ((s >> 2) & 0x33333333); + s = (s + (s >> 4)) & 0x0f0f0f0f; + s += (s >> 8); + s = (s + (s >> 16)) & 0x3f; + /* normalize divisor and dividend */ + v.ll <<= s; + c1.ll = (c1.ll << s) | ((c0.l.high >> (32 - s)) & (-s >> 31)); + c0.ll <<= s; + q1.ll = c1.ll / v.l.high; + rhat.ll = c1.ll - q1.ll * v.l.high; + cmp1.l.high = rhat.l.low; + cmp1.l.low = c0.l.high; + cmp2.ll = q1.ll * v.l.low; + while (q1.l.high || cmp2.ll > cmp1.ll) { + q1.ll--; + rhat.ll += v.l.high; + if (rhat.l.high) + break; + cmp1.l.high = rhat.l.low; + cmp2.ll -= v.l.low; + c1.l.high = c1.l.low; + c1.l.low = c0.l.high; + c1.ll -= q1.ll * v.ll; + q0.ll = c1.ll / v.l.high; + rhat.ll = c1.ll - q0.ll * v.l.high; + cmp1.l.low = c0.l.low; + cmp2.ll = q0.ll * v.l.low; + while (q0.l.high || cmp2.ll > cmp1.ll) { + q0.ll--; + q0.l.high += q1.l.low; + return q0.ll; gst_util_uint64_scale_int64 (guint64 val, guint64 num, guint64 denom) GstUInt64 a0, a1, b0, b1, c0, ct, c1, result; @@ -405,36 +501,15 @@ result.l.high = c1.ll / den; result.l.low = c0.ll / den; } else { - gint i; - gint64 mask; - /* full 128/64 case, very slow... */ - /* quotient is c1, c0 */ - a0.ll = 0; /* remainder a0 */ - /* This can be done faster, inspiration in Hacker's Delight p152 */ - for (i = 0; i < 128; i++) { - /* shift 192 bits remainder:quotient, we only need to - * check the top bit since denom is only 64 bits. */ - /* sign extend top bit into mask */ - mask = ((gint32) a0.l.high) >> 31; - mask |= (a0.ll = (a0.ll << 1) | (c1.l.high >> 31)); - c1.ll = (c1.ll << 1) | (c0.l.high >> 31); - c0.ll <<= 1; - /* if remainder >= denom or top bit was set */ - if (mask >= denom) { - a0.ll -= denom; - c0.ll += 1; - } - } - result.ll = c0.ll; + if (TRUE) + result.ll = gst_util_div128_64_iterate (c1, c0, denom); + else + result.ll = gst_util_div128_64 (c1, c0, denom); return result.ll; overflow: - g_warning ("int64 scaling overflow"); return G_MAXUINT64; @@ -456,6 +531,9 @@ g_return_val_if_fail (denom != 0, G_MAXUINT64); + if (num == 0) + return 0; /* if the denom is high, we need to do a 64 muldiv */ if (denom > G_MAXINT32) goto do_int64; @@ -500,6 +578,9 @@ g_return_val_if_fail (denom > 0, G_MAXUINT64); g_return_val_if_fail (num >= 0, G_MAXUINT64); if (val <= G_MAXUINT32) { /* simple case */ result.ll = val * num / denom; @@ -525,7 +606,6 @@ - g_warning ("int scaling overflow"); |
From: <wt...@fr...> - 2005-11-28 18:44:26
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Mon Nov 28 2005 10:44:23 PST Log message: * check/gst/gstutils.c: (GST_START_TEST): Updated check, add some scaling accuracy checking code. * gst/gstutils.c: (gst_util_div128_64), (gst_util_uint64_scale_int64), (gst_util_uint64_scale), (gst_util_uint64_scale_int): Fix 6 times faster division code. Optimize for common 1/1 and less common X/1 cases. Modified files: . : ChangeLog check/gst : gstutils.c gst : gstutils.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.2034&r2=1.2035 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/gst/gstutils.c.diff?r1=1.6&r2=1.7 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstutils.c.diff?r1=1.126&r2=1.127 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.2034 retrieving revision 1.2035 diff -u -d -r1.2034 -r1.2035 --- ChangeLog 28 Nov 2005 16:05:34 -0000 1.2034 +++ ChangeLog 28 Nov 2005 18:44:11 -0000 1.2035 @@ -1,5 +1,16 @@ 2005-11-28 Wim Taymans <wi...@fl...> + * check/gst/gstutils.c: (GST_START_TEST): + Updated check, add some scaling accuracy checking code. + + * gst/gstutils.c: (gst_util_div128_64), + (gst_util_uint64_scale_int64), (gst_util_uint64_scale), + (gst_util_uint64_scale_int): + Fix 6 times faster division code. Optimize for common + 1/1 and less common X/1 cases. +2005-11-28 Wim Taymans <wi...@fl...> * check/gst/gstutils.c: (GST_START_TEST), (gst_utils_suite): More checks. Index: gstutils.c RCS file: /cvs/gstreamer/gstreamer/gst/gstutils.c,v retrieving revision 1.126 retrieving revision 1.127 diff -u -d -r1.126 -r1.127 --- gstutils.c 28 Nov 2005 16:05:35 -0000 1.126 +++ gstutils.c 28 Nov 2005 18:44:11 -0000 1.127 @@ -356,36 +356,6 @@ } l; } GstUInt64; -static guint64 -gst_util_div128_64_iterate (GstUInt64 c1, GstUInt64 c0, guint64 denom) -{ - gint i; - gint64 mask; - GstUInt64 a0; - - /* full 128/64 case, very slow... */ - /* quotient is c1, c0 */ - a0.ll = 0; /* remainder a0 */ - /* This can be done faster, inspiration in Hacker's Delight p152 */ - for (i = 0; i < 128; i++) { - /* shift 192 bits remainder:quotient, we only need to - * check the top bit since denom is only 64 bits. */ - /* sign extend top bit into mask */ - mask = ((gint32) a0.l.high) >> 31; - mask |= (a0.ll = (a0.ll << 1) | (c1.l.high >> 31)); - c1.ll = (c1.ll << 1) | (c0.l.high >> 31); - c0.ll <<= 1; - /* if remainder >= denom or top bit was set */ - if (mask >= denom) { - a0.ll -= denom; - c0.ll += 1; - } - } - return c0.ll; -} /* based on Hacker's Delight p152 */ static guint64 gst_util_div128_64 (GstUInt64 c1, GstUInt64 c0, guint64 denom) @@ -409,10 +379,12 @@ s += (s >> 8); s = (s + (s >> 16)) & 0x3f; - /* normalize divisor and dividend */ - v.ll <<= s; - c1.ll = (c1.ll << s) | ((c0.l.high >> (32 - s)) & (-s >> 31)); - c0.ll <<= s; + if (s > 0) { + /* normalize divisor and dividend */ + v.ll <<= s; + c1.ll = (c1.ll << s) | (c0.l.high >> (32 - s)); + c0.ll <<= s; + } q1.ll = c1.ll / v.l.high; rhat.ll = c1.ll - q1.ll * v.l.high; @@ -489,6 +461,11 @@ if (c1.ll >= denom) goto overflow; + /* shortcut for division by 1, c1.ll should be 0 because of the + * overflow check above. */ + if (denom == 1) + return c0.ll; /* and 128/64 bits division, result fits 64 bits */ if (denom <= G_MAXUINT32) { guint32 den = (guint32) denom; @@ -501,10 +478,7 @@ result.l.high = c1.ll / den; result.l.low = c0.ll / den; } else { - if (TRUE) - result.ll = gst_util_div128_64_iterate (c1, c0, denom); - else - result.ll = gst_util_div128_64 (c1, c0, denom); + result.ll = gst_util_div128_64 (c1, c0, denom); } return result.ll; @@ -534,6 +508,9 @@ if (num == 0) return 0; + if (num == 1 && denom == 1) + return val; /* if the denom is high, we need to do a 64 muldiv */ if (denom > G_MAXINT32) goto do_int64; @@ -581,6 +558,9 @@ if (val <= G_MAXUINT32) { /* simple case */ result.ll = val * num / denom; RCS file: /cvs/gstreamer/gstreamer/check/gst/gstutils.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- gstutils.c 28 Nov 2005 16:05:35 -0000 1.6 +++ gstutils.c 28 Nov 2005 18:44:11 -0000 1.7 @@ -236,19 +236,35 @@ GST_START_TEST (test_math_scale_random) { - guint64 val, num, denom, res;; + guint64 val, num, denom, res; GRand *rand; gint i; rand = g_rand_new (); - i = 1000; + i = 1000000; while (i--) { + guint64 check, diff; val = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand); num = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand); denom = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand); res = gst_util_uint64_scale (val, num, denom); + check = gst_gdouble_to_guint64 (gst_guint64_to_gdouble (val) * + gst_guint64_to_gdouble (num) / gst_guint64_to_gdouble (denom)); + if (res < G_MAXUINT64 && check < G_MAXUINT64) { + if (res > check) + diff = res - check; + else + diff = check - res; + /* some arbitrary value, really.. someone do the proper math to get + * the upper bound */ + if (diff > 20000) + fail_if (diff > 20000); + } g_rand_free (rand); |