How to launch Gstreamer pipeline in Python
5 min. read |
Common use of Gstreamer is through command line. In the next post we are going to launch Gstreamer pipeline from Python. This could be helpful for those who have already working pipeline and want to debug/extend it with own code.
Requirements
- Ubuntu 18.04
- Python 3.6
- Gstreamer with Python Bindings
- I hope you have installed Gstreamer. If not – look at this post “How to install Gstreamer Python Bindings on Ubuntu 18”.
Code
What you’ll learn?
Go through next simple steps and learn how to launch Gstreamer pipeline within Python script in two common ways:
- with Gst.parse_launch
- with Gst.ElementFactory
Guide
Setup gst-python-tutorials
git clone https://github.com/jackersson/gst-python-tutorials.git cd gst-python-tutorials python3 -m venv venv source venv/bin/activate pip install --upgrade wheel pip setuptools pip install --upgrade --requirement requirements.txt
Basics
Import
At first import Gstreamer into Python script. Common libraries to import are Gst, GObject, GstApp, GstVideo, etc. To explore all of them use Python GObject API reference.
import gi gi.require_version('Gst', '1.0') from gi.repository import Gst, GObject
Note: If you do not specify “gi.require_version“ you’ll get warning message:
Gst was imported without specifying a version first. \ Use gi.require_version('Gst', '1.0') before \ import to ensure that the right version gets loaded
Init Gstreamer
Gst.init(sys.argv)
This call initializes the GStreamer library, setting up internal path lists, registering built-in elements, and loading standard plugins.
Note: if you do not call Gst.init you’ll get next error:
gi.overrides.Gst.NotInitialized: Please call \ Gst.init(argv) before using GStreamer
Define Pipeline
Gstreamer Pipeline is simple container of ordered elements through which data flows in specific direction, from Src to Sink.
For simplicity we’ll use “hello world” pipeline. Check it in your terminal.
gst-launch-1.0 videotestsrc num-buffers=50 ! autovideosink
Following pipeline generates 50 buffers of next video pattern. Hope you got similar window.
Let’s init this pipeline in python.
Init Pipeline in Python
Note: Gstreamer Pipeline in Python: Gst.Pipeline
With Gst.parse_launch
This method is fast and useful when you don’t want to handle connections between plugins manually and just want to launch some existing pipeline. Creating pipeline with Gst.parse_launch is very simple and flexible solution.
# Gst.Pipeline pipeline = Gst.parse_launch("videotestsrc num-buffers=50 ! autovideosink")
With Gst.ElementFactory
Next approach is for those who wants to handle all elements, properties, connections. This approach requires more advanced Gstreamer knowledge.
Gst.ElementFactory is suitable when you exactly know the pipeline and don’t change it to often.
# create pipeline object pipeline = Gst.Pipeline() # create Gst.Element by plugin name src = Gst.ElementFactory.make("videotestsrc") # as Gst.Element inherit from GObject # we can use GObject methods to set property of element src.set_property("num-buffers", 50) # create Gst.Element by plugin name sink = Gst.ElementFactory.make("gtksink") # as Gst.Pipeline is container of Gst.Elements # add src, sink to Gst.Pipeline pipeline.add(src, sink) # link src with sink # Note: elements should be elements of same Gst.Pipeline src.link(sink)
Start Pipeline
To start pipeline just set pipeline’s state to Gst.State.PLAYING (list of pipeline’s states)
pipeline.set_state(Gst.State.PLAYING)
To reset pipeline set NULL state:
pipeline.set_state(Gst.State.NULL)
Run GObject.MainLoop
Start GObject.MainLoop for pipeline to enable: receive signals, events, states or handle messages from Gst.Bus.
# Init GObject loop to handle Gstreamer Bus Events loop = GObject.MainLoop() try: loop.run() except: loop.quit()
Handle messages with Gst.Bus
Pipeline’s Bus allows handle messages in main thread. All errors, tags, meta info could be handled by Gst.Bus
# https://lazka.github.io/pgi-docs/Gst-1.0/classes/Bus.html bus = pipeline.get_bus() # allow bus to emit messages to main thread bus.add_signal_watch() # Add handler to specific signal # https://lazka.github.io/pgi-docs/GObject-2.0/classes/Object.html#GObject.Object.connect bus.connect("message", on_message, None)
Note: Every object in Gst module is GObject itself, so a lot of capabilities from GObject are accessible. For example, in Gst.Bus with GObject’s connect you can add message handler, like this (those are basic message types that you should handle in any Gstreamer Pipeline):
def on_message(bus: Gst.Bus, message: Gst.Message, loop: GObject.MainLoop): mtype = message.type """ Gstreamer Message Types and how to parse https://lazka.github.io/pgi-docs/Gst-1.0/flags.html#Gst.MessageType """ if mtype == Gst.MessageType.EOS: # Handle End of Stream print("End of stream") loop.quit() elif mtype == Gst.MessageType.ERROR: # Handle Errors err, debug = message.parse_error() print(err, debug) loop.quit() elif mtype == Gst.MessageType.WARNING: # Handle warnings err, debug = message.parse_warning() print(err, debug) return True
Run Examples
python launch_pipeline/pipeline_with_factory.py
Note: Look at videotestsrc patterns and try them. In previous example I changed pattern with next line of code:
src.set_property("pattern", "snow")
With pipeline_with_factory.py you can pass any pipeline
python launch_pipeline/pipeline_with_parse_launch.py \ -p "videotestsrc num-buffers=100 pattern=1 ! autovideosink"
Conclusion
- Gstreamer pipeline can be launched in Python script using Gst.parse_launch or Gst.ElementFactory
Hope everything works as expected 🙂 . In case of any troubles – leave comments.
Great tutorial. Can you share how to add capabilities to the Element factory