mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 03:35:21 +00:00
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:
parent
1bc63d73b9
commit
5768672390
16 changed files with 392 additions and 35 deletions
26
ChangeLog
26
ChangeLog
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
(parent "GObject")
|
||||
(c-name "GstObject")
|
||||
(gtype-id "GST_TYPE_OBJECT")
|
||||
(fields
|
||||
'("int" "__gstrefcount__")
|
||||
)
|
||||
)
|
||||
|
||||
(define-object Index
|
||||
|
|
110
gst/gst.override
110
gst/gst.override
|
@ -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 *
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
121
gst/pygstobject.c
Normal 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
36
gst/pygstobject.h
Normal 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_ */
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue