MathieuDuponchelle / MathieuDuponchelle.github.io

blog
1 stars 0 forks source link

How to write GStreamer (1.0) elements in python (Part 1) #2

Open MathieuDuponchelle opened 6 years ago

martinling commented 5 years ago

Hi Mathieu,

I have a project for which I want to write some GStreamer elements in Python and I'm trying to get your example from this article working, but running into trouble and I'm wondering if things have gotten broken again in git somewhere.

Details of what I've done are below - wondering if you have any insight, or if you could let me know any git versions of the packages that your example is known to work with.

I have removed all the system gstreamer packages from my Debian testing system, and built and installed from git master all of gstreamer, gstreamer-plugins-base, pygobject and gst-python. The basic gstreamer install seems to be working correctly and I can run simple pipelines with gst-launch-1.0.

With your srcelement.py in python below the current directory, running:

GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-inspect-1.0 audiotestsrc_py

just results in No such element or plugin 'audiotestsrc_py'.

Digging a bit deeper, it seems like there is a problem with the gst-python plugin. It does not show up in the list returned by gst-inspect-1.0, although libgstpython.so is present in /usr/local/lib/gstreamer-1.0/ with everything else, and ldd resolves all its dependencies correctly.

Running gst-inspect-1.0 /usr/local/lib/gstreamer-1.0/libgstpython.so, I get:

** (gst-inspect-1.0:9539): CRITICAL **: 14:02:25.125: gi.repository.Gst is no dict
Could not load plugin file: File "/usr/local/lib/gstreamer-1.0/libgstpython.so" appears to be a GStreamer plugin, but it failed to initialize

I don't understand this error. Gst-1.0.typelib is present in /usr/local/lib/girepository-1.0, and I have added that directory to GI_TYPELIB_PATH, and the following test script runs without error:

import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst
Gst.init([])
import srcelement

I realise I could probably register the plugin manually at this point but I was really hoping to end up with something that could just be used normally with gst-launch.

Any thoughts very welcome!

MathieuDuponchelle commented 5 years ago

Hey Martin, I've already seen this error but can't remember what it was about exactly, it is also a pretty terrible warning as that is how it occurs: https://github.com/GStreamer/gst-python/blob/master/plugin/gstpythonplugin.c#L287 . @thiblahute, any idea about that one?

Have you tried using gst-build? This is probably a better idea than messing with your system install, and it'll build pygobject and gst-python master and let you debug easily whatever error occurs.

Sorry not to be of more help, please let me know if you figure this out, we should definitely improve that error message at the very least :)

martinling commented 5 years ago

Hi Mathieu,

Yeah, I did find that code but I couldn't see why PyModule_GetDict should be returning null there. That module is already loaded successfully by PyImport_ImportModule and if there was some problem with it then my test script above should fail too.

I note that PyModule_GetDict is supposed to raise SystemError when it returns null, so I will try patching it to see what message is attached to the exception, maybe that will give some clue.

I can try gst-build, but is there any reason to expect that to give a different result? On this system I'm not actually using gstreamer for anything else, so it's no problem for me to just not have a system install in /usr/lib. At the next step in the project I will be needing to link in some other libraries, so I'd rather not be working in a gst-specific sandbox.

martinling commented 5 years ago

Quick update on this - I added a PyErr_Print() to that error path which gets:

SystemError: ../Objects/moduleobject.c:50: bad argument to internal function

The relevant line in Python (2.7) is here: https://github.com/python/cpython/blob/2.7/Objects/moduleobject.c#L50 So it looks like PyModule_Check() is failing for gst. Which shouldn't really happen given that PyImport_ImportModule succeeded right above there.

MathieuDuponchelle commented 5 years ago

Oh, python 2.7, have you made sure to build gst-python against python 2.7 ?

martinling commented 5 years ago

Yes, I built both pygobject and gst-python against 2.7. And I've also tried building both of those against 3.6 instead. That puts the plugin at /usr/local/lib/gstreamer-1.0/libgstpython.cpython-36m-x86_64-linux-gnu.so, and running gst-inspect-1.0 on that gives the same Gst is no dict error, with the same SystemError result, except that in 3.6 it's at line 470: https://github.com/python/cpython/blob/3.6/Objects/moduleobject.c#L470

MathieuDuponchelle commented 5 years ago

@martinling , did you try giving gst-build a go? If it works, then perhaps it can help you figure out what's different from your current setup

martinling commented 5 years ago

Not yet, I'll try that next.

martinling commented 5 years ago

Right, it works in the uninstalled environment produced by gst-build. So there's something different happening between the meson/ninja based builds and the individual autotools based ones.

I have no idea how to even start tracking down where the problem is, though.

MathieuDuponchelle commented 5 years ago

You could also try installing system-wide with meson instead of autotools, note that we will remove the autotools build system in gstreamer after 1.16. Also note that we plan to remove python2 support from gst-python after 2.7 has reached its EOL (https://pythonclock.org/) so I advise you to plan ahead :)

martinling commented 5 years ago

You could also try installing system-wide with meson instead of autotools

And how would I do that, then? There's no mention of how to build/install with meson in the README, the website, or the FAQ - all refer extensively to autotools. This is the first project I've ever encountered using meson so I have no idea about it - and on checking the source out from git there was nothing to indicate this was anything other than a purely autotools-based project. If you're retiring autotools in the near future then someone really needs to start thinking about documenting this.

Also note that we plan to remove python2 support from gst-python after 2.7 has reached its EOL (https://pythonclock.org/) so I advise you to plan ahead :)

I have 2.7 and 3.6 both installed here and the build chose to use 2.7. I didn't do anything to select this, I had to change it to use 3.6. So if support is getting dropped for 2.7 that seems like it might cause some surprises somewhere.

MathieuDuponchelle commented 5 years ago

And how would I do that, then?

ninja -C build install

There's no mention of how to build/install with meson in the README, the website, or the FAQ - all refer extensively to autotools.

Correct, and that's definitely something we should address, please open an issue against https://gitlab.freedesktop.org/gstreamer/gst-docs :)

I have 2.7 and 3.6 both installed here and the build chose to use 2.7. I didn't do anything to select this, I had to change it to use 3.6. So if support is getting dropped for 2.7 that seems like it might cause some surprises somewhere.

The build by default currently picks whatever "python" points to, in your case python 2.7. When dropping support, we will looks for "python3", and trying to build against another python major version will error out :)

martinling commented 5 years ago

OK, so I did ninja -C build install from my gst-build repository, which appears to have put everything in sensible places although now under /usr/local/lib/x86_64-linux-gnu instead of just /usr/local/lib.

Accounting for that difference in location, if I now run:

LD_LIBRARY_PATH=/usr/local/lib/x86_64-linux-gnu \
GI_TYPELIB_PATH=/usr/local/lib/x86_64-linux-gnu/girepository-1.0 \
gst-inspect-1.0 /usr/local/lib/x86_64-linux-gnu/gstreamer-1.0/libgstpython.so

... I get the same Gst is no dict error as before.

I have cleared out all the previous autotools-installed stuff under /usr/local/lib and the previous pygobject egg that was under /usr/local/lib/python3.6/dist-packages; ninja installs pygobject directly in site-packages. And there are still no debian gstreamer packages installed.

So this is all using the versions built by meson/ninja using gst-build, which worked in the uninstalled environment, but are now hitting the same problem when installed.

martinling commented 5 years ago

Correct, and that's definitely something we should address, please open an issue against https://gitlab.freedesktop.org/gstreamer/gst-docs :)

Now done: https://gitlab.freedesktop.org/gstreamer/gst-docs/issues/22

MathieuDuponchelle commented 5 years ago

You might want to fiddle with the PYTHONPATH, this has given me endless amounts of grief and might be a reason for this mix up, we now actually build pygobject in the gst-build environment systematically to keep some level of sanity. Not knowing your exact environment I'm afraid I can't be of much help, hopefully the difference between the uninstalled environment and the system wide install should make it easier for you to investigate this, please let me know if you figure this out :)

MathieuDuponchelle commented 5 years ago

Also, I notice you're a sigrok dev, awesome, I saw a lightning talk at the gst conf about the lib recently. Don't hesitate to drop by in our IRC channel if you want to have a more direct discussion :)

martinling commented 5 years ago

Thanks, got it - turned out to be PYTHONPATH. The ninja install from gst-build put pygobject in /usr/local/lib/python3.6/site-packages which I thoughts was in the path, but wasn't. Debian's python packages have always had the /usr/local stuff in the path, but apparently the python3 ones don't.

And yes, that was my talk in fact! This is very much related - I was going to start prototyping some ideas. I'm already on the IRC channel, will say hello there.

martinling commented 5 years ago

Debian's python packages have always had the /usr/local stuff in the path, but apparently the python3 ones don't.

After a bit more investigation: /usr/local/lib/python3/dist-packages and /usr/local/lib/python3.6/dist-packages are in the search path (but will only show up in sys.path if the directory exists). But /usr/local/lib/python3.6/site-packages is not, by default. And that's actually unchanged since python 2, which also has dist-packages but not site-packages included by default.

MathieuDuponchelle commented 5 years ago

Good to know you found it out, if you can come up with a gst-python patch to improve the warning, I'll be happy to review and merge, however I do wonder why the call to PyImport_ImportModule does return something, and it's only when calling PyModule_GetDict that a (not very clear) error pops up, any idea?

martinling commented 5 years ago

It's easy enough to change the warning from describing the symptom ("Gst not a dict") to the cause (something wrong with pygobject), but it should probably also suggest the solution. And I'm actually still not sure what that is. I thought it was "you need a newer version of pygobject", but I don't think that's right.

The two merge requests #10 and #8 linked at the top of your article were merged 8-9 months ago, and since then there have been several pygobject releases.

I have the latest one, 3.30.1, already installed through debian, and yet using that triggers the bug - it was only by changing PYTHONPATH to use the version built by gst-build that I was able to fix it.

There aren't many commits between 3.30.1 and the git master version I built by gst-build (commit 91407506), and none of them look relevant.

So actually it's still not clear where the problem is!

martinling commented 5 years ago

I do wonder why the call to PyImport_ImportModule does return something, and it's only when calling PyModule_GetDict that a (not very clear) error pops up, any idea?

Without having looked at the code yet my guess would be that pygobject, being a thing of introspective black magic, is doing some shenanigans where the module dict is something other than a normal dict, and something internal to that implementation is broken.

martinling commented 5 years ago

Just to conclude on this, I never did get to the bottom of what was going wrong here, but with more recent Debian packages this is now working out of the box - looks like pygobject 3.30.4 and gst-python 1.14.4 are sufficient at least.

jefflgaol commented 4 years ago

Hi, there! So, in order to make the plugin can be read, I need to uninstall all gstreamer comes from Debian package? And then install from https://github.com/GStreamer/gst-build using:

  1. meson build/
  2. ninja -C build/
  3. ninja -C build/ install ? Or is my conclusion wrong?
MathieuDuponchelle commented 4 years ago

@jefflgaol I wouldn't advise overwriting your package manager-provided GStreamer with your own custom build. For the purpose of testing, gst-build provides an uninstalled command, which you can run instead of your step 3:

ninja -C build uninstalled

This will drop you off in a shell with several environment variables set so you can test the built products in a sandboxed manner.

miguelwon commented 4 years ago

Hi, I'm having this error WARNING: erroneous pipeline: no element "audiotestsrc_py" when trying to run the example

GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch-1.0 -v audiotestsrc_py ! \
fakesink silent=false
MathieuDuponchelle commented 4 years ago

what's $PWD in your case?

miguelwon commented 4 years ago

The path where I have the python script with your example.

MathieuDuponchelle commented 4 years ago

You should be one level above:

 meh   fix-PyBool-refs  …  gst-python  examples  plugins  tree
.
└── python
    ├── audioplot.py
    ├── exampleTransform.py
    ├── identity.py
    ├── mixer.py
    ├── py_audiotestsrc.py
    ├── __pycache__
    │   ├── audioplot.cpython-37.pyc
    │   ├── exampleTransform.cpython-37.pyc
    │   ├── identity.cpython-37.pyc
    │   ├── mixer.cpython-37.pyc
    │   ├── py_audiotestsrc.cpython-37.pyc
    │   ├── repro.cpython-37.pyc
    │   └── sinkelement.cpython-37.pyc
    ├── repro.py
    └── sinkelement.py

2 directories, 14 files
 meh   fix-PyBool-refs  …  gst-python  examples  plugins  GST_PLUGIN_PATH=$PWD:$GST_PLUGIN_PATH gst-inspect-1.0 python
Plugin Details:
  Name                     python
  Description              loader for plugins written in python
  Filename                 /home/meh/devel/gst-build/subprojects/gst-python/plugin/.libs/libgstpython.cpython-37m-x86_64-linux-gnu.so
  Version                  1.15.0.1
  License                  LGPL
  Source module            gst-python
  Binary package           GStreamer GObject Introspection overrides for Python 
  Origin URL               http://gstreamer.freedesktop.org

  identity_py: Identity Python
  py_videomixer: Videomixer
  niroexample: GST NIRO Example
  ExampleTransform: ExampleTransform Python
  mysink: CustomSink
  py_audiotestsrc: CustomSrc

  6 features:
  +-- 6 elements

 meh   fix-PyBool-refs  …  gst-python  examples  plugins 
miguelwon commented 4 years ago

Sorry, same problem. :(

MathieuDuponchelle commented 4 years ago

Please paste the output of the commands I used

miguelwon commented 4 years ago

Ok, this is what I get:

(venv) pi@raspberrypi:~/experiments/test_custom_plugin/python $ tree
.
└── audiotestsrc_py.py

0 directories, 1 file
(venv) pi@raspberrypi:~/experiments/test_custom_plugin/python $ 
(venv) pi@raspberrypi:~/experiments/test_custom_plugin/python $ cd ..
(venv) pi@raspberrypi:~/experiments/test_custom_plugin $ GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-inspect-1.0 python

(gst-inspect-1.0:3497): GStreamer-WARNING **: 14:23:54.709: Failed to load plugin 'python': python.so: cannot open shared object file: No such file or directory
Could not load plugin file: Opening module failed: python.so: cannot open shared object file: No such file or directory
MathieuDuponchelle commented 4 years ago

Well that'd be your problem, you need to fix your environment first, then your plugin path should point to the parent directory (test_custom_plugin).

Edit: actually my bad, you went back up one folder I see, so yeah, fix your env!

miguelwon commented 4 years ago

Sorry, but I'm not understanding the problem. Why it tries to load python.so? There is no such thing. What do you suggest concerning the environment path? I'm not a big expert in Unix but I think I have all the libraries linked. I run GStreamer correctly (from python scripts) and there are no complaints.

MathieuDuponchelle commented 4 years ago

@miguelwon I can't comment on your environment, on my end as you can see gst-inspect-1.0 correctly displays the elements in the python plugin. Only thing I can suggest is for you to try with gst-build and see if things work better :)

ghost commented 4 years ago

Hi Mathieu,

I have a project for which I want to write some GStreamer elements in Python and I'm trying to get your example from this article working, but running into trouble and I'm wondering if things have gotten broken again in git somewhere.

Details of what I've done are below - wondering if you have any insight, or if you could let me know any git versions of the packages that your example is known to work with.

I have removed all the system gstreamer packages from my Debian testing system, and built and installed from git master all of gstreamer, gstreamer-plugins-base, pygobject and gst-python. The basic gstreamer install seems to be working correctly and I can run simple pipelines with gst-launch-1.0.

With your srcelement.py in python below the current directory, running:

GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-inspect-1.0 audiotestsrc_py

just results in No such element or plugin 'audiotestsrc_py'.

Digging a bit deeper, it seems like there is a problem with the gst-python plugin. It does not show up in the list returned by gst-inspect-1.0, although libgstpython.so is present in /usr/local/lib/gstreamer-1.0/ with everything else, and ldd resolves all its dependencies correctly.

Running gst-inspect-1.0 /usr/local/lib/gstreamer-1.0/libgstpython.so, I get:

** (gst-inspect-1.0:9539): CRITICAL **: 14:02:25.125: gi.repository.Gst is no dict
Could not load plugin file: File "/usr/local/lib/gstreamer-1.0/libgstpython.so" appears to be a GStreamer plugin, but it failed to initialize

I don't understand this error. Gst-1.0.typelib is present in /usr/local/lib/girepository-1.0, and I have added that directory to GI_TYPELIB_PATH, and the following test script runs without error:

import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst
Gst.init([])
import srcelement

I realise I could probably register the plugin manually at this point but I was really hoping to end up with something that could just be used normally with gst-launch.

Any thoughts very welcome!

you need to install the package named python36-gobject-devel. In centos 7, it is yum install https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/p/python36-gobject-devel-3.22.0-6.el7.x86_64.rpm

Hope this help

dayjaby commented 3 years ago

@MathieuDuponchelle a big thanks for the uninstalled hint!! This literally saved my life right now. The gst-uninstalled.py does the same, right? For automatically loading the uninstalled env e.g. in a bashrc, it is important to prevent recursion:

GST_INSPECT=$(which gst-inspect-1.0)
if [[ $GST_INSPECT == /usr/* ]] ;
then
   python3 <path to gst-build/gst-uninstalled.py>
fi
MathieuDuponchelle commented 3 years ago

@dayjaby that uninstalled script has since been renamed gst-env.py fwiw, we do still keep a symlink however :)

ghost commented 3 years ago

Could you add an addendum about how to package the finished element as an .rpm? This seems to require something different that what normal c-based elements require for packaging, but also different from what a python app would require.

MathieuDuponchelle commented 3 years ago

@swestrup I have absolutely no experience with package management I'm afraid :)

UkuKert commented 1 year ago

I had the same problem in deepstream 6.1.1 on a Nvidia Jetson Orin with a custom gstreamer element written in python. The plugin worked without no problems on an AMD docker container, but I faced the same issue when I compiled for ARM and tested on the Jetson. I fixed it by modifying @martinling s answer a bit. I just had to do export PYTHONPATH=$PYTHONPATH:/usr/lib/python3.8/site-packages or in the Dockerfile (works for amd and arm): ENV PYTHONPATH=$PYTHONPATH:/usr/lib/python3.8/site-packages Thanks a lot!