From: <th...@ke...> - 2007-04-10 18:01:45
|
CVS Root: /cvs/gstreamer Module: gst-python Changes by: thaytan Date: Tue Apr 10 2007 18:01:37 UTC Log message: * examples/pyidentity.py: * gst/common.h: * gst/gstpad.override: Implement pad query proxying so that python elements can answer pad queries. Fixes: #428299 Modified files: . : ChangeLog examples : pyidentity.py gst : common.h gstpad.override Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-python/ChangeLog.diff?r1=1.578&r2=1.579 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-python/examples/pyidentity.py.diff?r1=1.1&r2=1.2 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-python/gst/common.h.diff?r1=1.18&r2=1.19 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-python/gst/gstpad.override.diff?r1=1.39&r2=1.40 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gst-python/ChangeLog,v retrieving revision 1.578 retrieving revision 1.579 diff -u -d -r1.578 -r1.579 --- ChangeLog 10 Apr 2007 12:44:44 -0000 1.578 +++ ChangeLog 10 Apr 2007 18:01:25 -0000 1.579 @@ -1,6 +1,14 @@ 2007-04-10 Jan Schmidt <th...@ma...> * 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 <th...@ma...> + * 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 Index: pyidentity.py RCS file: /cvs/gstreamer/gst-python/examples/pyidentity.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- pyidentity.py 10 Apr 2007 12:44:44 -0000 1.1 +++ pyidentity.py 10 Apr 2007 18:01:25 -0000 1.2 @@ -32,6 +32,7 @@ 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 @@ 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) Index: common.h RCS file: /cvs/gstreamer/gst-python/gst/common.h,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- common.h 4 Apr 2007 12:22:03 -0000 1.18 +++ common.h 10 Apr 2007 18:01:25 -0000 1.19 @@ -54,6 +54,9 @@ 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 { Index: gstpad.override RCS file: /cvs/gstreamer/gst-python/gst/gstpad.override,v retrieving revision 1.39 retrieving revision 1.40 diff -u -d -r1.39 -r1.40 --- gstpad.override 4 Feb 2007 10:54:48 -0000 1.39 +++ gstpad.override 10 Apr 2007 18:01:25 -0000 1.40 @@ -85,6 +85,11 @@ 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 @@ %% +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; +} +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); + + /* 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) { + Py_DECREF(py_args); + 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; + 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"); + 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 |