mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 08:17:01 +00:00
3b20dd082d
Original commit message from CVS: * gst/gstcaps.override: Override gst_caps_append_structure() and make a copy of the structure given as argument. Fixes #549450
476 lines
13 KiB
C
476 lines
13 KiB
C
/* -*- Mode: C; c-basic-offset: 4 -*- */
|
|
/* gst-python
|
|
* Copyright (C) 2005 Johan Dahlin
|
|
* 2005 Benjamin Otte <otte@gnome.org>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*
|
|
* Author: Johan Dahlin <johan@gnome.org>
|
|
* Benjamin Otte <otte@gnome.org>
|
|
*/
|
|
%%
|
|
headers
|
|
/* This is a (hopefully) smart hack to allow access to a caps'
|
|
* structures without falling into traps when the caps get destroyed
|
|
* before the structures get.
|
|
* This Hash Table uses the structure PyObjects as keys and the caps
|
|
* PyObjects as values. No clue if this is a fast data structure but it
|
|
* probably doesn't matter anyway.
|
|
*/
|
|
static GHashTable *structure_caps_map = NULL;
|
|
|
|
static void
|
|
pygst_caps_map_add (PyObject *structure, PyObject *caps)
|
|
{
|
|
/* we can't have free_on_dealloc stuff in here */
|
|
g_assert (((PyGBoxed *)structure)->free_on_dealloc == FALSE);
|
|
g_hash_table_insert (structure_caps_map, structure, caps);
|
|
}
|
|
|
|
static void
|
|
pygst_caps_map_remove_structure (PyObject *structure)
|
|
{
|
|
g_hash_table_remove (structure_caps_map, structure);
|
|
}
|
|
|
|
static gboolean
|
|
pygst_caps_map_foreach (gpointer structure, gpointer caps, gpointer match)
|
|
{
|
|
PyGBoxed *boxed = structure;
|
|
|
|
if (match != caps)
|
|
return FALSE;
|
|
|
|
/* we can't have free_on_dealloc stuff in here */
|
|
g_assert (boxed->free_on_dealloc == FALSE);
|
|
boxed->boxed = gst_structure_copy (boxed->boxed);
|
|
boxed->free_on_dealloc = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
pygst_caps_map_modified (PyObject *caps)
|
|
{
|
|
g_hash_table_foreach_remove (structure_caps_map, pygst_caps_map_foreach, caps);
|
|
}
|
|
|
|
%%
|
|
init
|
|
structure_caps_map = g_hash_table_new (g_direct_hash, g_direct_equal);
|
|
%%
|
|
ignore
|
|
gst_caps_new_simple
|
|
gst_caps_new_full
|
|
gst_caps_set_simple
|
|
%%
|
|
override gst_caps_get_structure kwargs
|
|
static PyObject *pygst_caps_sq_item(PyObject *self, Py_ssize_t i);
|
|
static PyObject *
|
|
_wrap_gst_caps_get_structure(PyObject *self, PyObject *args, PyObject *kwargs)
|
|
{
|
|
static char *kwlist[] = { "index", NULL };
|
|
int index;
|
|
|
|
if (PyErr_Warn(PyExc_DeprecationWarning, "caps.get_structure(i) is deprecated, use caps[i]") < 0)
|
|
return NULL;
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:GstCaps.get_structure", kwlist, &index))
|
|
return NULL;
|
|
return pygst_caps_sq_item (self, index);
|
|
}
|
|
%%
|
|
override gst_caps_new_empty kwargs
|
|
static int
|
|
_wrap_gst_caps_new_empty(PyGBoxed *self, PyObject *args, PyObject *kwargs)
|
|
{
|
|
PyObject* item;
|
|
int len, i;
|
|
|
|
/* we wrap caps_new, caps_from_string and caps_new_full */
|
|
len = PyTuple_Size(args);
|
|
self->gtype = GST_TYPE_CAPS;
|
|
self->free_on_dealloc = TRUE;
|
|
|
|
if (len == 0) {
|
|
/* 0 length creates a new empty caps */
|
|
self->boxed = gst_caps_new_empty();
|
|
} else if (len == 1) {
|
|
item = PyTuple_GetItem(args, 0);
|
|
/* 1 length is either a string or a structure */
|
|
self->boxed = pygst_caps_from_pyobject (item, NULL);
|
|
} else {
|
|
/* it's multiple arguments that can all be made to caps */
|
|
GstCaps *append;
|
|
self->boxed = gst_caps_new_empty();
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
item = PyTuple_GetItem(args, i);
|
|
append = pygst_caps_from_pyobject (item, NULL);
|
|
if (!append) {
|
|
gst_caps_unref (self->boxed);
|
|
self->boxed = NULL;
|
|
break;
|
|
}
|
|
gst_caps_append (self->boxed, append);
|
|
}
|
|
}
|
|
if (!self->boxed) {
|
|
PyErr_SetString(PyExc_TypeError, "wrong arguments when creating GstCaps object");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
%%
|
|
override-slot GstCaps.tp_richcompare
|
|
|
|
static gboolean
|
|
pygst_caps_is_true_subset (GstCaps *caps1, GstCaps *caps2)
|
|
{
|
|
GstCaps *tmp;
|
|
gboolean ret;
|
|
|
|
/* order is important here */
|
|
if (gst_caps_is_any (caps1))
|
|
return FALSE;
|
|
if (gst_caps_is_any (caps2))
|
|
return TRUE;
|
|
if (gst_caps_is_empty (caps2))
|
|
return FALSE;
|
|
if (gst_caps_is_empty (caps1))
|
|
return TRUE;
|
|
|
|
tmp = gst_caps_subtract (caps1, caps2);
|
|
ret = gst_caps_is_empty (tmp);
|
|
gst_caps_unref (tmp);
|
|
if (!ret)
|
|
return FALSE;
|
|
tmp = gst_caps_subtract (caps2, caps1);
|
|
ret = gst_caps_is_empty (tmp);
|
|
gst_caps_unref (tmp);
|
|
return !ret;
|
|
}
|
|
|
|
static PyObject *
|
|
_wrap_gst_caps_tp_richcompare (PyObject *py_caps1, PyObject *py_caps2, int comparison)
|
|
{
|
|
GstCaps *caps1, *caps2;
|
|
gboolean caps2_is_copy;
|
|
PyObject *ret;
|
|
|
|
caps1 = pyg_boxed_get (py_caps1, GstCaps);
|
|
caps2 = pygst_caps_from_pyobject (py_caps2, &caps2_is_copy);
|
|
if (PyErr_Occurred()) {
|
|
/* the second arg is not a caps */
|
|
switch (comparison) {
|
|
case Py_EQ:
|
|
PyErr_Clear();
|
|
ret = Py_False;
|
|
Py_INCREF (ret);
|
|
return ret;
|
|
case Py_NE:
|
|
PyErr_Clear();
|
|
ret = Py_True;
|
|
Py_INCREF (ret);
|
|
return ret;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
switch (comparison) {
|
|
case Py_LT:
|
|
ret = pygst_caps_is_true_subset (caps1, caps2) ? Py_True : Py_False;
|
|
break;
|
|
case Py_LE:
|
|
ret = gst_caps_is_subset (caps1, caps2) ? Py_True : Py_False;
|
|
break;
|
|
case Py_NE:
|
|
ret = gst_caps_is_equal (caps1, caps2) ? Py_False : Py_True;
|
|
break;
|
|
case Py_EQ:
|
|
ret = gst_caps_is_equal (caps1, caps2) ? Py_True : Py_False;
|
|
break;
|
|
case Py_GE:
|
|
ret = gst_caps_is_subset (caps2, caps1) ? Py_True : Py_False;
|
|
break;
|
|
case Py_GT:
|
|
ret = pygst_caps_is_true_subset (caps2, caps1) ? Py_True : Py_False;
|
|
break;
|
|
default:
|
|
PyErr_SetString (PyExc_RuntimeError, "invalid comparison operation");
|
|
if (caps2 && caps2_is_copy)
|
|
gst_caps_unref (caps2);
|
|
return NULL;
|
|
}
|
|
if (caps2 && caps2_is_copy)
|
|
gst_caps_unref (caps2);
|
|
|
|
Py_INCREF (ret);
|
|
return ret;
|
|
}
|
|
|
|
%%
|
|
override-slot GstCaps.tp_as_number
|
|
|
|
/* In this number code, we mimic the Python set.Set datatype.
|
|
* The same operations are supported. If you want to have an operation
|
|
* supported for caps, add it to Python's Set type first.
|
|
*/
|
|
#define BINARY_FUNC(name,func) \
|
|
static PyObject * \
|
|
name (PyObject *py_caps1, PyObject *py_caps2) \
|
|
{ \
|
|
GstCaps *caps1, *caps2, *ret; \
|
|
gboolean caps2_is_copy; \
|
|
\
|
|
caps1 = pyg_boxed_get (py_caps1, GstCaps); \
|
|
caps2 = pygst_caps_from_pyobject (py_caps2, &caps2_is_copy); \
|
|
if (PyErr_Occurred()) \
|
|
return NULL; \
|
|
ret = func (caps1, caps2); \
|
|
if (caps2 && caps2_is_copy) \
|
|
gst_caps_unref (caps2); \
|
|
return pyg_boxed_new (GST_TYPE_CAPS, ret, FALSE, TRUE); \
|
|
}
|
|
|
|
BINARY_FUNC (pygst_caps_nb_subtract, gst_caps_subtract)
|
|
BINARY_FUNC (pygst_caps_nb_and, gst_caps_intersect)
|
|
BINARY_FUNC (pygst_caps_nb_or, gst_caps_union)
|
|
static GstCaps *
|
|
pygst_caps_xor (const GstCaps *caps1, const GstCaps *caps2)
|
|
{
|
|
GstCaps *intersect, *_union, *ret;
|
|
intersect = gst_caps_intersect (caps1, caps2);
|
|
_union = gst_caps_union (caps1, caps2);
|
|
ret = gst_caps_subtract (_union, intersect);
|
|
gst_caps_unref (_union);
|
|
gst_caps_unref (intersect);
|
|
gst_caps_do_simplify (ret);
|
|
return ret;
|
|
}
|
|
BINARY_FUNC (pygst_caps_nb_xor, pygst_caps_xor)
|
|
|
|
static int
|
|
pygst_caps_nb_nonzero (PyObject *py_caps)
|
|
{
|
|
GstCaps *caps = pyg_boxed_get (py_caps, GstCaps);
|
|
|
|
if (gst_caps_is_empty (caps))
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
pygst_caps_nb_coerce (PyObject **py_caps1, PyObject **py_caps2)
|
|
{
|
|
GstCaps *caps1, *caps2 = NULL;
|
|
gboolean caps1_is_copy, caps2_is_copy;
|
|
|
|
caps1 = pygst_caps_from_pyobject (*py_caps1, &caps1_is_copy);
|
|
if (!caps1)
|
|
goto error;
|
|
caps2 = pygst_caps_from_pyobject (*py_caps2, &caps2_is_copy);
|
|
if (!caps2)
|
|
goto error;
|
|
/* if they're not copies, they're caps already */
|
|
if (caps1_is_copy)
|
|
*py_caps1 = pyg_boxed_new (GST_TYPE_CAPS, caps1, FALSE, TRUE);
|
|
else
|
|
Py_INCREF (*py_caps1);
|
|
if (caps2_is_copy)
|
|
*py_caps2 = pyg_boxed_new (GST_TYPE_CAPS, caps2, FALSE, TRUE);
|
|
else
|
|
Py_INCREF (*py_caps2);
|
|
return 0;
|
|
|
|
error:
|
|
g_assert (PyErr_Occurred ());
|
|
PyErr_Clear ();
|
|
if (caps1 && !caps1_is_copy)
|
|
gst_caps_unref (caps1);
|
|
if (caps2 && !caps2_is_copy)
|
|
gst_caps_unref (caps2);
|
|
return 1;
|
|
}
|
|
|
|
static PyNumberMethods _wrap_gst_caps_tp_as_number = {
|
|
0, /* nb_add */
|
|
pygst_caps_nb_subtract, /* nb_subtract */
|
|
0, /* nb_multiply */
|
|
0, /* nb_divide */
|
|
0, /* nb_remainder */
|
|
0, /* nb_divmod */
|
|
0, /* nb_power */
|
|
0, /* nb_negative */
|
|
0, /* nb_positive */
|
|
0, /* nb_absolute */
|
|
pygst_caps_nb_nonzero, /* nb_nonzero */
|
|
0, /* nb_invert */
|
|
0, /* nb_lshift */
|
|
0, /* nb_rshift */
|
|
pygst_caps_nb_and, /* nb_and */
|
|
pygst_caps_nb_xor, /* nb_xor */
|
|
pygst_caps_nb_or, /* nb_or */
|
|
pygst_caps_nb_coerce, /* nb_coerce */
|
|
0, /* nb_int */
|
|
0, /* nb_long */
|
|
0, /* nb_float */
|
|
0, /* nb_oct */
|
|
0, /* nb_hex */
|
|
0, /* nb_inplace_add */
|
|
0, /* nb_inplace_subtract */
|
|
0, /* nb_inplace_multiply */
|
|
0, /* nb_inplace_divide */
|
|
0, /* nb_inplace_remainder */
|
|
0, /* nb_inplace_power */
|
|
0, /* nb_inplace_lshift */
|
|
0, /* nb_inplace_rshift */
|
|
0, /* nb_inplace_and */
|
|
0, /* nb_inplace_xor */
|
|
0, /* nb_inplace_or */
|
|
0, /* nb_floor_divide */
|
|
0, /* nb_true_divide */
|
|
0, /* nb_inplace_floor_divide */
|
|
0, /* nb_inplace_true_divide */
|
|
};
|
|
%%
|
|
override-slot GstCaps.tp_as_sequence
|
|
static Py_ssize_t
|
|
pygst_caps_sq_length(PyObject *self)
|
|
{
|
|
GstCaps *caps = pyg_boxed_get (self, GstCaps);
|
|
return gst_caps_get_size(caps);
|
|
}
|
|
|
|
static PyObject *
|
|
pygst_caps_sq_item(PyObject *self, Py_ssize_t i)
|
|
{
|
|
GstCaps *caps = pyg_boxed_get (self, GstCaps);
|
|
GstStructure *structure;
|
|
PyObject *ret;
|
|
|
|
if (i < 0 || i >= gst_caps_get_size(caps)) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
|
|
structure = gst_caps_get_structure(caps, i);
|
|
|
|
/* pyg_boxed_new handles NULL checking */
|
|
ret = pyg_boxed_new(GST_TYPE_STRUCTURE,
|
|
gst_caps_get_structure(pyg_boxed_get(self, GstCaps), i),
|
|
FALSE, FALSE);
|
|
if (ret)
|
|
pygst_caps_map_add (ret, self);
|
|
return ret;
|
|
}
|
|
|
|
/* FIXME: This syntax sucks */
|
|
static PyObject *
|
|
pygst_caps_sq_slice(PyObject *self, Py_ssize_t start, Py_ssize_t end)
|
|
{
|
|
GstCaps *caps = pyg_boxed_get (self, GstCaps);
|
|
GstCaps *ret = gst_caps_new_empty ();
|
|
int i;
|
|
|
|
if (start < 0)
|
|
start = 0;
|
|
if (end > gst_caps_get_size (caps))
|
|
end = gst_caps_get_size (caps);
|
|
|
|
for (i = start; i < end; i++)
|
|
gst_caps_append_structure (ret, gst_structure_copy (gst_caps_get_structure (caps, i)));
|
|
|
|
return pyg_boxed_new(GST_TYPE_CAPS, ret, FALSE, TRUE);
|
|
}
|
|
|
|
static PySequenceMethods _wrap_gst_caps_tp_as_sequence = {
|
|
pygst_caps_sq_length,
|
|
NULL, /* not allowed for sets, use | instead of + */
|
|
NULL, /* doesn't make sense, because it'd still be the same */
|
|
pygst_caps_sq_item,
|
|
pygst_caps_sq_slice,
|
|
NULL, /* doesn't make sense, you can only append */
|
|
NULL, /* doesn't make sense, you can only append */
|
|
NULL, /* doesn't make sense really, unless you use is_subset */
|
|
NULL, /* not allowed for sets, use | instead of + */
|
|
NULL /* doesn't make sense, because it'd still be the same */
|
|
};
|
|
%%
|
|
override-slot GstCaps.tp_dealloc
|
|
static void
|
|
_wrap_gst_caps_tp_dealloc (PyObject *self)
|
|
{
|
|
PyGBoxed *boxed = (PyGBoxed *) self;
|
|
|
|
if (boxed->free_on_dealloc && boxed->boxed) {
|
|
pygst_caps_map_modified (self);
|
|
GST_DEBUG ("unreffing caps %" GST_PTR_FORMAT " at %p with refcount %d",
|
|
boxed->boxed, boxed->boxed, GST_CAPS_REFCOUNT (boxed->boxed));
|
|
gst_caps_unref (boxed->boxed);
|
|
}
|
|
|
|
self->ob_type->tp_free((PyObject *)self);
|
|
}
|
|
|
|
%%
|
|
override-slot GstCaps.tp_str
|
|
static PyObject *
|
|
_wrap_gst_caps_tp_str(PyGObject *self)
|
|
{
|
|
gchar *tmp;
|
|
PyObject *retval;
|
|
|
|
tmp = gst_caps_to_string((GstCaps*)self->obj);
|
|
retval = PyString_FromString(tmp);
|
|
g_free(tmp);
|
|
|
|
return retval;
|
|
}
|
|
|
|
%%
|
|
override-attr GstCaps.__refcount__
|
|
|
|
static PyObject *
|
|
_wrap_gst_caps__get___refcount__(PyGObject *self, void *closure)
|
|
{
|
|
return PyInt_FromLong(GST_CAPS_REFCOUNT(self->obj));
|
|
}
|
|
|
|
%%
|
|
override gst_caps_append_structure kwargs
|
|
static PyObject *
|
|
_wrap_gst_caps_append_structure(PyObject *self, PyObject *args, PyObject *kwargs)
|
|
{
|
|
static char *kwlist[] = { "structure", NULL };
|
|
PyObject *py_structure;
|
|
GstStructure *structure = NULL;
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs,"O:GstCaps.append_structure", kwlist, &py_structure))
|
|
return NULL;
|
|
if (pyg_boxed_check(py_structure, GST_TYPE_STRUCTURE))
|
|
structure = gst_structure_copy(pyg_boxed_get(py_structure, GstStructure));
|
|
else {
|
|
PyErr_SetString(PyExc_TypeError, "structure should be a GstStructure");
|
|
return NULL;
|
|
}
|
|
pyg_begin_allow_threads;
|
|
gst_caps_append_structure(pyg_boxed_get(self, GstCaps), structure);
|
|
pyg_end_allow_threads;
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|