mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
f884a2a7de
Those two lines will never be called, because caps2 will always be NULL if we go to error (either we haven't used it yet (first goto and in this case it's NULL), or.. it's NULL (second goto)).
474 lines
13 KiB
C
474 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);
|
|
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;
|
|
}
|