gstreamer-cheat-sheet/python_examples/gstinter_02_separate_seeking.py

88 lines
3.3 KiB
Python
Raw Normal View History

#!/usr/bin/env python
'''
To run this, set the environment variables $SRC and $SRC2 to full paths to two mp4 files.
This has three pipelines:
- Pipeline 1 plays the file $SRC
- Pipeline 2 plays the file $SRC2
- Pipeline 3 displays them mixed
Pipeline-1 --\
---> Pipeline3
Pipeline 2 --/
This demo shows how, by splitting into pipelines, each soure can be seeked independently.
And if one fails (e.g. file not found), the other continues.
'''
import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst
import os
from time import sleep
from threading import Thread
Gst.init(None)
mainloop = GObject.MainLoop()
# We make the two pipelines
pipe1 = Gst.parse_launch("playbin uri=\"file://" + os.environ['SRC'] + "\"")
pipe2 = Gst.parse_launch("playbin uri=\"file://" + os.environ['SRC2'] + "\"")
# The third pipeline is more complex as it has to accept the other two, and mix.
pipe3 = Gst.parse_launch(
"intervideosrc name=video_src_1 ! videomix. " +
"interaudiosrc name=audio_src_1 ! autoaudiosink "
"intervideosrc name=video_src_2 ! videomix. " +
"interaudiosrc name=audio_src_2 ! autoaudiosink " +
"compositor name=videomix sink_1::xpos=800 sink_1::ypos=800 ! autovideosink "
)
# Because 'playbin' is a bin rather than element, the bit we want within it is 'playsink':
pipe1_playsink = pipe1.get_by_name('playsink')
pipe2_playsink = pipe2.get_by_name('playsink')
audio_src_1 = pipe3.get_by_name('audio_src_1')
video_src_1 = pipe3.get_by_name('video_src_1')
audio_src_2 = pipe3.get_by_name('audio_src_2')
video_src_2 = pipe3.get_by_name('video_src_2')
# Make the sinks for the first two pipelines:
video_sink_1 = Gst.ElementFactory.make("intervideosink", "video_sink_1")
audio_sink_1 = Gst.ElementFactory.make("interaudiosink", "audio_sink_1")
video_sink_2 = Gst.ElementFactory.make("intervideosink", "video_sink_2")
audio_sink_2 = Gst.ElementFactory.make("interaudiosink", "audio_sink_2")
pipe1_playsink.set_property('video-sink', video_sink_1)
pipe1_playsink.set_property('audio-sink', audio_sink_1)
pipe2_playsink.set_property('video-sink', video_sink_2)
pipe2_playsink.set_property('audio-sink', audio_sink_2)
# We use 'channel' to name the two different connections between
video_sink_1.set_property('channel', 'video-channel-1')
audio_sink_1.set_property('channel', 'audio-channel-1')
video_src_1.set_property('channel', 'video-channel-1')
audio_src_1.set_property('channel', 'audio-channel-1')
video_sink_2.set_property('channel', 'video-channel-2')
audio_sink_2.set_property('channel', 'audio-channel-2')
video_src_2.set_property('channel', 'video-channel-2')
audio_src_2.set_property('channel', 'audio-channel-2')
# Off we go!
pipe1.set_state(Gst.State.PLAYING)
pipe2.set_state(Gst.State.PLAYING)
pipe3.set_state(Gst.State.PLAYING)
# This bit allows the user to specitfy different offsets for each video
def separate_thread():
while True:
seconds = input("Enter the number of seconds to jump the FIRST video to (0=start): ")
pipe1.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, Gst.SECOND * int(seconds))
seconds = input("Enter the number of seconds to jump the SECOND video to (0=start): ")
pipe2.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, Gst.SECOND * int(seconds))
myThread = Thread(target=separate_thread, args=())
myThread.start()
mainloop.run()