I want to take time into discussing how GStreamer handles foreign objects to the GObject system. Assigning or obtaining element, pad or pad template properties in Python is pretty trivial as these are exposed as if they were Python object properties. An issue arises when we have to deal with types that are foreign to the GObject system, notably those coming from Qt or a machine learning library, which may have Python bindings too. This stems from gstreamer!8208 where I’ve used metaclasses to implement property getters and setters in a very hackish way.
Currently GStreamer uses void pointers to store these properties, such being the case of the Qt QML plugin. This for all intents and purposes fits the needs of an application developed in a systems language such as C, C++ or Rust. But if you try to do the same, for instance, in Python, exceptions will be thrown.
sink = Gst.ElementFactory.make("qml6glsink")
sink.set_property("widget", item) # This line raises an exception.
sink.get_property("widget") # This doesn't contain the item.
src = Gst.ElementFactory.make("qml6glsrc")
src.set_property("window", window) # This also fails.
src.get_property("window") # Not the window.
I have some alternatives to solve this problem, each of them having their pros and cons.
The best option in my opinion would be to implement a parameter spec for a foreign type that wraps a void pointer so that Python converters could be added without having to actually change native applications.
GstParamSpecForegin*
gst_param_spec_foreign (name, brief, description, wrapped, value, flags);
Here the wrapped parameter is a string that names the foreign type so that when the PyGObject gi/overrides code detects the parameter spec it installs hooks from a file placed in, for example, the gi/foreign directory. Theoretically, it could be like this.
# gi/foreign/qt.py
from gi.foreign import ForeignProperty
class ForeignQQuickItem(ForeignProperty):
def getter(self, intptr):
return wrapToQt(intptr)
def setter(self, value):
return unwrapFromQt(value)
Another way would be to also use scripts in the gi/overrides directory, but instead of supplying converters we implement class overrides for each type that derives from GstObject. This is much like the mentioned merge request.
# gi/overrides/gstqthelper.py
# ...
overrides = {
"GstQml6GLSink": {
"widget": {
"get": get_widget,
"set": set_widget,
},
},
"GstQml6GLSrc": {
"window": {
"get": get_window,
"set": set_window,
},
},
}
The other, more involved, solution is to implement a GStreamer library for each plugin that has foreign types and expose them in the GIRepository so that we can supply overrides for the contained types. This is not practical for obvious reasons.
If you have any suggestions, I’d be glad to hear them as I want to fix this issue.