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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9027>
This commit is contained in:
Thibault Saunier 2025-05-22 19:19:27 +02:00
parent c3d2209c1f
commit da9365176b
3 changed files with 85 additions and 4 deletions

View File

@ -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)

View File

@ -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* */

View File

@ -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):