gst/: add/move some code to handle wrapping/refcounting of possible

Original commit message from CVS:
* gst/Makefile.am:
* gst/common.h:
* gst/pygstobject.c: (pygstobject_sink), (pygstobject_new),
(pygst_object_unref):
* gst/pygstobject.h:
* gst/gstmodule.c: (init_gst):
add/move some code to handle wrapping/refcounting of possible
GstObject
* codegen/argtypes.py:
* gst/gstbin.override:
* gst/gstbus.override:
* gst/gstelement.override:
* gst/gstpad.override:
* gst/interfaces.override:
use this reffing code
* gst/gst-types.defs:
* gst/gst.override:
add a __gstrefcount__ field to GstObject types
add tp_traverse, tp_dealloc and tp_clear, so we handle refcounting
properly related to garbage collection
* testsuite/test_element.py:
* testsuite/test_pad.py:
add more tests, add some refcount checks
This commit is contained in:
Thomas Vander Stichele 2005-09-28 12:17:29 +00:00
parent 1bc63d73b9
commit 5768672390
16 changed files with 392 additions and 35 deletions

View file

@ -1,3 +1,29 @@
2005-09-28 Thomas Vander Stichele <thomas at apestaart dot org>
* gst/Makefile.am:
* gst/common.h:
* gst/pygstobject.c: (pygstobject_sink), (pygstobject_new),
(pygst_object_unref):
* gst/pygstobject.h:
* gst/gstmodule.c: (init_gst):
add/move some code to handle wrapping/refcounting of possible
GstObject
* codegen/argtypes.py:
* gst/gstbin.override:
* gst/gstbus.override:
* gst/gstelement.override:
* gst/gstpad.override:
* gst/interfaces.override:
use this reffing code
* gst/gst-types.defs:
* gst/gst.override:
add a __gstrefcount__ field to GstObject types
add tp_traverse, tp_dealloc and tp_clear, so we handle refcounting
properly related to garbage collection
* testsuite/test_element.py:
* testsuite/test_pad.py:
add more tests, add some refcount checks
2005-09-28 Edward Hervey <edward@fluendo.com>
* codegen/argtypes.py:

View file

@ -471,13 +471,15 @@ class ObjectArg(ArgType):
info.varlist.add(ptype, '*ret')
if ownsreturn:
info.varlist.add('PyObject', '*py_ret')
info.codeafter.append(' py_ret = pygobject_new((GObject *)ret);\n'
# < GLib 2.8: using our custom _new and _unref functions
# makes sure we update the proper GstObject refcount
info.codeafter.append(' py_ret = pygstobject_new((GObject *)ret);\n'
' if (ret != NULL)\n'
' g_object_unref(ret);\n'
' pygst_object_unref((GObject *)ret);\n'
' return py_ret;')
else:
info.codeafter.append(' /* pygobject_new handles NULL checking */\n' +
' return pygobject_new((GObject *)ret);')
info.codeafter.append(' /* pygstobject_new handles NULL checking */\n' +
' return pygstobject_new((GObject *)ret);')
class MiniObjectArg(ArgType):
# should change these checks to more typesafe versions that check

View file

@ -22,7 +22,7 @@ defs_DATA = gst-types.defs \
libs.defs
defsdir = $(pkgdatadir)/2.0/defs
noinst_HEADERS = common.h pygstvalue.h pygstminiobject.h
noinst_HEADERS = common.h pygstvalue.h pygstminiobject.h pygstobject.h
INCLUDES = $(PYTHON_INCLUDES)
EXTRA_DIST = $(defs_DATA) common.h arg-types.py
@ -33,7 +33,7 @@ GEN_FILES = arg-types.py gst-types.defs libs.defs
_gst_la_CFLAGS = $(common_cflags)
_gst_la_LIBADD = $(common_libadd)
_gst_la_LDFLAGS = $(common_ldflags) -export-symbols-regex init_gst $(GST_BASE_LIBS) $(GST_CONTROLLER_LIBS)
_gst_la_SOURCES = gst-argtypes.c gstmodule.c pygstvalue.c pygstminiobject.c
_gst_la_SOURCES = gst-argtypes.c gstmodule.c pygstvalue.c pygstminiobject.c pygstobject.c
nodist__gst_la_SOURCES = gst.c
GST_OVERRIDES = \
gst.override \

View file

@ -28,6 +28,7 @@
#include <gst/gst.h>
#include "pygobject.h"
#include "pygstobject.h"
#include "pygstminiobject.h"
#if (defined HAVE_OLD_PYGTK && (PY_VERSION_HEX < 0x02030000))

View file

@ -7,6 +7,9 @@
(parent "GObject")
(c-name "GstObject")
(gtype-id "GST_TYPE_OBJECT")
(fields
'("int" "__gstrefcount__")
)
)
(define-object Index

View file

@ -309,6 +309,7 @@ ignore
gst_tag_list_copy_value
gst_trace_read_tsc
%%
define GstTagList.keys noargs
void
@ -540,6 +541,114 @@ _wrap_gst_tag_list_get_value_index (PyGObject *self,
return pygst_value_as_pyobject(gvalue, FALSE);
}
/* keep this attribute around even after 2.8 for compatibility reasons */
%%
override-attr GstObject.__gstrefcount__
static PyObject *
_wrap_gst_object__get___gstrefcount__(PyGObject *self, void *closure)
{
return PyInt_FromLong(GST_OBJECT_REFCOUNT_VALUE(self->obj));
}
/* < GLib 2.8 */
/* because of our gst_object_ref/_unref, we do our own GC-related
* functions:
* our own tp_traverse that checks the GstObject refcount,
* and reuse _dealloc and _clear from gobject.GObject for ours
* compare with pygtk/gobject/pygobject.c
*/
/* a define is a little evil, but it seems to generate the right code
* to allow us to do our garbage collection routines */
%%
override-slot GstObject.tp_flags
#define _wrap_gst_object_tp_flags Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC
%%
override-slot GstObject.tp_traverse
static int
_wrap_gst_object_tp_traverse(PyGObject *self, visitproc visit, void *arg)
{
int ret = 0;
GSList *tmp;
if (self->inst_dict) ret = visit(self->inst_dict, arg);
if (ret != 0) return ret;
for (tmp = self->closures; tmp != NULL; tmp = tmp->next) {
PyGClosure *closure = tmp->data;
if (closure->callback) ret = visit(closure->callback, arg);
if (ret != 0) return ret;
if (closure->extra_args) ret = visit(closure->extra_args, arg);
if (ret != 0) return ret;
if (closure->swap_data) ret = visit(closure->swap_data, arg);
if (ret != 0) return ret;
}
if (self->obj && GST_OBJECT_REFCOUNT_VALUE(self->obj) == 1) {
GST_DEBUG_OBJECT(self->obj,
"gst.Object.tp_traverse: GstObject refcount of %p is 1, visit",
self->obj);
ret = visit((PyObject *)self, arg);
}
return ret;
}
%%
override-slot GstObject.tp_clear
int
_wrap_gst_object_tp_clear(PyGObject *self)
{
int ret;
GObject *obj = self->obj;
/* if we're a GstObject, we want to monkeypatch the GObject.tp_clear's
* g_object_unref and "replace" it with a gst_object_unref */
if (! GST_IS_OBJECT (obj))
obj = NULL;
else {
GST_DEBUG_OBJECT (obj, "gst.Object.tp_clear");
g_object_ref (obj);
}
ret = PyGObject_Type.tp_clear((PyObject *) self);
if (obj)
gst_object_unref (obj);
return ret;
}
%%
override-slot GstObject.tp_dealloc
void
_wrap_gst_object_tp_dealloc(PyGObject *self)
{
GObject *obj = self->obj;
/* if we're a GstObject, we want to monkeypatch the GObject.tp_dealloc's
* g_object_unref and "replace" it with a gst_object_unref */
if (! GST_IS_OBJECT (obj))
obj = NULL;
else {
GST_DEBUG_OBJECT (obj, "gst.Object.tp_dealloc");
g_object_ref (obj);
}
PyGObject_Type.tp_dealloc((PyObject *) self);
if (obj)
gst_object_unref (obj);
}
%%
override-slot GstObject.tp_repr
static PyObject *
@ -557,6 +666,7 @@ _wrap_gst_object_tp_repr(PyObject *self)
g_free (repr);
return ret;
}
%%
override-slot GstObject.tp_str
static PyObject *

View file

@ -126,7 +126,7 @@ _wrap_gst_bin_get_list(PyGObject *self)
GstElement *element = (GstElement*)l->data;
if (!element)
continue;
PyTuple_SetItem(tuple, i, pygobject_new(G_OBJECT(element)));
PyTuple_SetItem(tuple, i, pygstobject_new(G_OBJECT(element)));
}
return tuple;
@ -151,5 +151,5 @@ _wrap_gst_bin_get_by_name(PyGObject *self, PyObject *args, PyObject *kwargs)
ret = gst_bin_get_by_name(GST_BIN(self->obj), name);
/* pygobject_new handles NULL checking */
return pygobject_new((GObject *)ret);
return pygstobject_new((GObject *)ret);
}

View file

@ -44,7 +44,7 @@ bus_sync_handler (GstBus *bus, GstMessage *message, gpointer user_data)
/* Using N we give away our references to the args tuple */
args = Py_BuildValue ("(NN)",
pygobject_new (G_OBJECT (bus)),
pygstobject_new (G_OBJECT (bus)),
py_msg);
/* add all *args to the args tuple object */
@ -103,7 +103,7 @@ bus_func (GstBus *bus, GstMessage *message, gpointer user_data)
/* Using N we give away our references to the args tuple */
args = Py_BuildValue ("(NN)",
pygobject_new (G_OBJECT (bus)),
pygstobject_new (G_OBJECT (bus)),
py_msg);
g_assert (args);
@ -209,6 +209,7 @@ _wrap_gst_bus_add_watch (PyGObject *self, PyObject *args)
cbargs = PySequence_GetSlice(args, 2, len);
if (cbargs == NULL)
return NULL;
/* FIXME: thomas: I'm pretty sure the second N needs to be O */
data = Py_BuildValue("(ON)", callback, cbargs);
if (data == NULL)
return NULL;

View file

@ -41,7 +41,7 @@ _wrap_gst_element_get_pad_template(PyGObject *self, PyObject *args)
(GST_ELEMENT_GET_CLASS (self->obj), name);
if (tmpl) {
ret = pygobject_new (G_OBJECT (tmpl));
ret = pygstobject_new (G_OBJECT (tmpl));
} else {
ret = Py_None;
Py_INCREF (ret);
@ -62,7 +62,7 @@ _wrap_gst_element_get_pad_list(PyGObject *self)
list = PyList_New(0);
for (l = pads; l; l = l->next) {
GstPad *pad = (GstPad*)l->data;
PyList_Append(list, pygobject_new(G_OBJECT(pad)));
PyList_Append(list, pygstobject_new(G_OBJECT(pad)));
}
return list;
@ -80,7 +80,7 @@ _wrap_gst_element_get_pad_template_list(PyGObject *self)
list = PyList_New(0);
for (l = pads; l; l = l->next) {
GstPad *pad = (GstPad*)l->data;
PyList_Append(list, pygobject_new(G_OBJECT(pad)));
PyList_Append(list, pygstobject_new(G_OBJECT(pad)));
}
return list;

View file

@ -104,15 +104,6 @@ pygstminiobject_to_gvalue(GValue *value, PyObject *obj)
return 0;
}
static void
sink_gstobject(GObject *object)
{
if (GST_OBJECT_IS_FLOATING(object)) {
gst_object_ref(GST_OBJECT(object));
gst_object_sink(GST_OBJECT(object));
}
}
DL_EXPORT(void)
init_gst (void)
{
@ -156,7 +147,7 @@ init_gst (void)
}
/* _pygst_register_boxed_types (NULL); */
pygobject_register_sinkfunc(GST_TYPE_OBJECT, sink_gstobject);
pygobject_register_sinkfunc(GST_TYPE_OBJECT, pygstobject_sink);
m = Py_InitModule ("_gst", pygst_functions);
d = PyModule_GetDict (m);

View file

@ -94,7 +94,7 @@ pad_private(GstPad *pad)
private = g_object_get_qdata (G_OBJECT (pad), padprivate);
if (private == NULL) {
private = g_new0(PyGstPadPrivate, 1);
private->pad = (PyGObject *) pygobject_new (G_OBJECT (pad));
private->pad = (PyGObject *) pygstobject_new (G_OBJECT (pad));
Py_DECREF (private->pad);
g_object_set_qdata_full (G_OBJECT (pad), padprivate, private, free_pad_private);
}
@ -128,7 +128,7 @@ probe_handler_marshal(GstPad *pad, GstMiniObject *data, gpointer user_data)
callback = PyTuple_GetItem(py_user_data, 0);
args = Py_BuildValue("(NN)",
pygobject_new(G_OBJECT(pad)),
pygstobject_new(G_OBJECT(pad)),
py_data);
len = PyTuple_Size(py_user_data);
@ -866,7 +866,7 @@ _wrap_gst_pad_get_internal_links (PyGObject * self)
ret = PyList_New(0);
for (tmp = lst ; tmp; tmp = g_list_next(tmp)) {
PyList_Append(ret, pygobject_new(G_OBJECT(tmp->data)));
PyList_Append(ret, pygstobject_new(G_OBJECT(tmp->data)));
}
g_list_free(lst);
return ret;
@ -883,7 +883,7 @@ _wrap_gst_pad_get_internal_links_default (PyGObject * self)
ret = PyList_New(0);
for (tmp = lst ; tmp; tmp = g_list_next(tmp)) {
PyList_Append(ret, pygobject_new(G_OBJECT(tmp->data)));
PyList_Append(ret, pygstobject_new(G_OBJECT(tmp->data)));
}
g_list_free(lst);
return ret;
@ -963,7 +963,7 @@ pad_block_callback_marshal(GstPad *pad, gboolean blocked, gpointer user_data)
callback = PyTuple_GetItem(py_user_data, 0);
args = Py_BuildValue("(NN)",
pygobject_new(G_OBJECT(pad)),
pygstobject_new(G_OBJECT(pad)),
py_data);
len = PyTuple_Size(py_user_data);

View file

@ -65,7 +65,7 @@ _wrap_gst_tuner_list_channels(PyGObject *self)
py_list = PyList_New(0);
for (l = list; l; l = l->next) {
GstTunerChannel *channel = (GstTunerChannel*)l->data;
PyObject *py_channel = pygobject_new(G_OBJECT(channel));
PyObject *py_channel = pygstobject_new(G_OBJECT(channel));
PyList_Append(py_list, py_channel);
Py_DECREF(py_channel);
}
@ -87,7 +87,7 @@ _wrap_gst_tuner_list_norms(PyGObject *self)
py_list = PyList_New(0);
for (l = list; l; l = l->next) {
GstTunerNorm *norm = (GstTunerNorm*)l->data;
PyObject *py_norm = pygobject_new(G_OBJECT(norm));
PyObject *py_norm = pygstobject_new(G_OBJECT(norm));
PyList_Append(py_list, py_norm);
Py_DECREF(py_norm);
}
@ -109,7 +109,7 @@ _wrap_gst_mixer_list_tracks(PyGObject *self)
py_list = PyList_New(0);
for (l = list; l; l = l->next) {
GstMixerTrack *track = (GstMixerTrack*)l->data;
PyObject *py_track = pygobject_new(G_OBJECT(track));
PyObject *py_track = pygstobject_new(G_OBJECT(track));
PyList_Append(py_list, py_track);
Py_DECREF(py_track);
}
@ -131,7 +131,7 @@ _wrap_gst_color_balance_list_channels(PyGObject *self)
py_list = PyList_New(0);
for (l = list; l; l = l->next) {
GstColorBalanceChannel *channel = (GstColorBalanceChannel*)l->data;
PyObject *py_channel = pygobject_new(G_OBJECT(channel));
PyObject *py_channel = pygstobject_new(G_OBJECT(channel));
PyList_Append(py_list, py_channel);
Py_DECREF(py_channel);
}

121
gst/pygstobject.c Normal file
View file

@ -0,0 +1,121 @@
/* -*- Mode: C; ; c-file-style: "k&r"; c-basic-offset: 4 -*- */
/* gst-python
* Copyright (C) 2002 David I. Lehn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: David I. Lehn <dlehn@users.sourceforge.net>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "pygstobject.h"
#include <locale.h>
/* include this first, before NO_IMPORT_PYGOBJECT is defined */
#include <pygobject.h>
#include <gst/gst.h>
#include <gst/gstversion.h>
/* we reuse the same string for our quark so we get the same qdata;
* it might be worth it to use our own to shake out all instances
* were GObject-only calls are being used where we should be using
* gst_object_ */
static const gchar *pygobject_wrapper_id = "PyGObject::wrapper";
static GQuark pygobject_wrapper_key = 0;
/* only use on GstObject */
void
pygstobject_sink(GObject *object)
{
g_assert (GST_IS_OBJECT (object));
if (GST_OBJECT_IS_FLOATING(object)) {
gst_object_ref(GST_OBJECT(object));
gst_object_sink(GST_OBJECT(object));
}
}
/* functions used by the code generator we can call on both
* GstObject and non-GstObject GObjects
*/
/* to be called instead of pygobject_new */
PyObject *
pygstobject_new(GObject *obj)
{
PyGObject *self = NULL;
if (!GST_IS_OBJECT (obj))
return pygobject_new (obj);
GST_DEBUG_OBJECT (obj, "wrapping GstObject");
if (!pygobject_wrapper_key)
pygobject_wrapper_key = g_quark_from_static_string(pygobject_wrapper_id);
if (obj == NULL) {
Py_INCREF(Py_None);
return Py_None;
}
/* we already have a wrapper for this object -- return it. */
self = (PyGObject *)g_object_get_qdata(obj, pygobject_wrapper_key);
if (self != NULL) {
Py_INCREF(self);
} else {
/* create wrapper */
PyTypeObject *tp = pygobject_lookup_class(G_OBJECT_TYPE(obj));
/* need to bump type refcount if created with
pygobject_new_with_interfaces(). fixes bug #141042 */
if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE)
Py_INCREF(tp);
self = PyObject_GC_New(PyGObject, tp);
if (self == NULL)
return NULL;
pyg_begin_allow_threads;
self->obj = gst_object_ref(obj);
pyg_end_allow_threads;
pygstobject_sink(self->obj);
self->inst_dict = NULL;
self->weakreflist = NULL;
self->closures = NULL;
/* save wrapper pointer so we can access it later */
Py_INCREF(self);
g_object_set_qdata_full(obj, pygobject_wrapper_key, self,
pyg_destroy_notify);
PyObject_GC_Track((PyObject *)self);
}
GST_DEBUG_OBJECT (obj, "wrapped GstObject as PyObject %p", self);
return (PyObject *)self;
}
/* to be called instead of g_object_unref */
void
pygst_object_unref(GObject *obj)
{
if (GST_IS_OBJECT (obj)) {
GST_DEBUG_OBJECT (obj, "unreffing GstObject");
gst_object_unref (obj);
} else
g_object_unref (obj);
}

36
gst/pygstobject.h Normal file
View file

@ -0,0 +1,36 @@
/* -*- Mode: C; ; c-file-style: "k&r"; c-basic-offset: 4 -*- */
/* gst-python
* Copyright (C) 2002 David I. Lehn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: David I. Lehn <dlehn@users.sourceforge.net>
*/
#ifndef _PYGSTOBJECT_H_
#define _PYGSTOBJECT_H_
#include "common.h"
G_BEGIN_DECLS
void pygstobject_sink(GObject *object);
PyObject * pygstobject_new(GObject *obj);
void pygst_object_unref(GObject *obj);
G_END_DECLS
#endif /* !_PYGSTOBJECT_H_ */

View file

@ -22,6 +22,9 @@
from common import gst, unittest
import sys
import gc
# since I can't subclass gst.Element for some reason, I use a bin here
# it don't matter to Jesus
class TestElement(gst.Bin):
@ -180,6 +183,8 @@ class QueueTest(unittest.TestCase):
queue = gst.element_factory_make('queue')
assert isinstance(queue, gst.Queue)
assert queue.get_name() == 'queue0'
self.assertEquals(queue.__gstrefcount__, 1)
class DebugTest(unittest.TestCase):
def testDebug(self):

View file

@ -21,17 +21,43 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from common import gst, unittest
import sys
import gc
class PadTemplateTest(unittest.TestCase):
def tearDown(self):
gst.debug('garbage collecting')
gc.collect()
gst.debug('done garbage collecting')
def testConstructor(self):
self.failUnless(gst.PadTemplate("template", gst.PAD_SINK,
gst.PAD_ALWAYS, gst.caps_from_string("audio/x-raw-int")))
template = gst.PadTemplate("template", gst.PAD_SINK,
gst.PAD_ALWAYS, gst.caps_from_string("audio/x-raw-int"))
self.failUnless(template)
self.assertEquals(sys.getrefcount(template), 3)
#self.assertEquals(template.__gstrefcount__, 1)
class PadTest(unittest.TestCase):
def tearDown(self):
gst.debug('garbage collecting')
gc.collect()
gst.debug('done garbage collecting')
#elements = [o for o in gc.get_objects() if isinstance(o, gst.Element)]
#self.failIf(elements, elements)
#pads = [o for o in gc.get_objects() if isinstance(o, gst.Pad)]
#self.failIf(pads, pads)
def testConstructor(self):
# first style uses gst_pad_new
gst.debug('creating pad with name src')
self.failUnless(gst.Pad("src", gst.PAD_SRC))
print "creating pad with src"
pad = gst.Pad("src", gst.PAD_SRC)
print pad
self.failUnless(pad)
self.assertEquals(sys.getrefcount(pad), 3)
self.assertEquals(pad.__gstrefcount__, 1)
gst.debug('creating pad with no name')
self.failUnless(gst.Pad(None, gst.PAD_SRC))
self.failUnless(gst.Pad(name=None, direction=gst.PAD_SRC))
@ -46,6 +72,15 @@ class PadPipelineTest(unittest.TestCase):
self.pipeline = gst.parse_launch('fakesrc name=source ! fakesink')
src = self.pipeline.get_by_name('source')
self.srcpad = src.get_pad('src')
def tearDown(self):
del self.pipeline
del self.srcpad
gst.debug('garbage collecting')
gc.collect()
gst.debug('done garbage collecting')
#elements = [o for o in gc.get_objects() if isinstance(o, gst.Element)]
#self.failIf(elements, elements)
# FIXME: now that GstQuery is a miniobject with various _new_ factory
# functions, we need to figure out a way to deal with them in python
@ -62,6 +97,14 @@ class PadProbeTest(unittest.TestCase):
self.pipeline.add_many(self.fakesrc, self.fakesink)
self.fakesrc.link(self.fakesink)
def tearDown(self):
del self.pipeline
del self.fakesrc
del self.fakesink
gst.debug('garbage collecting')
gc.collect()
gst.debug('done garbage collecting')
def testFakeSrcProbeOnce(self):
self.fakesrc.set_property('num-buffers', 1)
@ -110,6 +153,24 @@ class PadProbeTest(unittest.TestCase):
assert self._num_times_called == 1
self.pipeline.set_state(gst.STATE_NULL)
class PadRefCountTest(unittest.TestCase):
def tearDown(self):
gst.debug('garbage collecting')
gc.collect()
gst.debug('done garbage collecting')
def testAddPad(self):
# add a pad to an element
e = gst.element_factory_make('fakesrc')
gst.debug('creating pad with name mpypad')
pad = gst.Pad("mpypad", gst.PAD_SRC)
self.failUnless(pad)
e.add_pad(pad)
gst.debug('deleting element')
del e
gst.debug('garbage collecting')
gc.collect()
gst.debug('done garbage collecting')
if __name__ == "__main__":
unittest.main()