mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-18 21:35:44 +00:00
Reimplement gstpython plugin on top of PyGobject
This commit is contained in:
parent
1cf5e26e01
commit
367d281ab6
5 changed files with 349 additions and 3 deletions
|
@ -1,4 +1,4 @@
|
|||
SUBDIRS = common gi
|
||||
SUBDIRS = common gi plugin
|
||||
|
||||
# Examples and testsuite need to be ported to 1.0
|
||||
#examples testsuite
|
||||
|
|
14
acinclude.m4
14
acinclude.m4
|
@ -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"
|
||||
|
|
19
configure.ac
19
configure.ac
|
@ -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
|
||||
])
|
||||
|
|
13
plugin/Makefile.am
Normal file
13
plugin/Makefile.am
Normal file
|
@ -0,0 +1,13 @@
|
|||
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)
|
304
plugin/gstpythonplugin.c
Normal file
304
plugin/gstpythonplugin.c
Normal file
|
@ -0,0 +1,304 @@
|
|||
/* 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)
|
Loading…
Reference in a new issue