More Python examples and more descriptions of inter-pipeline conections

This commit is contained in:
Matthew Clark 2018-06-11 23:42:50 +01:00
parent dbd54c4033
commit 5065eecd11
7 changed files with 191 additions and 6 deletions

View file

@ -12,9 +12,10 @@ A few Python examples are also [included](python_examples/) for when you need GS
* [Mixing video & audio](mixing.md)
* [Images](images.md)
* [Queues](queues.md)
* [Writing to files](writing_to_files.md)
* [Capturing images](capturing_images.md)
* [Sending to multiple destinations (tee)](tee.md)
* [Sharing and receiving pipelines, including sending/receiving video from shared memory](sharing_and_splitting_pipelines.md)
* [Sharing and receiving pipelines (including sending/receiving video from shared memory)](sharing_and_splitting_pipelines.md)
* [Network transfer](network_transfer.md) (including how to send so that VLC can preview)
## Sources and references

View file

@ -2,7 +2,7 @@
## Playing content
For these,set `SRC` to be e.g. an mp4 file., e.g.
These examples assume that bash variable `SRC` to be set to a video file (e.g. an mp4 file). You can do this by, e.g.
```
export SRC=/home/me/videos/test.mp4
@ -130,7 +130,13 @@ gst-launch-1.0 -v uridecodebin uri="file://$AUDIO_SRC" ! autoaudiosink
gst-launch-1.0 -v filesrc location=$AUDIO_SRC ! mpegaudioparse ! decodebin ! autoaudiosink
```
### Play files back to back
See (https://coaxion.net/blog/2014/08/concatenate-multiple-streams-gaplessly-with-gstreamer/)[https://coaxion.net/blog/2014/08/concatenate-multiple-streams-gaplessly-with-gstreamer/]
### Jumping to a certain point in a video/audio (seek/rewind/restart)
As far as I know, this isn't possible on the command-line. But it is possible as code. Here is a simple Python example:
[/python_examples/seeking.py](/python_examples/seeking.py)

View file

@ -0,0 +1,19 @@
#!/usr/bin/env python
# Shows how two pipelines can be connected, using interaudiosink/interaudiosrc.
# (Search and replace 'audio' with 'video' to get a video example.)
# It will output a test audio sound.
import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst
import os
Gst.init(None)
mainloop = GObject.MainLoop()
pipe1 = Gst.parse_launch("audiotestsrc is-live=1 ! interaudiosink name=psink")
pipe2 = Gst.parse_launch("interaudiosrc name=psrc ! autoaudiosink")
pipe1.set_state(Gst.State.PLAYING)
pipe2.set_state(Gst.State.PLAYING)
mainloop.run()

View file

@ -0,0 +1,87 @@
#!/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()

View file

@ -0,0 +1,25 @@
#!/usr/bin/env python
# Shows seeking in action.
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()
pipe = Gst.parse_launch("playbin uri=\"file://" + os.environ['SRC'] + "\"")
pipe.set_state(Gst.State.PLAYING)
def separate_thread():
while True:
seconds = input("Enter the number of seconds to jump to (0=start): ")
seek_success = pipe.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, Gst.SECOND * int(seconds))
print ('seek_success=' + str(seek_success))
myThread = Thread(target=separate_thread, args=())
myThread.start()
mainloop.run()

View file

@ -26,7 +26,7 @@ _As with the rest of this site, this is a rough guide, and is probably not compl
| *appsrc/appsink* | Allows video data to leave/enter the pipeline from your own application | n/a | https://thiblahute.github.io/GStreamer-doc/app-1.0/index.html?gi-language=c |
| *fdsrc/fdsink* | Allows communication via a file descriptor | n/a | https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-fdsrc.html |
| *interpipe* | Allows simple communication between two or more independent pipelines. Very powerful. | * Not part of GStreamer (though it is open-source... I'm not sure why it's not been included) | * Well-documented at https://developer.ridgerun.com/wiki/index.php?title=GstInterpipe<br>* https://gstreamer.freedesktop.org/data/events/gstreamer-conference/2015/Melissa%20Montero%20-%20GST%20Daemon%20and%20Interpipes:%20A%20simpler%20way%20to%20get%20your%20applications%20done%20.pdf |
| *inter* (intervideosink, etc) | Send/receive AV between two pipelines in the same process | Only support raw audio or video, and drop events and queries at the boundary (source: [Nirbheek's blog](http://blog.nirbheek.in/2018/02/decoupling-gstreamer-pipelines.html)) | * https://thiblahute.github.io/GStreamer-doc/inter-1.0/index.html?gi-language=c<br>* Pros and cons discussed here: http://gstreamer-devel.966125.n4.nabble.com/How-to-connect-intervideosink-and-intervideosrc-for-IPC-pipelines-td4684567.html |
| *inter* (intervideosink, etc) | Send/receive AV between two pipelines in the same process | Only support raw audio or video, and drop events and queries at the boundary (source: [Nirbheek's blog](http://blog.nirbheek.in/2018/02/decoupling-gstreamer-pipelines.html)) | See below |
| *ipcpipeline* | Allows communication between pipelines *in different processes*. | Arrived with GStreamer 1.14 (Spring 2018) | https://www.collabora.com/news-and-blog/blog/2017/11/17/ipcpipeline-splitting-a-gstreamer-pipeline-into-multiple-processes/ |
| *gstproxy (proxysink and proxysrc)* | Send/receive AV between two pipelines in the same process. | Arrived with GStreamer 1.14 (Spring 2018) | See below |
@ -72,8 +72,9 @@ gst-launch-1.0 shmsrc socket-path=/tmp/tmpsock ! \
## gstproxy (proxysink and proxysrc)
I've used `proxysink` and `proxysrc` to split large pipelines into smaller ones. That way, if a part fails, the rest can continue.
I've used `proxysink` and `proxysrc` to split larger pipelines into smaller ones. That way, if a part fails, the rest can continue.
Unlike _inter_ below, _proxy_ will keep timing in sync. This is great if it's what you want... but if you want pipelines to have their own timing, it might not be right for your needs..
### gstproxy documentation
@ -81,7 +82,6 @@ I've used `proxysink` and `proxysrc` to split large pipelines into smaller ones.
* Example code on proxysrc here: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-proxysrc.html
* Equivalent proxysink: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-proxysink.html
### gstproxy examples
It's not possible to use them via the command-line, because you connect them by having the receiver (`proxysrc`) reference the sender (`proxysink`).
@ -104,3 +104,21 @@ A slightly more interesting example can be found at
* that `proxysink` can work with [`playbin`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-playbin.html)
* separate proxies for audio and video
* that when the video ends, the other pipelines continue.
## inter (intervideosink/intervideosrc and their audio & subtitle counterparts)
The 'inter' versions of 'proxy' are dumber. They don't attempt to sync timings. But this can be useful if you want pipelines to be more independent. (Pros and cons on this discussed [here](http://gstreamer-devel.966125.n4.nabble.com/How-to-connect-intervideosink-and-intervideosrc-for-IPC-pipelines-td4684567.html).)
* `interaudiosink` and `intervideosink` allow a pipeline to send audio/video to another pipeline.
* `interaudiosrc` and `intervideosrc` are the corresponding elements for receiving the audio/video.
* subtitle versions are available too.
They are documented here: https://thiblahute.github.io/GStreamer-doc/inter-1.0/index.html?gi-language=c<
An example can't be done via the command-line, but here is a simple example using Python:
[/python_examples/gstinter_01_audiotestsrc.py](/python_examples/gstinter_01_audiotestsrc.py)
Here's a more complex example, showing how two files can have separate seeking by being in different pipelines:
[/python_examples/gstinter_02_separate_seeking](/python_examples/gstinter_02_separate_seeking)

View file

@ -1,7 +1,36 @@
# Writing to files (GStreamer command-line cheat sheet)
The [`filesink`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-filesink.html) element allows writing to a file.
Note that, when using the command-line, the `-e` parameter ensures the output file is correctly completed on exit.
### Write to an mp4 file
This example creates a test video (animated ball moving, with clock), and writes it as an MP4 file.
Also added is an audio test source - a short beep every second.
Leave it running for a few seconds, and then CTRL-C to stop it.
```
gst-launch-1.0 -e videotestsrc pattern=ball ! \
video/x-raw,width=1280,height=720 ! \
timeoverlay font-desc="Sans, 48" ! \
x264enc ! mux. \
audiotestsrc is-live=true wave=ticks ! audioconvert ! audioresample ! faac bitrate=32000 ! mux. \
mp4mux name=mux ! filesink location=file.mp4
```
### Other examples
```
gst-launch-1.0 -e videotestsrc ! video/x-raw-yuv, framerate=25/1, width=640, height=360 ! x264enc ! \
mpegtsmux ! filesink location=test.ts
```
```
gst-launch-1.0 -e videotestsrc !\
x264enc !\
mpegtsmux !\
filesink location=test.ts
```