gst/gst.defs: parse_launch also owns the return ref

Original commit message from CVS:

* gst/gst.defs:
parse_launch also owns the return ref
* gst/gstbin.override:
fix a leak in get_by_name()
* testsuite/common.py:
loop when garbage collecting; necessary when deleting, say,
a pipeline, that contains elements, to ensure the elements
also get collected
* testsuite/test_element.py:
* testsuite/test_pipeline.py:
test for garbage collection
This commit is contained in:
Thomas Vander Stichele 2005-09-28 14:20:03 +00:00
parent cb4e57360e
commit d1d42bd770
6 changed files with 85 additions and 13 deletions

View file

@ -1,3 +1,17 @@
2005-09-28 Thomas Vander Stichele <thomas at apestaart dot org>
* gst/gst.defs:
parse_launch also owns the return ref
* gst/gstbin.override:
fix a leak in get_by_name()
* testsuite/common.py:
loop when garbage collecting; necessary when deleting, say,
a pipeline, that contains elements, to ensure the elements
also get collected
* testsuite/test_element.py:
* testsuite/test_pipeline.py:
test for garbage collection
2005-09-28 Thomas Vander Stichele <thomas at apestaart dot org> 2005-09-28 Thomas Vander Stichele <thomas at apestaart dot org>
* testsuite/common.py: * testsuite/common.py:

View file

@ -3686,6 +3686,7 @@
(define-function parse_launch (define-function parse_launch
(c-name "gst_parse_launch") (c-name "gst_parse_launch")
(return-type "GstElement*") (return-type "GstElement*")
(caller-owns-return #t)
(parameters (parameters
'("const-gchar*" "pipeline_description") '("const-gchar*" "pipeline_description")
'("GError**" "error") '("GError**" "error")
@ -3695,6 +3696,7 @@
(define-function parse_launchv (define-function parse_launchv
(c-name "gst_parse_launchv") (c-name "gst_parse_launchv")
(return-type "GstElement*") (return-type "GstElement*")
(caller-owns-return #t)
(parameters (parameters
'("const-gchar**" "argv") '("const-gchar**" "argv")
'("GError**" "error") '("GError**" "error")

View file

@ -139,17 +139,21 @@ _wrap_gst_bin_get_by_name(PyGObject *self, PyObject *args, PyObject *kwargs)
static char *kwlist[] = { "name", "recurse", NULL }; static char *kwlist[] = { "name", "recurse", NULL };
char *name; char *name;
gboolean recurse = FALSE; gboolean recurse = FALSE;
GstElement *ret; GstElement *el;
PyObject *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|b:GstBin.get_by_name", if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|b:GstBin.get_by_name",
kwlist, &name, &recurse)) kwlist, &name, &recurse))
return NULL; return NULL;
if (recurse) if (recurse)
ret = gst_bin_get_by_name_recurse_up(GST_BIN(self->obj), name); el = gst_bin_get_by_name_recurse_up(GST_BIN(self->obj), name);
else else
ret = gst_bin_get_by_name(GST_BIN(self->obj), name); el = gst_bin_get_by_name(GST_BIN(self->obj), name);
/* pygobject_new handles NULL checking */ /* pygobject_new handles NULL checking */
return pygstobject_new((GObject *)ret); ret = pygstobject_new((GObject *)el);
gst_object_unref (el); /* from _get_by_name */
return ret;
} }

View file

@ -114,9 +114,14 @@ def run_silent(function, *args, **kwargs):
class TestCase(unittest.TestCase): class TestCase(unittest.TestCase):
def gccollect(self): def gccollect(self):
# run the garbage collector # run the garbage collector
ret = 0
gst.debug('garbage collecting') gst.debug('garbage collecting')
gc.collect() while True:
c = gc.collect()
ret += c
if c == 0: break
gst.debug('done garbage collecting') gst.debug('done garbage collecting')
return ret
def gctrack(self): def gctrack(self):
# store all gst objects in the gc in a tracking dict # store all gst objects in the gc in a tracking dict

View file

@ -20,10 +20,9 @@
# License along with this library; if not, write to the Free Software # License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from common import gst, unittest from common import gst, unittest, TestCase
import sys import sys
import gc
# since I can't subclass gst.Element for some reason, I use a bin here # since I can't subclass gst.Element for some reason, I use a bin here
# it don't matter to Jesus # it don't matter to Jesus
@ -165,18 +164,36 @@ class ElementName(unittest.TestCase):
assert get_name(-1) == 'UNKNOWN!(-1)' assert get_name(-1) == 'UNKNOWN!(-1)'
self.assertRaises(TypeError, get_name, '') self.assertRaises(TypeError, get_name, '')
class QueryTest(unittest.TestCase): class QueryTest(TestCase):
def setUp(self): def setUp(self):
self.gctrack()
self.pipeline = gst.parse_launch('fakesrc name=source ! fakesink') self.pipeline = gst.parse_launch('fakesrc name=source ! fakesink')
self.assertEquals(self.pipeline.__gstrefcount__, 1)
self.element = self.pipeline.get_by_name('source') self.element = self.pipeline.get_by_name('source')
self.assertEquals(self.pipeline.__gstrefcount__, 1)
self.assertEquals(self.element.__gstrefcount__, 2)
self.assertEquals(sys.getrefcount(self.element), 3)
def tearDown(self):
del self.pipeline
del self.element
self.gccollect()
self.gcverify()
def testQuery(self): def testQuery(self):
gst.debug('querying fakesrc in FORMAT_BYTES')
res = self.element.query_position(gst.FORMAT_BYTES) res = self.element.query_position(gst.FORMAT_BYTES)
self.assertEquals(self.pipeline.__gstrefcount__, 1)
self.assertEquals(sys.getrefcount(self.pipeline), 3)
self.assertEquals(self.element.__gstrefcount__, 2)
self.assertEquals(sys.getrefcount(self.element), 3)
assert res assert res
assert res[0] == 0 assert res[0] == 0
assert res[1] == -1 assert res[1] == -1
res = self.element.query_position(gst.FORMAT_TIME) res = self.element.query_position(gst.FORMAT_TIME)
assert not res assert not res
self.gccollect()
class QueueTest(unittest.TestCase): class QueueTest(unittest.TestCase):
def testConstruct(self): def testConstruct(self):

View file

@ -22,20 +22,37 @@
import time import time
from common import gst, unittest from common import gst, unittest, TestCase
import gobject import gobject
class PipelineConstructor(unittest.TestCase): class TestConstruction(TestCase):
def setUp(self):
self.gctrack()
def tearDown(self):
self.gccollect()
self.gcverify()
def testGoodConstructor(self): def testGoodConstructor(self):
name = 'test-pipeline' name = 'test-pipeline'
pipeline = gst.Pipeline(name) pipeline = gst.Pipeline(name)
self.assertEquals(pipeline.__gstrefcount__, 1)
assert pipeline is not None, 'pipeline is None' assert pipeline is not None, 'pipeline is None'
assert isinstance(pipeline, gst.Pipeline), 'pipeline is not a GstPipline' self.failUnless(isinstance(pipeline, gst.Pipeline),
'pipeline is not a GstPipline')
assert pipeline.get_name() == name, 'pipelines name is wrong' assert pipeline.get_name() == name, 'pipelines name is wrong'
self.assertEquals(pipeline.__gstrefcount__, 1)
class Pipeline(unittest.TestCase): def testParseLaunch(self):
pipeline = gst.parse_launch('fakesrc ! fakesink')
del pipeline
pass
class Pipeline(TestCase):
def setUp(self): def setUp(self):
self.gctrack()
self.pipeline = gst.Pipeline('test-pipeline') self.pipeline = gst.Pipeline('test-pipeline')
source = gst.element_factory_make('fakesrc', 'source') source = gst.element_factory_make('fakesrc', 'source')
source.set_property('num-buffers', 5) source.set_property('num-buffers', 5)
@ -43,6 +60,11 @@ class Pipeline(unittest.TestCase):
self.pipeline.add_many(source, sink) self.pipeline.add_many(source, sink)
gst.element_link_many(source, sink) gst.element_link_many(source, sink)
def tearDown(self):
del self.pipeline
self.gccollect()
self.gcverify()
def testRun(self): def testRun(self):
self.assertEqual(self.pipeline.get_state(None)[1], gst.STATE_NULL) self.assertEqual(self.pipeline.get_state(None)[1], gst.STATE_NULL)
self.pipeline.set_state(gst.STATE_PLAYING) self.pipeline.set_state(gst.STATE_PLAYING)
@ -54,8 +76,9 @@ class Pipeline(unittest.TestCase):
self.pipeline.set_state(gst.STATE_NULL) self.pipeline.set_state(gst.STATE_NULL)
self.assertEqual(self.pipeline.get_state(None)[1], gst.STATE_NULL) self.assertEqual(self.pipeline.get_state(None)[1], gst.STATE_NULL)
class PipelineAndBus(unittest.TestCase): class PipelineAndBus(TestCase):
def setUp(self): def setUp(self):
self.gctrack()
self.pipeline = gst.Pipeline('test-pipeline') self.pipeline = gst.Pipeline('test-pipeline')
self.pipeline.set_property('play-timeout', 0L) self.pipeline.set_property('play-timeout', 0L)
source = gst.element_factory_make('fakesrc', 'source') source = gst.element_factory_make('fakesrc', 'source')
@ -68,6 +91,13 @@ class PipelineAndBus(unittest.TestCase):
self.loop = gobject.MainLoop() self.loop = gobject.MainLoop()
def tearDown(self):
# FIXME: fix the refcount issues with the bus/pipeline
#del self.pipeline
#del self.bus
self.gccollect()
#self.gcverify()
def _message_received(self, bus, message): def _message_received(self, bus, message):
gst.debug('received message: %s, %s' % ( gst.debug('received message: %s, %s' % (
message.src.get_path_string(), message.type.value_nicks[1])) message.src.get_path_string(), message.type.value_nicks[1]))