From da9365176be29cd173ee6902592b75b653cabbe2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 May 2025 19:19:27 +0200 Subject: [PATCH] python: Add a Caps.get_value variant that does not copy the structures Keeping the __getitem__ implementation the same way This also now make structure.set_value() raise an exception if the structure was not writable Part-of: --- subprojects/gst-python/gi/overrides/Gst.py | 10 ++++- .../gst-python/gi/overrides/gstmodule.c | 42 +++++++++++++++++++ subprojects/gst-python/testsuite/test_gst.py | 37 ++++++++++++++-- 3 files changed, 85 insertions(+), 4 deletions(-) diff --git a/subprojects/gst-python/gi/overrides/Gst.py b/subprojects/gst-python/gi/overrides/Gst.py index 0939798b55..59a0b1e801 100644 --- a/subprojects/gst-python/gi/overrides/Gst.py +++ b/subprojects/gst-python/gi/overrides/Gst.py @@ -161,11 +161,16 @@ class Caps(Gst.Caps): def __getitem__(self, index): if index >= self.get_size(): raise IndexError('structure index out of range') - return self.get_structure(index) + + return Gst.Caps.get_structure(self, index) def __len__(self): return self.get_size() + def get_structure(self, index): + return StructureWrapper(_gi_gst.caps_get_structure(self, index), self, + False) + def get_structure_writable(self, index): return StructureWrapper(_gi_gst.caps_get_writable_structure(self, index), self, True) @@ -371,6 +376,9 @@ class Structure(Gst.Structure): self._writable = False pass + def __ptr__(self): + return _gi_gst._get_object_ptr(self) + def __getitem__(self, key): return self.get_value(key) diff --git a/subprojects/gst-python/gi/overrides/gstmodule.c b/subprojects/gst-python/gi/overrides/gstmodule.c index 9909c17ad0..0236e46c2f 100644 --- a/subprojects/gst-python/gi/overrides/gstmodule.c +++ b/subprojects/gst-python/gi/overrides/gstmodule.c @@ -989,6 +989,29 @@ _gst_caps_make_writable (PyObject * self, PyObject * args) return res; } +static PyObject * +_gst_caps_get_structure (PyObject * self, PyObject * args) +{ + PyTypeObject *gst_caps_type; + PyObject *py_caps, *py_structure; + GstCaps *caps; + gint idx; + + /* Look up Gst.Caps and Gst.Structure parameters */ + gst_caps_type = pygobject_lookup_class (_gst_caps_type); + if (!PyArg_ParseTuple (args, "O!i", gst_caps_type, &py_caps, &idx)) + return NULL; + + /* Extract GstCaps from Gst.Caps parameter */ + caps = GST_CAPS (pygobject_get (py_caps)); + + /* Get the structure at the given index */ + py_structure = pyg_boxed_new (_gst_structure_type, + gst_caps_get_structure (caps, idx), FALSE, FALSE); + + return py_structure; +} + static PyObject * _gst_caps_get_writable_structure (PyObject * self, PyObject * args) { @@ -1052,6 +1075,23 @@ _gst_memory_override_unmap (PyObject * self, PyObject * args) return success; } + +static PyObject * +_gst_get_object_ptr (PyObject * self, PyObject * args) +{ + PyObject *first_arg; + + first_arg = PyTuple_GetItem (args, 0); + gpointer ptr = pygobject_get (first_arg); + + if (ptr == NULL) { + PyErr_SetString (PyExc_TypeError, "Expected a PyGObject"); + return NULL; + } + + return PyLong_FromVoidPtr (ptr); +} + static PyObject * _gst_buffer_override_map_range (PyObject * self, PyObject * args) { @@ -1182,9 +1222,11 @@ static PyMethodDef _gi_gst_functions[] = { {"buffer_override_unmap", (PyCFunction) _gst_buffer_override_unmap, METH_VARARGS, NULL}, {"memory_override_map", (PyCFunction) _gst_memory_override_map, METH_VARARGS, NULL}, {"memory_override_unmap", (PyCFunction) _gst_memory_override_unmap, METH_VARARGS, NULL}, + {"caps_get_structure", (PyCFunction) _gst_caps_get_structure, METH_VARARGS, NULL}, {"caps_get_writable_structure", (PyCFunction) _gst_caps_get_writable_structure, METH_VARARGS, NULL}, {"caps_make_writable", (PyCFunction) _gst_caps_make_writable, METH_VARARGS, NULL}, {"caps_is_writable", (PyCFunction) _gst_caps_is_writable, METH_VARARGS, NULL}, + {"_get_object_ptr", (PyCFunction) _gst_get_object_ptr, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; /* *INDENT-ON* */ diff --git a/subprojects/gst-python/testsuite/test_gst.py b/subprojects/gst-python/testsuite/test_gst.py index 474c81786a..6f3994336f 100644 --- a/subprojects/gst-python/testsuite/test_gst.py +++ b/subprojects/gst-python/testsuite/test_gst.py @@ -132,7 +132,8 @@ class TestCaps(TestCase): s.set_value("rate", 44100) capsfilter.set_property("caps", caps) caps = capsfilter.get_property("caps") - self.assertEqual(caps[0]["rate"], 44100) + with caps.get_structure(0) as s: + self.assertEqual(s["rate"], 44100) def test_writable(self): Gst.init(None) @@ -141,8 +142,38 @@ class TestCaps(TestCase): with caps.get_structure_writable(0) as s: s.set_value("rate", 44100) s.set_value("channels", 2) - self.assertEqual(caps[0]["rate"], 44100) - self.assertEqual(caps[0]["channels"], 2) + with caps.get_structure(0) as s: + self.assertEqual(s["rate"], 44100) + self.assertEqual(s["channels"], 2) + + def test_delete_caps_while_accessing(self): + Gst.init(None) + caps = Gst.Caps("audio/x-raw") + + with caps.get_structure_writable(0) as s: + del caps + s.set_value("rate", 44100) + s.set_value("channels", 2) + self.assertEqual(s["rate"], 44100) + self.assertEqual(s["channels"], 2) + + def test_read_no_copy(self): + Gst.init(None) + caps = Gst.Caps("audio/x-raw") + + with caps.get_structure(0) as s: + ptr = s.__ptr__() + + with caps.get_structure(0) as s: + self.assertEqual(ptr, s.__ptr__()) + + c2 = caps.mini_object + self.assertEqual(c2.refcount, 2) + caps.make_writable() + + with caps.get_structure(0) as s: + self.assertNotEqual(ptr, s.__ptr__()) + class TestStructure(TestCase):