From d3a4c03c2b578b7fd63b259ad0967731f2c1cc16 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 10 Apr 2007 18:01:25 +0000 Subject: [PATCH] Implement pad query proxying so that python elements can answer pad queries. Fixes: #428299 Original commit message from CVS: * examples/pyidentity.py: * gst/common.h: * gst/gstpad.override: Implement pad query proxying so that python elements can answer pad queries. Fixes: #428299 --- ChangeLog | 8 +++ examples/pyidentity.py | 3 + gst/common.h | 3 + gst/gstpad.override | 147 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+) diff --git a/ChangeLog b/ChangeLog index 5543d72..31fb2e1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,14 @@ 2007-04-10 Jan Schmidt * examples/pyidentity.py: + * gst/common.h: + * gst/gstpad.override: + Implement pad query proxying so that python elements can + answer pad queries. Fixes: #428299 + +2007-04-10 Jan Schmidt + + * examples/pyidentity.py: Add a simple example that implements an identity-like element in python and passes buffers through. It lacks buffer-alloc & query handling at the moment, because the required gstreamer funcs aren't diff --git a/examples/pyidentity.py b/examples/pyidentity.py index e864892..184c8c5 100644 --- a/examples/pyidentity.py +++ b/examples/pyidentity.py @@ -32,6 +32,7 @@ class PyIdentity(gst.Element): self.srcpad = gst.Pad(self._srcpadtemplate, "src") self.srcpad.set_event_function(self.srceventfunc) + self.srcpad.set_query_function(self.srcqueryfunc) self.srcpad.set_getcaps_function(gst.Pad.proxy_getcaps) self.srcpad.set_setcaps_function(gst.Pad.proxy_setcaps) self.add_pad (self.srcpad) @@ -43,6 +44,8 @@ class PyIdentity(gst.Element): def eventfunc(self, pad, event): return self.srcpad.push_event (event) + def srcqueryfunc (self, pad, query): + return self.sinkpad.query (query) def srceventfunc (self, pad, event): return self.sinkpad.push_event (event) diff --git a/gst/common.h b/gst/common.h index bf4676c..68ce75f 100644 --- a/gst/common.h +++ b/gst/common.h @@ -54,6 +54,9 @@ typedef struct { GClosure *activate_function; GClosure *activatepull_function; GClosure *activatepush_function; + /* Query is not implemented as a closure to avoid refcounting + * making the query immutable and therefore useless */ + PyObject *query_function; } PyGstPadPrivate; typedef struct { diff --git a/gst/gstpad.override b/gst/gstpad.override index cc9e1ff..07c24e6 100644 --- a/gst/gstpad.override +++ b/gst/gstpad.override @@ -85,6 +85,11 @@ free_pad_private (gpointer data) INVALIDATE_CLOSURE (private->activatepull_function) INVALIDATE_CLOSURE (private->activatepush_function) #undef INVALIDATE_CLOSURE + + if (private->query_function) { + Py_DECREF (private->query_function); + private->query_function = NULL; + } } static PyGstPadPrivate* @@ -352,6 +357,148 @@ _wrap_gst_pad_set_event_function (PyGObject *self, } %% +override gst_pad_set_query_function kwargs + +static gboolean +pypad_copy_struct_members (GQuark field_id, const GValue * value, + GstStructure* to_structure) +{ + gst_structure_id_set_value (to_structure, field_id, value); + + return TRUE; +} + +static gboolean +call_query_function (GstPad *pad, GstQuery *query) +{ + PyGILState_STATE __py_state; + PyGObject *py_pad; + PyGstPadPrivate *priv; + + PyObject *py_ret; + PyObject *py_args; + gboolean ret = FALSE; + GstQuery *query_copy; + PyObject *py_query; + + /* Push our GIL state */ + __py_state = pyg_gil_state_ensure(); + + /* Get the python version of the pad */ + py_pad = (PyGObject *) pygobject_new((GObject*) (pad)); + if (!py_pad) { + if (PyErr_Occurred()) + PyErr_Print(); + goto beach; + } + /* Private data, where our callback should be stored */ + priv = py_pad_private(py_pad); + if (priv->query_function == NULL) { + /* FIXME: Generate an error message somewhere? */ + Py_DECREF(py_pad); + goto beach; + } + + /* Create our arguments tuple and populate */ + py_args = PyTuple_New(2); + + /* We copy the query into a new one so that it can have a refcount + * of exactly 1 and be owned by python */ + pyg_begin_allow_threads; + query_copy = gst_query_copy (query); + pyg_end_allow_threads; + py_query = pygstminiobject_new((GstMiniObject *)query_copy); + gst_query_unref (query_copy); + + PyTuple_SetItem(py_args, 0, (PyObject *) (py_pad)); + PyTuple_SetItem(py_args, 1, py_query); + + /* Perform the callback into python, then parse the result */ + py_ret = PyObject_CallObject(priv->query_function, py_args); + if (!py_ret) { + if (PyErr_Occurred()) + PyErr_Print(); + + Py_DECREF(py_args); + goto beach; + } + + ret = (py_ret == Py_True ? TRUE : FALSE); + + /* If the query succeeded, copy the result back into the original query. + * We still have a refcount to it, because we didn't unref the py_query + * wrapper yet. */ + if (ret) { + /* I feel ill violating the poor query like this, but it's the only + * way to transfer data from our copy back to the original query */ + GstStructure *from, *to; + + pyg_begin_allow_threads; + from = GST_QUERY (query_copy)->structure; + to = query->structure; + gst_structure_foreach (from, + (GstStructureForeachFunc) pypad_copy_struct_members, to); + pyg_end_allow_threads; + } + + Py_DECREF(py_args); + Py_DECREF(py_ret); +beach: + pyg_gil_state_release(__py_state); + + return ret; +} + +static PyObject* +_wrap_gst_pad_set_query_function (PyGObject *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "query_function", NULL }; + PyObject *function; + GstPad *pad; + PyGstPadPrivate *priv; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O:GstPad.set_query_function", + kwlist, + &function)) { + return NULL; + } + + pad = (GstPad*)pygobject_get(self); + priv = py_pad_private(self); + + /* Allow setting query_function to None to clear it to NULL */ + if (function == Py_None) { + if (priv->query_function) { + Py_DECREF (priv->query_function); + priv->query_function = NULL; + } + gst_pad_set_query_function (pad, NULL); + goto out; + } + + if (!PyCallable_Check(function)) { + PyErr_SetString(PyExc_TypeError, "Passed query_function not callable"); + return NULL; + } + + if (priv->query_function) { + Py_DECREF (priv->query_function); + } + + Py_INCREF(function); + priv->query_function = function; + + gst_pad_set_query_function (pad, call_query_function); + +out: + Py_INCREF(Py_None); + return Py_None; +} + +%% override gst_pad_set_setcaps_function kwargs static void EXCEPTION_HANDLER -- 2.7.4