From 904bb001c53a2bcd7eef5858c451ce8c4d2a03d0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 6 Dec 2021 19:27:24 -0300 Subject: [PATCH] python: Add support for the GstURIHandlerInterface Part-of: --- .../examples/plugins/python/sinkelement.py | 20 +++- subprojects/gst-python/gi/overrides/Gst.py | 8 ++ subprojects/gst-python/gi/overrides/gstmodule.c | 112 +++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) diff --git a/subprojects/gst-python/examples/plugins/python/sinkelement.py b/subprojects/gst-python/examples/plugins/python/sinkelement.py index 2ec3608..94281e4 100644 --- a/subprojects/gst-python/examples/plugins/python/sinkelement.py +++ b/subprojects/gst-python/examples/plugins/python/sinkelement.py @@ -15,6 +15,10 @@ # # $ export GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD/plugin:$PWD/examples/plugins # $ GST_DEBUG=python:4 gst-launch-1.0 fakesrc num-buffers=10 ! mysink +# +# Since this implements the `mypysink://` protocol you can also do: +# +# $ gst-launch-1.0 videotestsrc ! pymysink:// from gi.repository import Gst, GObject, GstBase Gst.init(None) @@ -22,7 +26,7 @@ Gst.init(None) # # Simple Sink element created entirely in python # -class MySink(GstBase.BaseSink): +class MySink(GstBase.BaseSink, Gst.URIHandler): __gstmetadata__ = ('CustomSink','Sink', \ 'Custom test sink element', 'Edward Hervey') @@ -31,9 +35,23 @@ class MySink(GstBase.BaseSink): Gst.PadPresence.ALWAYS, Gst.Caps.new_any()) + __protocols__ = ("pymysink",) + __uritype__ = Gst.URIType.SINK + + def __init__(self): + super().__init__() + # Working around https://gitlab.gnome.org/GNOME/pygobject/-/merge_requests/129 + self.__dontkillme = self + def do_render(self, buffer): Gst.info("timestamp(buffer):%s" % (Gst.TIME_ARGS(buffer.pts))) return Gst.FlowReturn.OK + def do_get_uri(self, uri): + return "pymysink://" + + def do_set_uri(self, uri): + return True + GObject.type_register(MySink) __gstelementfactory__ = ("mysink", Gst.Rank.NONE, MySink) diff --git a/subprojects/gst-python/gi/overrides/Gst.py b/subprojects/gst-python/gi/overrides/Gst.py index 1b75e35..1d5a44e 100644 --- a/subprojects/gst-python/gi/overrides/Gst.py +++ b/subprojects/gst-python/gi/overrides/Gst.py @@ -48,6 +48,14 @@ python module to use with Gst 0.10" warnings.warn(warn_msg, RuntimeWarning) +# Ensuring that PyGObject loads the URIHandler interface +# so we can force our own implementation soon enough (in gstmodule.c) +class URIHandler(Gst.URIHandler): + pass + +URIHandler = override(URIHandler) +__all__.append('URIHandler') + class Element(Gst.Element): @staticmethod def link_many(*args): diff --git a/subprojects/gst-python/gi/overrides/gstmodule.c b/subprojects/gst-python/gi/overrides/gstmodule.c index dc8364a..da52cd5 100644 --- a/subprojects/gst-python/gi/overrides/gstmodule.c +++ b/subprojects/gst-python/gi/overrides/gstmodule.c @@ -32,6 +32,9 @@ #include +#define URI_HANDLER_PROTOCOLS_QUARK g_quark_from_static_string("__gst__uri_handler_protocols") +#define URI_HANDLER_URITYPE_QUARK g_quark_from_static_string("__gst__uri_handler_uritype") + #define PYGLIB_MODULE_START(symbol, modname) \ static struct PyModuleDef _##symbol##module = { \ PyModuleDef_HEAD_INIT, \ @@ -1103,6 +1106,113 @@ static PyMethodDef _gi_gst_functions[] = { {NULL, NULL, 0, NULL} }; +static const gchar *const * +py_uri_handler_get_protocols (GType type) +{ + /* FIXME: Ideally we should be able to free the list of protocols on + * deinitialization */ + return g_type_get_qdata (type, URI_HANDLER_PROTOCOLS_QUARK); +} + +static GstURIType +py_uri_handler_get_type (GType type) +{ + return GPOINTER_TO_INT (g_type_get_qdata (type, URI_HANDLER_URITYPE_QUARK)); +} + +static const GStrv +py_uri_handler_get_protocols_from_pyobject (PyObject * protocols) +{ + GStrv res = NULL; + + if (PyTuple_Check (protocols)) { + gint i, len; + + len = PyTuple_Size (protocols); + if (len == 0) { + PyErr_Format (PyExc_TypeError, + "Empty tuple for GstUriHandler.__protocols"); + goto err; + } + + res = g_malloc (len * sizeof (gchar *)); + for (i = 0; i < len; i++) { + PyObject *protocol = (PyObject *) PyTuple_GetItem (protocols, i); + + if (!PyUnicode_Check (protocol)) { + Py_DECREF (protocol); + goto err; + } + + res[i] = g_strdup (PyUnicode_AsUTF8 (protocol)); + } + } else { + PyErr_Format (PyExc_TypeError, "invalid type for GstUriHandler.__protocols." + " Should be a tuple"); + goto err; + } + + return res; + +err: + Py_DECREF (protocols); + g_strfreev (res); + return FALSE; +} + +static void +uri_handler_iface_init (GstURIHandlerInterface * iface, PyTypeObject * pytype) +{ + gint uritype; + GStrv protocols; + PyObject *pyprotocols = pytype ? PyObject_GetAttrString ((PyObject *) pytype, + "__protocols__") : NULL; + PyObject *pyuritype = pytype ? PyObject_GetAttrString ((PyObject *) pytype, + "__uritype__") : NULL; + GType gtype = pyg_type_from_object ((PyObject *) pytype); + + if (pyprotocols == NULL) { + PyErr_Format (PyExc_KeyError, "__protocols__ missing in %s", + pytype->tp_name); + goto done; + } + + if (pyuritype == NULL) { + PyErr_Format (PyExc_KeyError, "__pyuritype__ missing in %s", + pytype->tp_name); + goto done; + } + + protocols = py_uri_handler_get_protocols_from_pyobject (pyprotocols); + if (!protocols) + goto done; + + if (pyg_enum_get_value (GST_TYPE_URI_TYPE, pyuritype, &uritype) < 0) { + PyErr_SetString (PyExc_TypeError, + "entry for __uritype__ must be of type GstURIType"); + goto done; + } + + iface->get_protocols = py_uri_handler_get_protocols; + g_type_set_qdata (gtype, URI_HANDLER_PROTOCOLS_QUARK, protocols); + + iface->get_type = py_uri_handler_get_type; + g_type_set_qdata (gtype, URI_HANDLER_URITYPE_QUARK, + GINT_TO_POINTER (uritype)); + +done: + if (pyprotocols) + Py_DECREF (pyprotocols); + if (pyuritype) + Py_DECREF (pyuritype); +} + +static const GInterfaceInfo GstURIHandlerInterfaceInfo = { + (GInterfaceInitFunc) uri_handler_iface_init, + NULL, + NULL +}; + PYGLIB_MODULE_START (_gi_gst, "_gi_gst") { PyObject *d; @@ -1120,6 +1230,8 @@ PYGLIB_MODULE_START (_gi_gst, "_gi_gst") d = PyModule_GetDict (module); gi_gst_register_types (d); pyg_register_class_init (GST_TYPE_ELEMENT, _pygst_element_init); + pyg_register_interface_info (GST_TYPE_URI_HANDLER, + &GstURIHandlerInterfaceInfo); } PYGLIB_MODULE_END; -- 2.7.4