GNOME Bugzilla – Bug 753754
Add GstValueList and GstValueArray support to gst-python
Last modified: 2017-08-05 14:24:57 UTC
As detailed in bug #669982, the GStreamer Python bindings currently lack support for GstValueList. As Sebastian pointed out in https://bugzilla.gnome.org/show_bug.cgi?id=669982#c5 some "override magic" would be nedded to overcome the lack of support in pygi. As it currently stands, elements using GstValueList to communicate (namely spectrum) are virtually unsupported in Python.
This issue not only affects the spectrum element but the much more widely used v4l2src element too. It certainly needs fixing.
There's also GstValueArray which works basically the same and would be good to have
We need to do something similare to http://cgit.freedesktop.org/gstreamer/gst-python/tree/gi/overrides/gstmodule.c#n131 for those GTypes
Am i correct in assuming that it is still not possible to get volume magnitude from python ?
(In reply to Arne Caspari from comment #1) > This issue not only affects the spectrum element but the much more widely > used v4l2src element too. It certainly needs fixing. How does this affect v4l2src ?
(In reply to Nicolas Dufresne (stormer) from comment #5) > How does this affect v4l2src ? It affects any caps that may contain a value list, for example: >>> from gi.repository import Gst >>> Gst.init(()) [] >>> src = Gst.ElementFactory.make("v4l2src") >>> src.set_property("device", "/dev/video1") >>> src.set_state(Gst.State.READY) <enum GST_STATE_CHANGE_SUCCESS of type Gst.StateChangeReturn> >>> caps = src.pads[0].query_caps() >>> s = caps.get_structure(0) >>> s.to_string() 'video/x-bayer, format=(string)gbrg, width=(int)744, height=(int)480, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 20000/263, 60/1, 30/1, 25/1, 15/1, 15/2, 5/1 };' >>> s.get_value("framerate") Traceback (most recent call last):
+ Trace 237275
>>>
While it would be interesting to have python specific bindings (even though not that trivial), I made a experiment today of a new API that would address this issue. What I did, and it was conclusive, is to implement GValueArray to/from GST_TYPE_ARRAY/LIST conversion (though g_value_transform). Then I implement those new function in GstStructure: gboolean gst_structure_get_array (s, fieldname, GValueArray ** array) gboolean gst_structure_get_list (s, fieldname, GValueArray **array) void gst_structure_set_array (s, fieldname, GValueArray * array) void gst_structure_set_list (s, fieldname, GValueArray * array) Then in Python, you can use it as follow: s = Gst.Structure.new_empty("test") arr = GObject.ValueArray() arr.append(1) arr.append(2) s.set_array("array", arr) ret, arr = s.get_array("array") I'll add similar helpers to get/set GST_TYPE_ARRAY/LIST object properties. The reason I went this way is that it's language agnostic, and representing those in an override seems more complex then just a Fraction.
Created attachment 348360 [details] [review] gstvalue: Add transformation to/from GValueArray This allow transforming a GValue of type G_TYPE_VALUE_ARRAY to and from GST_TYPE_ARRAY/LIST.
Created attachment 348361 [details] [review] structure: Add get/set_array/list using GValueArray This adds a binding friendly interface to get and set arrays and list into GstStructure. New API: - gst_structure_set_array - gst_structure_set_list - gst_structure_get_array - gst_structure_get_list
Created attachment 348362 [details] [review] gstutils: Add helpers to get/set array properties This is to help bindings access properties of type GST_TYPE_ARRAY. This function will get/set the property and convert form/to GValueArray. New API: gst_util_set_object_array gst_util_get_object_array
There is an interesting side effect that should be mentionned, you can now g_object_set() any GST_TYPE_LIST/GST_TYPE_ARRAY using a GValueArray (and vis-versa). GObject kindly call g_value_transform() internally. This is not usable from Python though, since the bindings will try and convert by itself. So if you pass a GValueArray, it won't wrap it into a GValue before setting it.
And same applies if you use g_object_get/get_property(). Meaning you don't even need to port code using those properties, at least in C.
*** Bug 693168 has been marked as a duplicate of this bug. ***
Ok, this is just not elegant, though the transform stuff is kind of nice to have, so maybe we could keep this one. I'll start adding stuff in the python overrides. That means at some point we should create gst-javascript if we want the same to be usable.
Created attachment 348593 [details] [review] overrides: Add more GstValue overrides This patch adds overrides to support IntRange, Int64Range, DoubleRange, FractionRange, Array and List. For integer ranges, it maps this to python 'range'. Gst.IntRange() and Gst.Int64Range() are simple cast to let the underlying code know which GType to use. To set such range in python you will do: structure.set_value("range", Gst.IntRange(range(0,10,2))) Same for the 64 bit variant. And when you do: r = structure.get_value("range") A range will be returned directly, without the wrapper. For DoubleRange and FractionRange, there is no native support in python. So the usage will be: structure.set_value("range", Gst.DoubleRange(0,10.0)) structure.set_value("range", Gst.FractionRange(Gst.Fraction(1/30), Gst.Fraction(1/5)) When getting this value, Gst.DoubleRange and Gst.FractionRange class are returned. They both have start/stop members. The naming was taken from range type. For Array and List, both uses the native list type, though they can be constructed from any python sequence. So again, the class is just like a cast, to let it pick the right GType and python list are being returned. structure.set_value("list", Gst.ValueList([1,2,3,4])) structure.set_value("array", Gst.ValueArray([1,2,3,4)) Using string and tuple could also work. Since Gst.ValueList/Array are sequence, you can convert one to the other with: list = Gst.ValueList([1,2,3,4]) array = Gst.ValueArray (list)
Review of attachment 348593 [details] [review]: Looks about right, but adding some unit tests would be very welcome :) ::: gi/overrides/gstmodule.c @@ -130,0 +130,40 @@ +static PyObject * +gi_gst_int_range_from_value (const GValue * value) +{ ... 37 more ... Please raise an exception here. @@ -130,0 +130,83 @@ +static PyObject * +gi_gst_int_range_from_value (const GValue * value) +{ ... 80 more ... Sounds like you should raise an exception here. @@ +271,3 @@ + return 0; + + goto fail; Same. @@ +348,3 @@ + return 0; + + PyErr_SetString (PyExc_KeyError, Same.
Comment on attachment 348593 [details] [review] overrides: Add more GstValue overrides Attachment 348593 [details] pushed as a4566ff - overrides: Add more GstValue overrides
Attachment 348360 [details] pushed as 84f826a - gstvalue: Add transformation to/from GValueArray Attachment 348361 [details] pushed as c21e219 - structure: Add get/set_array/list using GValueArray Attachment 348362 [details] pushed as 2c05656 - gstutils: Add helpers to get/set array properties
Voilà, so now we have both the workaround, and proper overrides in Python. Btw, I have added all exception code, added type check on the python side and finally added unit tests for everything (which has been very useful to find small bugs).
Dear Gstreamers, thank you for your work. I tried to run an application with the gstspectrum element in a python environment. When I read the elements message with the array of frequency magnitudes: def on_message(self, bus, message): s = message.get_structure() gva = s.get_value('magnitude') I still get: TypeError: unknown type GstValueArray. What is the difference between GstValueArray and Gst.ValueArray? What am I doing wrong? Gstreamer 1.12.2 Python 2.7.12 Linux pi-VirtualBox 4.4.0-53-generic #74-Ubuntu SMP ... x86_64 GNU/Linux
This ticket was closed and you don't seem to be reporting a regression, but instead requesting for support. The GStreamer mailing list is likely a better place for your question. P.s. Make sure you have gst-python 1.12 package properly installed.