/* -*- Mode: C; c-basic-offset: 4 -*- */ /* gst-python * Copyright (C) 2002 David I. Lehn * Copyright (C) 2004 Johan Dahlin * * 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: David I. Lehn */ %% headers /* define this for all source files that don't run init_pygobject() * before including pygobject.h */ #define NO_IMPORT_PYGOBJECT #ifdef HAVE_CONFIG_H # include #endif #include "common.h" #include #include #include #include #include #include #include "pygstvalue.h" #include "pygstminiobject.h" /* These headers have been included directly to get around multiple * GetAttrString calls */ #include #include PyObject *PyGstExc_LinkError = NULL; GSList *mainloops = NULL; void _pygst_main_quit(void) { if (!mainloops) g_error ("Quit more loops than there are"); else { GMainLoop *loop = mainloops->data; mainloops = g_slist_delete_link (mainloops, mainloops); g_main_loop_quit (loop); g_main_loop_unref (loop); } } void _pygst_main(void) { GMainLoop *loop; loop = g_main_loop_new (NULL, FALSE); mainloops = g_slist_prepend (mainloops, loop); g_main_loop_run (loop); } /* This function checks if a former Python code threw an exception and if * so, transforms this exception into an error on the given GstElement. * This allows code run on the element to just raise an exception instead of * returning GStreamer specific return values. * The exception is cleared afterwards. */ gboolean _pygst_element_check_error (GstElement *element) { PyObject *type, *value, *traceback, *lineno, *msg, *typemsg; PyFrameObject *frame; if (!PyErr_Occurred()) return FALSE; PyErr_Fetch (&type, &value, &traceback); if (traceback) { frame = (PyFrameObject *) PyObject_GetAttrString (traceback, "tb_frame"); lineno = PyObject_GetAttrString (traceback, "tb_lineno"); } else { frame = NULL; lineno = NULL; } msg = PyObject_Str (value); typemsg = PyObject_Str (type); if (msg && PyString_Check (msg)) { gst_element_message_full (element, GST_MESSAGE_ERROR, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, g_strdup (PyString_AsString (msg)), typemsg ? g_strconcat (PyString_AsString (typemsg), ": ", PyString_AsString (msg), NULL) : g_strdup (PyString_AsString (msg)), frame ? PyString_AsString(frame->f_code->co_filename) : "???", frame ? PyString_AsString(frame->f_code->co_name) : "???", lineno ? PyInt_AsLong (lineno) : 0); } else { gst_element_message_full (element, GST_MESSAGE_ERROR, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_TOO_LAZY, NULL, NULL, frame ? PyString_AsString(frame->f_code->co_filename) : "???", frame ? PyString_AsString(frame->f_code->co_name) : "???", lineno ? PyInt_AsLong (lineno) : 0); } PyErr_Clear (); Py_XDECREF (frame); Py_XDECREF (lineno); Py_DECREF (msg); Py_DECREF (typemsg); return TRUE; } #ifdef pyg_register_class_init PyTypeObject PyGstPadTemplate_Type; static int add_templates (gpointer gclass, PyObject *templates) { gint i, len; PyGObject *templ; if (pygobject_check(templates, &PyGstPadTemplate_Type)) { gst_element_class_add_pad_template (gclass, GST_PAD_TEMPLATE (pygobject_get (templates))); return 0; } if (!PyTuple_Check(templates)) { PyErr_SetString(PyExc_TypeError, "__gsttemplates__ attribute neither a tuple nor a GstPadTemplate!"); return -1; } len = PyTuple_Size(templates); if (len == 0) return 0; for (i = 0; i < len; i++) { templ = (PyGObject*) PyTuple_GetItem(templates, i); if (!pygobject_check(templ, &PyGstPadTemplate_Type)) { PyErr_SetString(PyExc_TypeError, "entries for __gsttemplates__ must be of type GstPadTemplate"); return -1; } } for (i = 0; i < len; i++) { templ = (PyGObject*) PyTuple_GetItem(templates, i); gst_element_class_add_pad_template (gclass, GST_PAD_TEMPLATE (templ->obj)); } return 0; } static int _pygst_element_set_details (gpointer gclass, PyObject *details) { GstElementDetails gstdetails = { 0, }; if (!PyTuple_Check (details)) { PyErr_SetString(PyExc_TypeError, "__gstdetails__ must be a tuple"); return -1; } if (PyTuple_Size (details) != 4) { PyErr_SetString(PyExc_TypeError, "__gstdetails__ must be contain 4 elements"); return -1; } if (!PyArg_ParseTuple (details, "ssss", &gstdetails.longname, &gstdetails.klass, &gstdetails.description, &gstdetails.author)) { PyErr_SetString (PyExc_TypeError, "__gstdetails__ must be contain 4 strings"); return -1; } gst_element_class_set_details (gclass, &gstdetails); return 0; } static int _pygst_element_init (gpointer gclass, PyTypeObject *pyclass) { PyObject *templates, *details; templates = PyDict_GetItemString(pyclass->tp_dict, "__gsttemplates__"); if (templates) { if (add_templates(gclass, templates) != 0) return -1; } else { PyErr_Clear(); } details = PyDict_GetItemString(pyclass->tp_dict, "__gstdetails__"); if (details) { if (_pygst_element_set_details (gclass, details) != 0) return -1; PyDict_DelItemString(pyclass->tp_dict, "__gstdetails__"); } else { PyErr_Clear(); } return 0; } #endif %% include gstbin.override gstbuffer.override gstcaps.override gstelement.override gstevent.override gstpad.override gststructure.override %% init { /* FIXME: new in pygtk-2.6 */ #ifdef pyg_register_class_init pyg_register_class_init (GST_TYPE_ELEMENT, _pygst_element_init); #endif if (!pygst_value_init()) return; pygst_miniobject_init(); } %% modulename gst %% import gobject.GObject as PyGObject_Type %% ignore-glob _* *_copy *_error_quark *_free *_get_type *_private *_thyself *_valist gst_class_* gst_init* gst_interface_* gst_tag_list_get_* gst_value_* %% ignore gst_alloc_trace_list gst_alloc_trace_get gst_error_get_message gst_object_default_deep_notify gst_object_check_uniqueness gst_object_replace gst_parse_launchv gst_tag_list_add gst_tag_list_add_values gst_tag_list_add_valist_values gst_tag_list_copy_value gst_trace_read_tsc %% define GstTagList.keys noargs void tag_foreach_func_dict (const GstTagList *list, const gchar *tag, PyObject *dict) { int count; guint i; const GValue *gvalue; PyObject *value; gchar *key; count = gst_tag_list_get_tag_size(GST_TAG_LIST(list), tag); for (i = 0; i < count; i++) { gvalue = gst_tag_list_get_value_index(GST_TAG_LIST(list), tag, i); value = pygst_value_as_pyobject(gvalue, TRUE); key = g_strdup (tag); PyDict_SetItemString(dict, key, value); g_free (key); Py_DECREF(value); } } void tag_foreach_func_list (const GstTagList *list, const gchar *tag, PyObject *py_list) { int count; count = gst_tag_list_get_tag_size(GST_TAG_LIST(list), tag); if (count == 0) PyErr_SetString(PyExc_KeyError, tag); else if (count == 1) PyList_Append(py_list, PyString_FromString(tag)); #if 0 else if (count > 1) PyErr_SetString(PyExc_TypeError, "lists are currently unspported"); #endif } static PyObject* _wrap_gst_tag_list_keys(PyGObject *self) { PyObject *dict; dict = PyList_New(0); gst_tag_list_foreach(GST_TAG_LIST(self->obj), (GstTagForeachFunc)tag_foreach_func_list, (gpointer)dict); return dict; } %% override-slot GstTagList.tp_as_mapping static int _wrap_gst_tag_list_length(PyGObject *self) { return gst_structure_n_fields((GstStructure*)self->obj); } static PyObject * _wrap_gst_tag_list_subscript(PyGObject *self, PyObject *py_key) { PyObject *v = NULL; char *key = PyString_AsString(py_key); int count = gst_tag_list_get_tag_size(GST_TAG_LIST(self->obj), key); if (count == 0) { PyErr_SetObject(PyExc_KeyError, py_key); } else if (count == 1) { const GValue *gvalue; gvalue = gst_tag_list_get_value_index(GST_TAG_LIST(self->obj), key, 0); v = pygst_value_as_pyobject(gvalue, TRUE); } else { PyErr_SetString(PyExc_TypeError, "lists are currently unspported"); } if (v != NULL) Py_INCREF(v); return v; } static PySequenceMethods _wrap_gst_tag_list_tp_as_mapping = { (inquiry)_wrap_gst_tag_list_length, /* mp_length */ (binaryfunc)_wrap_gst_tag_list_subscript, /* mp_subscript */ NULL, }; %% define GstTagList.has_key args static PyObject* _wrap_gst_tag_list_has_key(PyGObject *self, PyObject *args) { gchar *key; const GValue *gvalue; if (!PyArg_ParseTuple(args, "s:GstTagList.has_key", &key)) return NULL; gvalue = gst_tag_list_get_value_index(GST_TAG_LIST(self->obj), key, 0); return PyInt_FromLong(gvalue != NULL); } %% define GstTagList.get static PyObject * _wrap_gst_tag_list_get(PyGObject *self, PyObject *args) { char *key; PyObject *failobj = Py_None; PyObject *val = NULL; const GValue *gvalue; if (!PyArg_ParseTuple(args, "s|O:GstTagList.get", &key, &failobj)) return NULL; gvalue = gst_tag_list_get_value_index(GST_TAG_LIST(self->obj), key, 0); if (gvalue != NULL) { int count = gst_tag_list_get_tag_size(GST_TAG_LIST(self->obj), key); if (count == 0) { PyErr_SetString(PyExc_KeyError, key); } else if (count == 1) { gvalue = gst_tag_list_get_value_index(GST_TAG_LIST(self->obj), key, 0); val = pygst_value_as_pyobject(gvalue, TRUE); } else { PyErr_SetString(PyExc_TypeError, "lists are currently unspported"); } } if (val == NULL) val = failobj; Py_INCREF(val); return val; } %% override gst_tag_list_foreach kwargs static gboolean pygst_tag_list_foreach_marshal(GstTagList *list, const gchar *tag, gpointer user_data) { PyGstCustomNotify *cunote = user_data; PyObject *py_list; PyObject *py_key, *retobj; gboolean retval = TRUE; PyGILState_STATE state; g_assert(cunote->func); state = pyg_gil_state_ensure(); py_list = pyg_boxed_new(GST_TYPE_TAG_LIST, list, TRUE, TRUE); py_key = Py_BuildValue("s", tag); if (cunote->data) retobj = PyEval_CallFunction(cunote->func, "(NNO)", py_list, py_key, cunote->data); else retobj = PyEval_CallFunction(cunote->func, "(NN)", py_list, py_key); if (PyErr_Occurred () || (retobj == NULL) || (retobj == Py_None)) { PyErr_Print (); retval = FALSE; } else if (retobj != Py_None) { retval = PyInt_AsLong(retobj); } Py_XDECREF(retobj); pyg_gil_state_release(state); return retval; } static PyObject * _wrap_gst_tag_list_foreach (PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "foreach_function", "args", NULL }; PyObject *pyfunc, *pyarg = NULL; PyGstCustomNotify cunote; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:GstTagList.foreach", kwlist, &pyfunc, &pyarg)) return NULL; if (!PyCallable_Check(pyfunc)) { PyErr_SetString(PyExc_TypeError, "foreach_function not callable"); return NULL; } cunote.func = pyfunc; cunote.data = pyarg; gst_tag_list_foreach(pyg_boxed_get(self, GstTagList), (GstTagForeachFunc)pygst_tag_list_foreach_marshal, &cunote); Py_INCREF(Py_None); return Py_None; } %% override gst_tag_list_get_value_index kwargs static PyObject * _wrap_gst_tag_list_get_value_index (PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "tag", "index", NULL }; char *tag; int index; const GValue *gvalue; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si:GstTagList.get_value_index", kwlist, &tag, &index)) return NULL; gvalue = gst_tag_list_get_value_index(pyg_boxed_get(self, GstTagList), tag, index); return pygst_value_as_pyobject(gvalue, FALSE); } %% override-slot GstObject.tp_repr static PyObject * _wrap_gst_object_tp_repr(PyObject *self) { gchar *repr; PyObject *ret; GstObject *object = GST_OBJECT (pygobject_get (self)); repr = g_strdup_printf ("<%s object (%s) at 0x%lx>", self->ob_type->tp_name, GST_OBJECT_NAME(object) ? GST_OBJECT_NAME(object) : "unnamed", (long)self); ret = PyString_FromString(repr); g_free (repr); return ret; } %% override-slot GstObject.tp_str static PyObject * _wrap_gst_object_tp_str(PyObject *self) { gchar *repr, *path; PyObject *ret; GstObject *object = GST_OBJECT (pygobject_get (self)); path = gst_object_get_path_string (object); repr = g_strdup_printf ("%s (%s)", path, self->ob_type->tp_name); ret = PyString_FromString(repr); g_free (repr); g_free (path); return ret; } %% override-slot GstPluginFeature.tp_repr static PyObject * _wrap_gst_plugin_feature_tp_repr(PyObject *self) { gchar *repr; PyObject *ret; GstPluginFeature *feature = GST_PLUGIN_FEATURE (pygobject_get (self)); repr = g_strdup_printf ("<%s %s @ 0x%lx>", self->ob_type->tp_name, gst_plugin_feature_get_name (feature), (long) self); ret = PyString_FromString(repr); g_free (repr); return ret; } %% override-slot GstPluginFeature.tp_str static PyObject * _wrap_gst_plugin_feature_tp_str(PyObject *self) { gchar *repr; PyObject *ret; GstPluginFeature *feature = GST_PLUGIN_FEATURE (pygobject_get (self)); repr = g_strdup_printf ("<%s %s (%d)>", self->ob_type->tp_name, gst_plugin_feature_get_name (feature), gst_plugin_feature_get_rank (feature)); ret = PyString_FromString(repr); g_free (repr); return ret; } %% override gst_type_find_factory_get_caps noargs static PyObject * _wrap_gst_type_find_factory_get_caps(PyGObject *self) { GstCaps *ret = (GstCaps*)gst_type_find_factory_get_caps(GST_TYPE_FIND_FACTORY(self->obj)); return pyg_boxed_new(GST_TYPE_CAPS, ret, TRUE, TRUE); } %% override gst_type_find_factory_get_caps noargs static PyObject * _wrap_gst_type_find_factory_get_caps(PyGObject *self) { GstCaps *ret = (GstCaps*)gst_type_find_factory_get_caps(GST_TYPE_FIND_FACTORY(self->obj)); return pyg_boxed_new(GST_TYPE_CAPS, ret, TRUE, TRUE); } %% override-attr GError.domain static PyObject * _wrap_gst_g_error__get_domain(PyGObject *self, void *closure) { return PyString_FromString(g_quark_to_string(((GError*)self->obj)->domain)); } %% override-slot GError.tp_str static PyObject * _wrap_gst_g_error_tp_str(PyGObject *self) { GError *error = (GError*)self->obj; return PyString_FromString(gst_error_get_message (error->domain, error->code)); } %% override gst_main noargs static PyObject * _wrap_gst_main(PyObject *self) { pyg_begin_allow_threads; _pygst_main(); pyg_end_allow_threads; if (PyErr_Occurred()) return NULL; Py_INCREF(Py_None); return Py_None; } %% override gst_main_quit args static PyObject * _wrap_gst_main_quit(PyObject *self) { _pygst_main_quit(); Py_INCREF(Py_None); return Py_None; } %% override gst_event_new_any kwargs static PyObject * _wrap_gst_event_new_any(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "structure", NULL }; PyObject *py_structure; GstStructure *structure = NULL; GstEvent *event; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:event_new_any", kwlist, &py_structure)) return NULL; if (pyg_boxed_check(py_structure, GST_TYPE_STRUCTURE)) structure = pyg_boxed_get(py_structure, GstStructure); else { PyErr_SetString(PyExc_TypeError, "structure should be a GstStructure"); return NULL; } event = gst_event_new (GST_EVENT_ANY); if (!event) { PyErr_SetString(PyExc_RuntimeError, "could not create GstEvent object"); return NULL; } event->event_data.structure.structure = gst_structure_copy(structure); /* pyg_boxed_new handles NULL checking */ return pyg_boxed_new(GST_TYPE_EVENT, event, TRUE, TRUE); } %% override gst_event_any_get_structure noargs static PyObject * _wrap_gst_event_any_get_structure(PyObject *self) { GstStructure *ret; GstEvent *event; event = pyg_pointer_get(self, GstEvent); if (GST_EVENT_TYPE(event) == GST_EVENT_ANY) { ret = event->event_data.structure.structure; /* pyg_boxed_new handles NULL checking */ return pyg_boxed_new(GST_TYPE_STRUCTURE, ret, TRUE, TRUE); } else { Py_INCREF(Py_None); return Py_None; } } %% override gst_event_new_discontinuous kwargs static PyObject * _wrap_gst_event_new_discontinuous(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "new_media", "format", "value", NULL }; int new_media = FALSE; PyObject *py_format = NULL; gint64 value = 0; GstFormat format; GstEvent *event; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iOL:event_new_discontinuous", kwlist, &new_media, &py_format, &value)) { return NULL; } if (pyg_enum_get_value(GST_TYPE_FORMAT, py_format, (gint *) &format)) { return NULL; } event = gst_event_new_discontinuous (new_media, format, value, GST_FORMAT_UNDEFINED); return pyg_boxed_new(GST_TYPE_EVENT, event, TRUE, TRUE); } %% override gst_registry_pool_plugin_list noargs static PyObject * _wrap_gst_registry_pool_plugin_list(PyGObject *self) { GList *l, *plugins; PyObject *list; plugins = gst_registry_pool_plugin_list(); list = PyList_New(0); for (l = plugins; l; l = l->next) { GstPlugin *plugin = (GstPlugin*)l->data; PyList_Append(list, pyg_boxed_new(GST_TYPE_PLUGIN, plugin, TRUE, TRUE)); } g_list_free(plugins); return list; } %% override gst_registry_pool_feature_list static PyObject * _wrap_gst_registry_pool_feature_list(PyGObject *self, PyObject *args) { GList *l, *features; PyObject *pygtype, *list; GType gtype; if (!PyArg_ParseTuple(args, "O:registry_pool_feature_list", &pygtype)) return NULL; gtype = pyg_type_from_object (pygtype); if (!gtype) return NULL; features = gst_registry_pool_feature_list(gtype); list = PyList_New(0); for (l = features; l; l = l->next) { GstPluginFeature *feature = (GstPluginFeature*)l->data; PyList_Append(list, pygobject_new (G_OBJECT (feature))); } g_list_free(features); return list; } %% override gst_xml_new noargs extern PyObject * libxml_xmlDocPtrWrap(xmlDocPtr doc); extern PyObject * libxml_xmlNodePtrWrap(xmlNodePtr node); /* libxml2 available check */ static PyObject * _gst_get_libxml2_module(void) { PyObject *xml = NULL; xml = PyImport_ImportModule("libxml2"); if (!xml) { PyErr_Clear(); PyErr_SetString(PyExc_RuntimeError,"libxml2 bindings required"); return NULL; } return xml; } static int _wrap_gst_xml_new(PyGObject *self) { PyObject *xml = _gst_get_libxml2_module(); if(!xml) return -1; self->obj = (GObject *)gst_xml_new(); if (!self->obj) { PyErr_SetString(PyExc_RuntimeError, "could not create GstXML object"); return -1; } pygobject_register_wrapper((PyObject *)self); return 0; } %% override gst_xml_get_topelements noargs static PyObject * _wrap_gst_xml_get_topelements(PyGObject *self) { GList *l, *xml_elements; PyObject *py_list; py_list = PyList_New(0); xml_elements = gst_xml_get_topelements(GST_XML(self->obj)); for (l = xml_elements; l; l = l->next) { GstElement *element = (GstElement*)l->data; PyList_Append(py_list, pygobject_new(G_OBJECT(element))); } return py_list; } %% override gst_xml_parse_memory kwargs static PyObject * _wrap_gst_xml_parse_memory(PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "buffer", "root", NULL }; int buffer_len, ret; char *root = NULL; guchar *buffer; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|s:GstXML.parse_memory", kwlist, &buffer, &buffer_len, &root)) return NULL; ret = gst_xml_parse_memory(GST_XML(self->obj), buffer, buffer_len, root); return PyBool_FromLong(ret); } %% override gst_tag_setter_get_list noargs static PyObject * _wrap_gst_tag_setter_get_list(PyGObject *self) { GstTagList *ret; ret = (GstTagList*)gst_tag_setter_get_list(GST_TAG_SETTER(self->obj)); /* pyg_boxed_new handles NULL checking */ return pyg_boxed_new(GST_TYPE_TAG_LIST, ret, TRUE, TRUE); } %% override gst_plugin_get_version noargs static PyObject * _wrap_gst_plugin_get_version(PyGObject *self) { PyObject *tuple; const gchar *version; gchar **items, **p; gint i = 0; gint count = 0; version = gst_plugin_get_version(GST_PLUGIN(self->obj)); items = g_strsplit(version, ".", 4); for (p = items; *p; ++p) ++count; tuple = PyTuple_New(count); for (p = items; *p; ++p) { PyObject *item; item = PyInt_FromString(*p, NULL, 10); PyTuple_SetItem(tuple, i, item); i++; } g_strfreev(items); return tuple; } %% override gst_element_register kwargs static GstPlugin * _pygst_get_plugin(void) { PyObject *dict = NULL, *module = NULL, *pyplugin = NULL; GstPlugin *ret; if (!(module = PyImport_ImportModule ("gst"))) goto err; if (!(dict = PyModule_GetDict (module))) goto err; if (!(pyplugin = PyDict_GetItemString (dict, "__plugin__"))) goto err; ret = pyg_boxed_get (pyplugin, GstPlugin); Py_DECREF (module); return ret; err: Py_XDECREF (module); PyErr_Clear (); return NULL; } static PyObject * _wrap_gst_element_register(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "type", "elementname", "rank", NULL }; PyObject *py_type = NULL; guint rank = GST_RANK_NONE; char *elementname = NULL; int ret; GType type; /* FIXME: can we make the name optional, too? Anyone know a good default? */ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os|I:element_register", kwlist, &py_type, &elementname, &rank)) return NULL; if ((type = pyg_type_from_object(py_type)) == 0) return NULL; ret = gst_element_register(_pygst_get_plugin(), elementname, rank, type); return PyBool_FromLong(ret); }