/* gst-python * Copyright (C) 2004 Andy Wingo * * 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: Andy Wingo */ /* define this for all source files that don't run init_pygobject() * before including pygobject.h */ #define NO_IMPORT_PYGOBJECT #include "pygstvalue.h" static PyObject *gstvalue_class = NULL; static PyObject *gstfourcc_class = NULL; static PyObject *gstintrange_class = NULL; static PyObject *gstdoublerange_class = NULL; static PyObject *gstfraction_class = NULL; static PyObject *gstfractionrange_class = NULL; /* helper function */ /* Finds the greatest common divisor. * Returns 1 if none other found. * This is Euclid's algorithm. */ static long my_gcd (long num, long denom) { while (denom != 0) { long temp = num; num = denom; denom = temp % denom; } return ABS (num); } /** * pygst_value_as_pyobject: * @value: the GValue object. * @copy_boxed: true if boxed values should be copied. * * This function creates/returns a Python wrapper object that * represents the GValue passed as an argument. * * Returns: a PyObject representing the value. */ PyObject * pygst_value_as_pyobject (const GValue * value, gboolean copy_boxed) { PyObject *ret = pyg_value_as_pyobject (value, copy_boxed); if (!ret) { PyErr_Clear (); if (GST_VALUE_HOLDS_FOURCC (value)) { gchar str[5]; g_snprintf (str, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (gst_value_get_fourcc (value))); ret = PyObject_Call (gstfourcc_class, Py_BuildValue ("(s)", str), NULL); } else if (GST_VALUE_HOLDS_INT_RANGE (value)) { ret = PyObject_Call (gstintrange_class, Py_BuildValue ("ii", gst_value_get_int_range_min (value), gst_value_get_int_range_max (value)), NULL); } else if (GST_VALUE_HOLDS_DOUBLE_RANGE (value)) { ret = PyObject_Call (gstdoublerange_class, Py_BuildValue ("dd", gst_value_get_double_range_min (value), gst_value_get_double_range_max (value)), NULL); } else if (GST_VALUE_HOLDS_LIST (value)) { int i, len; len = gst_value_list_get_size (value); ret = PyList_New (len); for (i = 0; i < len; i++) { PyList_SetItem (ret, i, pygst_value_as_pyobject (gst_value_list_get_value (value, i), copy_boxed)); } } else if (GST_VALUE_HOLDS_ARRAY (value)) { int i, len; len = gst_value_array_get_size (value); ret = PyTuple_New (len); for (i = 0; i < len; i++) { PyTuple_SetItem (ret, i, pygst_value_as_pyobject (gst_value_array_get_value (value, i), copy_boxed)); } } else if (GST_VALUE_HOLDS_FRACTION (value)) { ret = PyObject_Call (gstfraction_class, Py_BuildValue ("ii", gst_value_get_fraction_numerator (value), gst_value_get_fraction_denominator (value)), NULL); } else if (GST_VALUE_HOLDS_FRACTION_RANGE (value)) { const GValue *min, *max; min = gst_value_get_fraction_range_min (value); max = gst_value_get_fraction_range_max (value); ret = PyObject_Call (gstfractionrange_class, Py_BuildValue ("OO", pygst_value_as_pyobject (min, copy_boxed), pygst_value_as_pyobject (max, copy_boxed)), NULL); } else if (GST_VALUE_HOLDS_BUFFER (value)) { return pygstminiobject_new (gst_value_get_mini_object (value)); } else { gchar buf[256]; g_snprintf (buf, 256, "unknown type: %s", g_type_name (G_VALUE_TYPE (value))); PyErr_SetString (PyExc_TypeError, buf); } } if (G_VALUE_TYPE (value) == G_TYPE_STRING) { PyObject *u = NULL; /* FIXME: docs are not clear on whether this sets a python exception when it fails */ u = PyUnicode_FromEncodedObject (ret, "utf-8", NULL); Py_DECREF (ret); ret = u; } return ret; } #define VALUE_TYPE_CHECK(v, t) \ G_STMT_START{\ if (!G_VALUE_HOLDS (v, t)) {\ gchar errbuf[256];\ g_snprintf (errbuf, 256, "Could not convert %s to %s",\ g_type_name (t), g_type_name (G_VALUE_TYPE (v)));\ PyErr_SetString (PyExc_TypeError, errbuf);\ return -1;\ }}G_STMT_END gboolean pygst_value_init_for_pyobject (GValue * value, PyObject * obj) { GType t; if (obj == Py_None) { PyErr_SetString (PyExc_TypeError, "value can't be None"); return FALSE; } if (!(t = pyg_type_from_object ((PyObject *) obj->ob_type))) { if (PyObject_IsInstance (obj, gstvalue_class)) { PyErr_Clear (); if (PyObject_IsInstance (obj, gstfourcc_class)) t = GST_TYPE_FOURCC; else if (PyObject_IsInstance (obj, gstintrange_class)) t = GST_TYPE_INT_RANGE; else if (PyObject_IsInstance (obj, gstdoublerange_class)) t = GST_TYPE_DOUBLE_RANGE; else if (PyObject_IsInstance (obj, gstfraction_class)) t = GST_TYPE_FRACTION; else if (PyObject_IsInstance (obj, gstfractionrange_class)) t = GST_TYPE_FRACTION_RANGE; else { PyErr_SetString (PyExc_TypeError, "Unexpected gst.Value instance"); return FALSE; } } else if (PyObject_IsInstance (obj, (PyObject *) & PyGstMiniObject_Type)) { PyErr_Clear (); t = GST_TYPE_MINI_OBJECT; } else if (PyTuple_Check (obj)) { PyErr_Clear (); t = GST_TYPE_ARRAY; } else if (PyList_Check (obj)) { PyErr_Clear (); t = GST_TYPE_LIST; } else if (PyUnicode_Check (obj)) { /* unicode strings should be converted to UTF-8 */ PyErr_Clear (); t = G_TYPE_STRING; } else { /* pyg_type_from_object already set the error */ return FALSE; } } g_value_init (value, t); return TRUE; } static int pygst_value_from_pyobject_internal (GValue * value, PyObject * obj) { GType f = g_type_fundamental (G_VALUE_TYPE (value)); /* work around a bug in pygtk whereby pyg_value_from_pyobject claims success for unknown fundamental types without actually doing anything */ if (f < G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST) && pyg_value_from_pyobject (value, obj) == 0) { return 0; } else if (PyObject_IsInstance (obj, gstvalue_class)) { PyErr_Clear (); if (PyObject_IsInstance (obj, gstfourcc_class)) { PyObject *pystr; gchar *str; VALUE_TYPE_CHECK (value, GST_TYPE_FOURCC); if (!(pystr = PyObject_GetAttrString (obj, "fourcc"))) return -1; if (!(str = PyString_AsString (pystr))) return -1; g_assert (strlen (str) == 4); gst_value_set_fourcc (value, GST_STR_FOURCC (str)); } else if (PyObject_IsInstance (obj, gstintrange_class)) { PyObject *pyval; long low, high; VALUE_TYPE_CHECK (value, GST_TYPE_INT_RANGE); if (!(pyval = PyObject_GetAttrString (obj, "low"))) return -1; low = PyInt_AsLong (pyval); g_assert (G_MININT <= low && low <= G_MAXINT); if (!(pyval = PyObject_GetAttrString (obj, "high"))) return -1; high = PyInt_AsLong (pyval); g_assert (G_MININT <= high && high <= G_MAXINT); gst_value_set_int_range (value, (int) low, (int) high); } else if (PyObject_IsInstance (obj, gstdoublerange_class)) { PyObject *pyval; double low, high; VALUE_TYPE_CHECK (value, GST_TYPE_DOUBLE_RANGE); if (!(pyval = PyObject_GetAttrString (obj, "low"))) return -1; low = PyFloat_AsDouble (pyval); if (!(pyval = PyObject_GetAttrString (obj, "high"))) return -1; high = PyFloat_AsDouble (pyval); gst_value_set_double_range (value, low, high); } else if (PyObject_IsInstance (obj, gstfraction_class)) { PyObject *pyval; long num, denom; long gcd = 0; VALUE_TYPE_CHECK (value, GST_TYPE_FRACTION); if (!(pyval = PyObject_GetAttrString (obj, "num"))) return -1; num = PyInt_AsLong (pyval); if ((num == -1) && PyErr_Occurred ()) return -1; g_assert (G_MININT <= num && num <= G_MAXINT); if (!(pyval = PyObject_GetAttrString (obj, "denom"))) return -1; denom = PyInt_AsLong (pyval); if ((denom == -1) && PyErr_Occurred ()) return -1; /* we need to reduce the values to be smaller than MAXINT */ if ((gcd = my_gcd (num, denom))) { num /= gcd; denom /= gcd; } g_assert (G_MININT <= denom && denom <= G_MAXINT); gst_value_set_fraction (value, (int) num, (int) denom); } else if (PyObject_IsInstance (obj, gstfractionrange_class)) { GValue low = { 0, }; GValue high = { 0, }; PyObject *pylow, *pyhigh; VALUE_TYPE_CHECK (value, GST_TYPE_FRACTION_RANGE); if (!(pylow = PyObject_GetAttrString (obj, "low"))) return -1; if (!pygst_value_init_for_pyobject (&low, pylow)) return -1; if (pygst_value_from_pyobject (&low, pylow) != 0) return -1; if (!(pyhigh = PyObject_GetAttrString (obj, "high"))) return -1; if (!pygst_value_init_for_pyobject (&high, pyhigh)) return -1; if (pygst_value_from_pyobject (&high, pyhigh) != 0) return -1; gst_value_set_fraction_range (value, &low, &high); } else { gchar buf[256]; gchar *str = PyString_AsString (PyObject_Repr (obj)); g_snprintf (buf, 256, "Unknown gst.Value type: %s", str); PyErr_SetString (PyExc_TypeError, buf); return -1; } return 0; } else if (PyObject_IsInstance (obj, (PyObject *) & PyGstMiniObject_Type)) { VALUE_TYPE_CHECK (value, GST_TYPE_MINI_OBJECT); gst_value_set_mini_object (value, pygstminiobject_get (obj)); return 0; } else if (PyTuple_Check (obj)) { gint i, len; PyErr_Clear (); VALUE_TYPE_CHECK (value, GST_TYPE_ARRAY); len = PyTuple_Size (obj); for (i = 0; i < len; i++) { PyObject *o; GValue new = { 0, }; o = PyTuple_GetItem (obj, i); if (!pygst_value_init_for_pyobject (&new, o)) return -1; if (pygst_value_from_pyobject (&new, o) != 0) { g_value_unset (&new); return -1; } gst_value_array_append_value (value, &new); g_value_unset (&new); } return 0; } else if (PyList_Check (obj)) { gint i, len; PyErr_Clear (); VALUE_TYPE_CHECK (value, GST_TYPE_LIST); len = PyList_Size (obj); for (i = 0; i < len; i++) { PyObject *o; GValue new = { 0, }; o = PyList_GetItem (obj, i); if (!pygst_value_init_for_pyobject (&new, o)) return -1; if (pygst_value_from_pyobject (&new, o) != 0) { g_value_unset (&new); return -1; } gst_value_list_append_value (value, &new); g_value_unset (&new); } return 0; } else { return -1; } } /** * pygst_value_from_pyobject: * @value: the GValue object to store the converted value in. * @obj: the Python object to convert. * * This function converts a Python object and stores the result in a * GValue. The GValue must be initialised in advance with * g_value_init(). If the Python object can't be converted to the * type of the GValue, then an error is returned. * * Returns: 0 on success, -1 on error. */ int pygst_value_from_pyobject (GValue * value, PyObject * obj) { PyObject *v = NULL; int res; /* Unicode objects should be converted to utf-8 strings */ if (PyObject_TypeCheck (obj, &PyUnicode_Type)) { v = PyUnicode_AsUTF8String (obj); obj = v; } res = pygst_value_from_pyobject_internal (value, obj); if (v) { Py_DECREF (obj); } return res; } #define NULL_CHECK(o) if (!o) goto err gboolean pygst_value_init (void) { PyObject *module, *dict; if ((module = PyImport_ImportModule ("gst")) == NULL) return FALSE; dict = PyModule_GetDict (module); gstvalue_class = (PyObject *) PyDict_GetItemString (dict, "Value"); NULL_CHECK (gstvalue_class); gstfourcc_class = (PyObject *) PyDict_GetItemString (dict, "Fourcc"); NULL_CHECK (gstfourcc_class); gstintrange_class = (PyObject *) PyDict_GetItemString (dict, "IntRange"); NULL_CHECK (gstintrange_class); gstdoublerange_class = (PyObject *) PyDict_GetItemString (dict, "DoubleRange"); NULL_CHECK (gstdoublerange_class); gstfraction_class = (PyObject *) PyDict_GetItemString (dict, "Fraction"); NULL_CHECK (gstfraction_class); gstfractionrange_class = (PyObject *) PyDict_GetItemString (dict, "FractionRange"); NULL_CHECK (gstfractionrange_class); return TRUE; err: PyErr_SetString (PyExc_ImportError, "Failed to get GstValue classes from gst module"); return FALSE; }