I am trying to make a simple Gstreamer pipeline in python that will take input from the webcam and show it on a video window.
The following code works as expected:
import gi
gi.require_version("Gst", "1.0")
from gi.repository import Gst, GLib
from threading import Thread
Gst.init()
main_loop = GLib.MainLoop()
pipeline = Gst.parse_launch("v4l2src ! decodebin ! videoconvert ! autovideosink")
main_loop_tread = Thread(target=main_loop.run)
main_loop_tread.start()
pipeline.set_state(Gst.State.PLAYING)
However, when I try to do the same thing with a manually created pipeline, the pipeline does not show any window. My camera light still turns on, but I get no video window popup. Also, if I reaplce the autovideo sink with an appsink, every buffer I get is None.
import gi
gi.require_version("Gst", "1.0")
from gi.repository import Gst, GLib
from threading import Thread
Gst.init()
main_loop = GLib.MainLoop()
pipeline = Gst.Pipeline()
main_loop_tread = Thread(target=main_loop.run)
main_loop_tread.start()
src = Gst.ElementFactory.make("v4l2src")
decode = Gst.ElementFactory.make("decodebin")
convert = Gst.ElementFactory.make("videoconvert")
sink = Gst.ElementFactory.make("autovideosink")
pipeline.add(src)
pipeline.add(decode)
pipeline.add(convert)
pipeline.add(sink)
src.link(decode)
decode.link(convert)
convert.link(sink)
pipeline.set_state(Gst.State.PLAYING)
What is wrong with the second code example?
I ran your code with GST_DEBUG=3
flag and saw warnings
$ GST_DEBUG=3 python3 python_gstreamer.py
0:00:00.010488893 2604612 0x55d4f997cc00 FIXME default gstutils.c:4025:gst_pad_create_stream_id_internal:<videotestsrc0:src> Creating random stream-id, consider implementing a deterministic way of creating a stream-id
0:00:00.011231276 2604612 0x55d4f997cc00 WARN basesrc gstbasesrc.c:3127:gst_base_src_loop:<videotestsrc0> error: Internal data stream error.
0:00:00.011236130 2604612 0x55d4f997cc00 WARN basesrc gstbasesrc.c:3127:gst_base_src_loop:<videotestsrc0> error: streaming stopped, reason not-linked (-1)
Then I ran it with GST_DEBUG=4
to find more details and I noticed that the decodebin
element wasn't being linked to videoconvert
element properly.
$ GST_DEBUG=4 python3 python_gstreamer.py
...
0:00:00.008857654 2606874 0x564edfcf68a0 INFO GST_ELEMENT_PADS gstutils.c:1816:gst_element_link_pads_full: trying to link element decodebin0:(any) to element videoconvert0:(any)
0:00:00.008860541 2606874 0x564edfcf68a0 INFO GST_PADS gstpad.c:4357:gst_pad_peer_query:<videoconvert0:src> pad has no peer
0:00:00.008934791 2606874 0x564edfcf68a0 INFO GST_ELEMENT_PADS gstelement.c:1013:gst_element_get_static_pad: no such pad 'src_%u' in element "decodebin0"
0:00:00.008941910 2606874 0x564edfcf68a0 INFO GST_ELEMENT_PADS gstutils.c:1270:gst_element_get_compatible_pad:<decodebin0> Could not find a compatible pad to link to videoconvert0:sink
...
Apparently, you have to handle the "pad-added" signal emitted by decodebin and then link the new pad to the sink pad of next element.
import gi
gi.require_version("Gst", "1.0")
from gi.repository import Gst, GLib
from threading import Thread
Gst.init()
def pad_added_handler(src, new_pad, convert):
sink_pad = convert.get_static_pad("sink")
if sink_pad.is_linked():
return
new_pad.link(sink_pad)
main_loop = GLib.MainLoop()
pipeline = Gst.Pipeline()
main_loop_tread = Thread(target=main_loop.run)
main_loop_tread.start()
src = Gst.ElementFactory.make("v4l2src")
decode = Gst.ElementFactory.make("decodebin")
convert = Gst.ElementFactory.make("videoconvert")
sink = Gst.ElementFactory.make("autovideosink")
pipeline.add(src)
pipeline.add(decode)
pipeline.add(convert)
pipeline.add(sink)
src.link(decode)
convert.link(sink)
decode.connect("pad-added", pad_added_handler, convert)
pipeline.set_state(Gst.State.PLAYING)
Note: I tested the code with videotestsrc
element instead of v4l2src
as I don't have usb camera.