gstreamer/gst/gstcaps.override

454 lines
12 KiB
Text
Raw Normal View History

/* -*- 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));
}