Skip to content
Snippets Groups Projects
Commit 367d281a authored by Thibault Saunier's avatar Thibault Saunier Committed by Thibault Saunier
Browse files

Reimplement gstpython plugin on top of PyGobject

parent 1cf5e26e
No related branches found
Tags mesa-18.3.0-rc5
No related merge requests found
SUBDIRS = common gi
SUBDIRS = common gi plugin
# Examples and testsuite need to be ported to 1.0
#examples testsuite
......
......@@ -47,6 +47,11 @@ py_prefix=`$PYTHON -c "import sys; print(sys.prefix)"`
py_exec_prefix=`$PYTHON -c "import sys; print(sys.exec_prefix)"`
if $PYTHON-config --help 1>/dev/null 2>/dev/null; then
PYTHON_INCLUDES=`$PYTHON-config --includes 2>/dev/null`
if $PYTHON-config --abiflags 1>/dev/null 2>/dev/null; then
PYTHON_ABI_FLAGS=`$PYTHON-config --abiflags 2>/dev/null`
else
PYTHON_ABI_FLAGS=
fi
else
PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}"
if test "$py_prefix" != "$py_exec_prefix"; then
......@@ -86,8 +91,12 @@ if $PYTHON-config --help 1>/dev/null 2>/dev/null; then
# default to prefix/lib for distros that don't have a link in
# .../pythonX.Y/config/
if test ! -e $PYTHON_LIB_LOC/libpython${PYTHON_VERSION}.so; then
PYTHON_LIB_LOC=${py_prefix}/lib
if test ! -e $PYTHON_LIB_LOC/libpython${PYTHON_VERSION}${PYTHON_ABI_FLAGS}.so; then
if test -e ${py_prefix}/lib64/libpython${PYTHON_VERSION}${PYTHON_ABI_FLAGS}.so; then
PYTHON_LIB_LOC=${py_prefix}/lib64
else
PYTHON_LIB_LOC=${py_prefix}/lib
fi
fi
fi
else
......@@ -111,6 +120,7 @@ fi
AC_SUBST(PYTHON_LIBS)
AC_SUBST(PYTHON_LIB_LOC)
AC_SUBST(PYTHON_ABI_FLAGS)
AC_SUBST(PYTHON_LIB_SUFFIX)
dnl check if the headers exist:
save_LIBS="$LIBS"
......
......@@ -64,7 +64,21 @@ if sys.version_info < minver:
sys.exit(1)
sys.exit(0)"
dnl check for GStreamer
GST_API_VERSION=1.0
AC_SUBST(GST_API_VERSION)
PKG_CHECK_MODULES(GST, gstreamer-$GST_API_VERSION >= $GST_REQ)
AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [Gst API version])
GST_CFLAGS="$GST_CFLAGS $GLIB_EXTRA_CFLAGS"
AC_SUBST(GST_CFLAGS)
AC_SUBST(GST_LIBS)
dnl check for pygobject
PKG_CHECK_MODULES(PYGOBJECT, pygobject-3.0 >= $PYGOBJECT_REQ)
AC_SUBST(PYGOBJECT_CFLAGS)
dnl check for python
if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC
then
AC_MSG_RESULT(okay)
......@@ -109,6 +123,8 @@ GST_CFLAGS="$GST_CFLAGS $GLIB_EXTRA_CFLAGS"
AC_SUBST(GST_CFLAGS)
AC_SUBST(GST_LIBS)
AG_GST_SET_PLUGINDIR
dnl check for pygobject
PKG_CHECK_MODULES(PYGOBJECT, pygobject-3.0 >= $PYGOBJECT_REQ)
AC_SUBST(PYGOBJECT_CFLAGS)
......@@ -117,6 +133,8 @@ dnl and set the override directory
AC_ARG_WITH([pygi_overrides_dir],
AC_HELP_STRING([--with-pygi-overrides-dir], [Path to pygobject overrides directory]))
AM_CHECK_PYTHON_LIBS(, AC_MSG_ERROR([Python libs not found. Windows requires Python modules to be explicitly linked to libpython.]))
AG_GST_VALGRIND_CHECK
dnl set release date/time
......@@ -133,5 +151,6 @@ AC_OUTPUT([
common/Makefile
common/m4/Makefile
gi/Makefile
plugin/Makefile
gi/overrides/Makefile
])
plugin_LTLIBRARIES = libgstpythonplugin.la
INCLUDES = $(PYGOBJECT_CFLAGS) $(GST_CFLAGS)\
-DPYTHON_VERSION=\"$(PYTHON_VERSION)\" \
-DPY_LIB_LOC="\"$(PYTHON_LIB_LOC)\"" \
-DPY_ABI_FLAGS="\"$(PYTHON_ABI_FLAGS)\"" \
-DPY_LIB_SUFFIX=$(PYTHON_LIB_SUFFIX) \
$(PYTHON_INCLUDES)
libgstpythonplugin_la_SOURCES = gstpythonplugin.c
libgstpythonplugin_la_LDFLAGS =
libgstpythonplugin_la_LIBADD = $(PYTHON_LIBS) $(PYGOBJECT_LIBS) $(GST_LIBS)
libgstpythonplugin_la_CFLAGS = $(GST_CFLAGS) $(PYGOBJECT_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(PYTHON_INCLUDES)
/* gst-python
* Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* include this first, before NO_IMPORT_PYGOBJECT is defined */
#include <pygobject.h>
#include <gst/gst.h>
#include <gmodule.h>
#include <Python.h>
void *_PyGstElement_Type;
GST_DEBUG_CATEGORY_STATIC (pyplugindebug);
#define GST_CAT_DEFAULT pyplugindebug
#define GST_ORIGIN "http://gstreamer.freedesktop.org"
static PyObject *element;
static gboolean
gst_python_plugin_load_file (GstPlugin * plugin, const char *name)
{
PyObject *main_module, *main_locals;
PyObject *elementfactory;
PyObject *module;
const gchar *facname;
guint rank;
PyObject *class;
GST_DEBUG ("loading plugin %s", name);
main_module = PyImport_AddModule ("__main__");
if (main_module == NULL) {
GST_WARNING ("Could not get __main__, ignoring plugin %s", name);
PyErr_Print ();
PyErr_Clear ();
return FALSE;
}
main_locals = PyModule_GetDict (main_module);
module =
PyImport_ImportModuleEx ((char *) name, main_locals, main_locals, NULL);
if (!module) {
GST_DEBUG ("Could not load module, ignoring plugin %s", name);
PyErr_Print ();
PyErr_Clear ();
return FALSE;
}
/* Get __gstelementfactory__ from file */
elementfactory = PyObject_GetAttrString (module, "__gstelementfactory__");
if (!elementfactory) {
GST_DEBUG ("python file doesn't contain __gstelementfactory__");
PyErr_Clear ();
return FALSE;
}
/* parse tuple : name, rank, gst.ElementClass */
if (!PyArg_ParseTuple (elementfactory, "sIO", &facname, &rank, &class)) {
GST_WARNING ("__gstelementfactory__ isn't correctly formatted");
PyErr_Print ();
PyErr_Clear ();
Py_DECREF (elementfactory);
return FALSE;
}
if (!PyObject_IsSubclass (class, (PyObject *) & PyGObject_Type)) {
GST_WARNING ("the class provided isn't a subclass of GObject.Object");
PyErr_Print ();
PyErr_Clear ();
Py_DECREF (elementfactory);
Py_DECREF (class);
return FALSE;
}
if (!g_type_is_a (pyg_type_from_object (class), GST_TYPE_ELEMENT)) {
GST_WARNING ("the class provided isn't a subclass of Gst.Element");
PyErr_Print ();
PyErr_Clear ();
Py_DECREF (elementfactory);
Py_DECREF (class);
return FALSE;
}
GST_INFO ("Valid plugin");
Py_DECREF (elementfactory);
return gst_element_register (plugin, facname, rank,
pyg_type_from_object (class));
}
static gboolean
gst_python_load_directory (GstPlugin * plugin, gchar * path)
{
GDir *dir;
const gchar *file;
GError *error = NULL;
gboolean ret = TRUE;
dir = g_dir_open (path, 0, &error);
if (!dir) {
/*retval should probably be depending on error, but since we ignore it... */
GST_DEBUG ("Couldn't open Python plugin dir: %s", error->message);
g_error_free (error);
return FALSE;
}
while ((file = g_dir_read_name (dir))) {
/* FIXME : go down in subdirectories */
if (g_str_has_suffix (file, ".py")) {
gsize len = strlen (file) - 3;
gchar *name = g_strndup (file, len);
ret &= gst_python_plugin_load_file (plugin, name);
g_free (name);
}
}
return TRUE;
}
static gboolean
gst_python_plugin_load (GstPlugin * plugin)
{
PyObject *sys_path;
const gchar *plugin_path;
gboolean ret = TRUE;
sys_path = PySys_GetObject ("path");
/* Mimic the order in which the registry is checked in core */
/* 1. check env_variable GST_PLUGIN_PATH */
plugin_path = g_getenv ("GST_PLUGIN_PATH");
if (plugin_path) {
char **list;
int i;
GST_DEBUG ("GST_PLUGIN_PATH set to %s", plugin_path);
list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0);
for (i = 0; list[i]; i++) {
gchar *sysdir = g_build_filename (list[i], "python", NULL);
PyList_Insert (sys_path, 0, PyUnicode_FromString (sysdir));
gst_python_load_directory (plugin, sysdir);
g_free (sysdir);
}
g_strfreev (list);
}
/* 2. Check for GST_PLUGIN_SYSTEM_PATH */
plugin_path = g_getenv ("GST_PLUGIN_SYSTEM_PATH");
if (plugin_path == NULL) {
char *home_plugins;
/* 2.a. Scan user and system-wide plugin directory */
GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH not set");
/* plugins in the user's home directory take precedence over
* system-installed ones */
home_plugins = g_build_filename (g_get_home_dir (),
".gstreamer-" GST_API_VERSION, "plugins", "python", NULL);
PyList_Insert (sys_path, 0, PyUnicode_FromString (home_plugins));
gst_python_load_directory (plugin, home_plugins);
g_free (home_plugins);
/* add the main (installed) library path */
PyList_Insert (sys_path, 0, PyUnicode_FromString (PLUGINDIR "/python"));
gst_python_load_directory (plugin, PLUGINDIR "/python");
} else {
gchar **list;
gint i;
/* 2.b. Scan GST_PLUGIN_SYSTEM_PATH */
GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH set to %s", plugin_path, plugin_path);
list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0);
for (i = 0; list[i]; i++) {
gchar *sysdir;
sysdir = g_build_filename (list[i], "python", NULL);
PyList_Insert (sys_path, 0, PyUnicode_FromString (sysdir));
gst_python_load_directory (plugin, sysdir);
g_free (sysdir);
}
g_strfreev (list);
}
return ret;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
PyGILState_STATE state;
PyObject *gst, *dict, *pyplugin;
gboolean we_initialized = FALSE;
GModule *libpython;
gpointer has_python = NULL;
PyObject *seq, *list;
int i, len;
GST_DEBUG_CATEGORY_INIT (pyplugindebug, "pyplugin", 0,
"Python plugin loader");
gst_plugin_add_dependency_simple (plugin,
"HOME/.gstreamer-" GST_API_VERSION
"/plugins/python:GST_PLUGIN_SYSTEM_PATH/python:GST_PLUGIN_PATH/python",
PLUGINDIR "/python:HOME/.gstreamer-" GST_API_VERSION "/plugins/python:"
"GST_PLUGIN_SYSTEM_PATH/python:GST_PLUGIN_PATH/python", NULL,
GST_PLUGIN_DEPENDENCY_FLAG_NONE);
GST_LOG ("Checking to see if libpython is already loaded");
g_module_symbol (g_module_open (NULL, G_MODULE_BIND_LOCAL), "_Py_NoneStruct",
&has_python);
if (has_python) {
GST_LOG ("libpython is already loaded");
} else {
GST_LOG ("loading libpython");
libpython =
g_module_open (PY_LIB_LOC "/libpython" PYTHON_VERSION PY_ABI_FLAGS
"." PY_LIB_SUFFIX, 0);
if (!libpython) {
GST_WARNING ("Couldn't g_module_open libpython. Reason: %s",
g_module_error ());
return FALSE;
}
}
if (!Py_IsInitialized ()) {
GST_LOG ("python wasn't initialized");
/* set the correct plugin for registering stuff */
Py_Initialize ();
we_initialized = TRUE;
} else {
GST_LOG ("python was already initialized");
state = PyGILState_Ensure ();
}
GST_LOG ("initializing pygobject");
if (!pygobject_init (3, 0, 0)) {
GST_WARNING ("pygobject initialization failed");
return FALSE;
}
gst = PyImport_ImportModule ("gi.repository.Gst");
if (we_initialized) {
PyObject *tmp;
dict = PyModule_GetDict (gst);
if (!dict) {
GST_ERROR ("no dict?!");
}
tmp =
PyObject_GetAttr (PyMapping_GetItemString (dict,
"_introspection_module"), PyUnicode_FromString ("__dict__"));
_PyGstElement_Type = PyMapping_GetItemString (tmp, "Element");
if (!_PyGstElement_Type) {
g_error ("Could not get Gst.Element");
Py_DECREF (pyplugin);
}
pyplugin = pygobject_new (G_OBJECT (plugin));
if (!pyplugin || PyModule_AddObject (gst, "__plugin__", pyplugin) != 0) {
g_warning ("Couldn't set plugin");
Py_DECREF (pyplugin);
}
}
gst_python_plugin_load (plugin);
if (we_initialized) {
/* We need to release the GIL since we're going back to C land */
PyEval_SaveThread ();
} else
PyGILState_Release (state);
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR, python,
"loader for plugins written in python",
plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_ORIGIN)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment