/* -*- 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 #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; PyObject *PyGstExc_AddError = NULL; PyObject *PyGstExc_RemoveError = NULL; GST_DEBUG_CATEGORY_EXTERN (python_debug); GST_DEBUG_CATEGORY_EXTERN (pygst_debug); #define GST_CAT_DEFAULT pygst_debug 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 static PyObject * pygst_debug_log (PyObject *pyobject, PyObject *string, GstDebugLevel level, gboolean isgstobject) { gchar *str; gchar *function; gchar *filename; int lineno; PyFrameObject *frame; GObject *object = NULL; if (!PyArg_ParseTuple(string, "s:gst.debug_log", &str)) { PyErr_SetString(PyExc_TypeError, "Need a string!"); return NULL; } frame = PyEval_GetFrame(); function = PyString_AsString(frame->f_code->co_name); filename = g_path_get_basename(PyString_AsString(frame->f_code->co_filename)); lineno = PyCode_Addr2Line(frame->f_code, frame->f_lasti); /* gst_debug_log : category, level, file, function, line, object, format, va_list */ if (isgstobject) object = G_OBJECT (pygobject_get (pyobject)); gst_debug_log (python_debug, level, filename, function, lineno, object, "%s", str); if (filename) g_free(filename); Py_INCREF (Py_None); return Py_None; } %% include gstbin.override gstbuffer.override gstbus.override gstcaps.override gstelement.override gstevent.override gstmessage.override gstobject.override gstpad.override gstquery.override gststructure.override gsttaglist.override gstlibs.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(); gst_controller_init(NULL, NULL); } %% modulename gst %% import gobject.GObject as PyGObject_Type %% ignore-glob _* *_copy *_error_quark *_free *_get_type *_private *_thyself *_valist *_ref *_unref *_init gst_class_* gst_init* gst_interface_* gst_value_* gst_param_spec_* %% ignore gst_alloc_trace_list gst_alloc_trace_get gst_error_get_message gst_parse_launchv gst_trace_read_tsc gst_debug_log gst_debug_log_default gst_iterator_new_list %% 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_registry_get_path_list static PyObject * _wrap_gst_registry_get_path_list (PyGObject *self) { GstRegistry *registry; GList *l, *paths; PyObject *list; registry = GST_REGISTRY (self->obj); paths = gst_registry_get_path_list (registry); list = PyList_New (0); for (l = paths; l; l = l->next) { gchar *path = (gchar *) l->data; PyList_Append (list, PyString_FromString(path)); } g_list_free (paths); return list; } %% override gst_registry_get_plugin_list static PyObject * _wrap_gst_registry_get_plugin_list (PyGObject *self) { GstRegistry *registry; GList *l, *plugins; PyObject *list; registry = GST_REGISTRY (self->obj); plugins = gst_registry_get_plugin_list (registry); list = PyList_New (0); for (l = plugins; l; l = l->next) { GstPlugin *plugin = (GstPlugin *) l->data; PyList_Append (list, pygobject_new (G_OBJECT (plugin))); } g_list_free (plugins); return list; } %% override gst_registry_get_feature_list kwargs static PyObject * _wrap_gst_registry_get_feature_list (PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "type", NULL }; PyObject *py_type = NULL; GType type; GstRegistry *registry; GList *l, *features; PyObject *list; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:GstRegistry.get_feature_list", kwlist, &py_type)) return NULL; if ((type = pyg_type_from_object(py_type)) == 0) return NULL; registry = GST_REGISTRY (self->obj); features = gst_registry_get_feature_list (registry, type); 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_registry_get_feature_list_by_plugin kwargs static PyObject * _wrap_gst_registry_get_feature_list_by_plugin (PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "name", NULL }; gchar * name = NULL; GstRegistry *registry; GList *l, *features; PyObject *list; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:GstRegistry.get_feature_list_by_plugin", kwlist, &name)) return NULL; registry = GST_REGISTRY (self->obj); features = gst_registry_get_feature_list_by_plugin (registry, name); 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_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); } %% 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_uri_handler_get_protocols noargs static PyObject * _wrap_gst_uri_handler_get_protocols (PyGObject *self) { gchar **tab; int i, len; PyObject *ret; tab = gst_uri_handler_get_protocols (GST_URI_HANDLER (self->obj)); if (!tab) { Py_INCREF (Py_None); return Py_None; } ret = PyList_New(0); len = g_strv_length (tab); for (i = 0; i < len; i++) { PyList_Append(ret, PyString_FromString(tab[i])); } return ret; } %% override gst_flow_get_name kwargs static PyObject * _wrap_gst_flow_get_name(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "ret", NULL }; PyObject *py_ret = NULL; const gchar *ret; gchar *nret; GstFlowReturn flow; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:gst_flow_get_name", kwlist, &py_ret)) return NULL; if (pyg_enum_get_value(GST_TYPE_FLOW_RETURN, py_ret, (gint *)&flow)) return NULL; ret = gst_flow_get_name(flow); if (ret) { nret = g_strdup(ret); return PyString_FromString(nret); } Py_INCREF(Py_None); return Py_None; } %% override gst_log args static PyObject * _wrap_gst_log (PyObject *whatever, PyObject *string) { return pygst_debug_log (whatever, string, GST_LEVEL_LOG, FALSE); } %% override gst_debug args static PyObject * _wrap_gst_debug (PyObject *whatever, PyObject *string) { return pygst_debug_log (whatever, string, GST_LEVEL_DEBUG, FALSE); } %% override gst_info args static PyObject * _wrap_gst_info (PyObject *whatever, PyObject *string) { return pygst_debug_log (whatever, string, GST_LEVEL_INFO, FALSE); } %% override gst_warning args static PyObject * _wrap_gst_warning (PyObject *whatever, PyObject *string) { return pygst_debug_log (whatever, string, GST_LEVEL_WARNING, FALSE); } %% override gst_error args static PyObject * _wrap_gst_error (PyObject *whatever, PyObject *string) { return pygst_debug_log (whatever, string, GST_LEVEL_ERROR, FALSE); } %% override gst_object_log args static PyObject * _wrap_gst_object_log (PyObject *whatever, PyObject *string) { return pygst_debug_log (whatever, string, GST_LEVEL_LOG, TRUE); } %% override gst_object_debug args static PyObject * _wrap_gst_object_debug (PyObject *whatever, PyObject *string) { return pygst_debug_log (whatever, string, GST_LEVEL_DEBUG, TRUE); } %% override gst_object_info args static PyObject * _wrap_gst_object_info (PyObject *whatever, PyObject *string) { return pygst_debug_log (whatever, string, GST_LEVEL_INFO, TRUE); } %% override gst_object_warning args static PyObject * _wrap_gst_object_warning (PyObject *whatever, PyObject *string) { return pygst_debug_log (whatever, string, GST_LEVEL_WARNING, TRUE); } %% override gst_object_error args static PyObject * _wrap_gst_object_error (PyObject *whatever, PyObject *string) { return pygst_debug_log (whatever, string, GST_LEVEL_ERROR, TRUE); }