├── .gitignore
├── README.html
├── README.org
├── capabilities-example.py
├── capabilities-playbin-example.py
├── capabilities-resolution-example.py
├── dynamic-ghostpad-example.py
├── functions.js
├── gst-inspect-playbin.txt
├── index.html
├── index.org
├── pipeline-block.svg
├── pipeline-branch-block.svg
├── pipeline-branch-example.py
├── pipeline-example.py
├── playbin-block.svg
├── playbin-example-audio.py
├── playbin-example-cliplayer.py
├── playbin-example-video.py
├── playbin-pads-block.svg
├── pygst-tutorial.html
├── pygst-tutorial.org
├── pygst-tutorial.pdf
├── seeking-example.py
├── setup.org
├── sink-src-block.svg
├── style.css
├── tvlogo.png
├── videomixer-example.py
├── videotestsrc-frame.jpg
└── webcam-example.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.pyc
3 | pygst-tutorial.tex
4 | pipeline-block.pdf
5 | pipeline-branch-block.pdf
6 | playbin-block.pdf
7 | playbin-pads-block.pdf
8 | sink-src-block.pdf
9 | *.ogg
10 | *.mp3
11 | *.mp4
12 | test.*
13 |
--------------------------------------------------------------------------------
/README.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
219 |
Tutorial on using GStreamer Python Bindings (org-mode version)
220 |
221 | This repository holds a tutorial on using the Python bindings for GStreamer 1.0 (re)written in Emacs org-mode.
222 |
223 |
224 |
225 | Note: this was mostly an exercise for me to learn the topic. There is hardly any novel work here.
226 |
227 |
228 |
229 | The main document is ./pygst-tutorial.html. An HTML export of this document is also committed but may not always be up to date. You can read it online at:
230 |
231 |
232 |
233 |
234 | http://brettviren.github.io/pygst-tutorial-org/pygst-tutorial.html
235 |
236 |
237 |
238 |
239 | Or you can download the document as a PDF.
240 |
241 |
242 |
243 | The starting point for this document was Ruben Gonzalez's rescue from Google's cache of the original by Jens Persson. This document differs in:
244 |
245 |
246 |
247 | - Ruben's markdown converted to org-mode
248 |
249 | - Command line and Python examples tested and some fixed for GStreamer 1.0 (problems may remain)
250 |
251 | - Change the ASCII art into ditaa diagrams
252 |
253 | - Text edited for minor language things
254 |
255 |
256 |
257 |
258 | Other useful sources of info on using GStreamer 1.0 Python bindings:
259 |
260 |
261 |
269 |
270 |
271 |
Author: Brett Viren
272 |
Created: 2015-01-04 Sun 15:53
273 |
Emacs 24.3.1 (Org mode 8.2.5a)
274 |
Validate
275 |
276 |
277 |
278 |
--------------------------------------------------------------------------------
/README.org:
--------------------------------------------------------------------------------
1 | #+TITLE: Tutorial on using GStreamer Python Bindings (org-mode version)
2 | #+SETUPFILE: setup.org
3 |
4 | This repository holds a tutorial on using the Python bindings for GStreamer 1.0 (re)written in Emacs org-mode.
5 |
6 | Note: this was mostly an exercise for me to learn the topic. There is hardly any novel work here.
7 |
8 | The main document is [[./pygst-tutorial.org]]. An HTML export of this document is also committed but may not always be up to date. You can read it online at:
9 |
10 | #+BEGIN_QUOTE
11 | http://brettviren.github.io/pygst-tutorial-org/pygst-tutorial.html
12 | #+END_QUOTE
13 |
14 | Or you can download the document as a [[http://brettviren.github.io/pygst-tutorial-org/pygst-tutorial.pdf][PDF]].
15 |
16 | The starting point for this document was [[https://github.com/rubenrua/GstreamerCodeSnippets/tree/master/1.0/Python/pygst-tutorial][Ruben Gonzalez's]] rescue from Google's cache of the original by Jens Persson. This document differs in:
17 |
18 | - Ruben's markdown converted to org-mode
19 | - Command line and Python examples tested and some fixed for GStreamer 1.0 (problems may remain)
20 | - Change the ASCII art into [[http://ditaa.sourceforge.net/][ditaa]] diagrams
21 | - Text edited for minor language things
22 |
23 | Other useful sources of info on using GStreamer 1.0 Python bindings:
24 |
25 | - Ruben's [[https://github.com/rubenrua/GstreamerCodeSnippets][GstreamerCodeSnippets]]
26 | - [[https://lazka.github.io/pgi-docs/#Gst-1.0][API Reference]]
27 | - [[https://wiki.ubuntu.com/Novacut/GStreamer1.0][Novacut's porting guide]]
28 |
--------------------------------------------------------------------------------
/capabilities-example.py:
--------------------------------------------------------------------------------
1 |
2 | #!/usr/bin/env python
3 |
4 | import gi
5 | gi.require_version("Gst", "1.0")
6 | from gi.repository import Gst, GObject, Gtk
7 |
8 | class GTK_Main:
9 |
10 | def __init__(self):
11 | window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
12 | window.set_title("Videotestsrc-Player")
13 | window.set_default_size(300, -1)
14 | window.connect("destroy", Gtk.main_quit, "WM destroy")
15 | vbox = Gtk.VBox()
16 | window.add(vbox)
17 | self.button = Gtk.Button("Start")
18 | self.button.connect("clicked", self.start_stop)
19 | vbox.add(self.button)
20 | window.show_all()
21 | self.player = Gst.Pipeline.new("player")
22 | source = Gst.ElementFactory.make("videotestsrc", "video-source")
23 | sink = Gst.ElementFactory.make("xvimagesink", "video-output")
24 | caps = Gst.Caps.from_string("video/x-raw, width=320, height=230")
25 | filter = Gst.ElementFactory.make("capsfilter", "filter")
26 | filter.set_property("caps", caps)
27 | self.player.add(source)
28 | self.player.add(filter)
29 | self.player.add(sink)
30 | source.link(filter)
31 | filter.link(sink)
32 |
33 | def start_stop(self, w):
34 | if self.button.get_label() == "Start":
35 | self.button.set_label("Stop")
36 | self.player.set_state(Gst.State.PLAYING)
37 | else:
38 | self.player.set_state(Gst.State.NULL)
39 | self.button.set_label("Start")
40 |
41 | GObject.threads_init()
42 | Gst.init(None)
43 | GTK_Main()
44 | Gtk.main()
45 |
--------------------------------------------------------------------------------
/capabilities-playbin-example.py:
--------------------------------------------------------------------------------
1 |
2 | #!/usr/bin/env python
3 |
4 | import os
5 | import gi
6 | gi.require_version("Gst", "1.0")
7 | from gi.repository import Gst, GObject, Gtk
8 |
9 | class GTK_Main:
10 | def __init__(self):
11 | window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
12 | window.set_title("Video-Player")
13 | window.set_default_size(500, 400)
14 | window.connect("destroy", Gtk.main_quit, "WM destroy")
15 | vbox = Gtk.VBox()
16 | window.add(vbox)
17 | hbox = Gtk.HBox()
18 | vbox.pack_start(hbox, False, False, 0)
19 | self.entry = Gtk.Entry()
20 | hbox.add(self.entry)
21 | self.button = Gtk.Button("Start")
22 | hbox.pack_start(self.button, False, False, 0)
23 | self.button.connect("clicked", self.start_stop)
24 | self.movie_window = Gtk.DrawingArea()
25 | vbox.add(self.movie_window)
26 | window.show_all()
27 | self.player = Gst.ElementFactory.make("playbin", "player")
28 | self.bin = Gst.Bin.new("my-bin")
29 | videoscale = Gst.ElementFactory.make("videoscale")
30 | videoscale.set_property("method", 1)
31 | pad = videoscale.get_static_pad("sink")
32 | ghostpad = Gst.GhostPad.new("sink", pad)
33 | ghostpad.set_active(True)
34 | self.bin.add_pad(ghostpad)
35 | caps = Gst.Caps.from_string("video/x-raw, width=720")
36 | filter = Gst.ElementFactory.make("capsfilter", "filter")
37 | filter.set_property("caps", caps)
38 | textoverlay = Gst.ElementFactory.make('textoverlay')
39 | textoverlay.set_property("text", "GNUTV")
40 | textoverlay.set_property("font-desc", "normal 14")
41 | # TypeError: object of type `GstTextOverlay' does not have property `halign'
42 | #textoverlay.set_property("halign", "right")
43 | # TypeError: object of type `GstTextOverlay' does not have property `valign'
44 | #textoverlay.set_property("valign", "top")
45 | conv = Gst.ElementFactory.make ("videoconvert", "conv")
46 | videosink = Gst.ElementFactory.make("autovideosink")
47 |
48 | self.bin.add(videoscale)
49 | self.bin.add(filter)
50 | self.bin.add(textoverlay)
51 | self.bin.add(conv)
52 | self.bin.add(videosink)
53 |
54 | videoscale.link(filter)
55 | filter.link(textoverlay)
56 | textoverlay.link(conv)
57 | conv.link(videosink)
58 |
59 | self.player.set_property("video-sink", self.bin)
60 | bus = self.player.get_bus()
61 | bus.add_signal_watch()
62 | bus.enable_sync_message_emission()
63 | bus.connect("message", self.on_message)
64 | bus.connect("sync-message::element", self.on_sync_message)
65 |
66 | def start_stop(self, w):
67 | if self.button.get_label() == "Start":
68 | filepath = self.entry.get_text().strip()
69 | if os.path.exists(filepath):
70 | filepath = os.path.realpath(filepath)
71 | self.button.set_label("Stop")
72 | self.player.set_property("uri", "file://" + filepath)
73 | self.player.set_state(Gst.State.PLAYING)
74 | else:
75 | self.player.set_state(Gst.State.NULL)
76 | self.button.set_label("Start")
77 |
78 | def on_message(self, bus, message):
79 | typ = message.type
80 | if typ == Gst.MessageType.EOS:
81 | self.player.set_state(Gst.State.NULL)
82 | self.button.set_label("Start")
83 | elif typ == Gst.MessageType.ERROR:
84 | self.player.set_state(Gst.State.NULL)
85 | self.button.set_label("Start")
86 | err, debug = message.parse_error()
87 | print("Error: %s" % err, debug)
88 |
89 | def on_sync_message(self, bus, message):
90 | if message.structure is None:
91 | return
92 | message_name = message.structure.get_name()
93 | if message_name == "prepare-xwindow-id":
94 | imagesink = message.src
95 | imagesink.set_property("force-aspect-ratio", True)
96 | imagesink.set_xwindow_id(self.movie_window.window.xid)
97 |
98 | GObject.threads_init()
99 | Gst.init(None)
100 | GTK_Main()
101 | Gtk.main()
102 |
--------------------------------------------------------------------------------
/capabilities-resolution-example.py:
--------------------------------------------------------------------------------
1 |
2 | #!/usr/bin/env python
3 |
4 | import os
5 | import gi
6 | gi.require_version("Gst", "1.0")
7 | from gi.repository import Gst, GObject, Gtk
8 |
9 | class GTK_Main:
10 | def __init__(self):
11 | window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
12 | window.set_title("Resolutionchecker")
13 | window.set_default_size(300, -1)
14 | window.connect("destroy", Gtk.main_quit, "WM destroy")
15 | vbox = Gtk.VBox()
16 | window.add(vbox)
17 | self.entry = Gtk.Entry()
18 | vbox.pack_start(self.entry, False, True, 0)
19 | self.button = Gtk.Button("Check")
20 | self.button.connect("clicked", self.start_stop)
21 | vbox.add(self.button)
22 | window.show_all()
23 | self.player = Gst.Pipeline.new("player")
24 | source = Gst.ElementFactory.make("filesrc", "file-source")
25 | decoder = Gst.ElementFactory.make("decodebin", "decoder")
26 | decoder.connect("pad-added", self.decoder_callback)
27 | self.fakea = Gst.ElementFactory.make("fakesink", "fakea")
28 | self.fakev = Gst.ElementFactory.make("fakesink", "fakev")
29 | self.player.add(source)
30 | self.player.add(decoder)
31 | self.player.add(self.fakea)
32 | self.player.add(self.fakev)
33 | source.link(decoder)
34 | bus = self.player.get_bus()
35 | bus.add_signal_watch()
36 | bus.connect("message", self.on_message)
37 |
38 | def start_stop(self, w):
39 | filepath = self.entry.get_text().strip()
40 | if os.path.isfile(filepath):
41 | filepath = os.path.realpath(filepath)
42 | self.player.set_state(Gst.State.NULL)
43 | self.player.get_by_name("file-source").set_property("location", filepath)
44 | self.player.set_state(Gst.State.PAUSED)
45 | def on_message(self, bus, message):
46 | typ = message.type
47 | if typ == Gst.MessageType.STATE_CHANGED:
48 | if message.parse_state_changed()[1] == Gst.State.PAUSED:
49 | decoder = self.player.get_by_name("decoder")
50 | for pad in decoder.srcpads:
51 | caps = pad.query_caps(None)
52 | structure_name = caps.to_string()
53 | width = caps.get_structure(0).get_int('width')
54 | height = caps.get_structure(0).get_int('height')
55 | if structure_name.startswith("video") and len(str(width)) < 6:
56 | print "Width:%d, Height:%d" %(width, height)
57 | self.player.set_state(Gst.State.NULL)
58 | break
59 | elif typ == Gst.MessageType.ERROR:
60 | err, debug = message.parse_error()
61 | print("Error: %s" % err, debug)
62 | self.player.set_state(Gst.State.NULL)
63 |
64 | def decoder_callback(self, decoder, pad):
65 | caps = pad.query_caps(None)
66 | structure_name = caps.to_string()
67 | if structure_name.startswith("video"):
68 | fv_pad = self.fakev.get_static_pad("sink")
69 | pad.link(fv_pad)
70 | elif structure_name.startswith("audio"):
71 | fa_pad = self.fakea.get_static_pad("sink")
72 | pad.link(fa_pad)
73 |
74 | GObject.threads_init()
75 | Gst.init(None)
76 | GTK_Main()
77 | Gtk.main()
78 |
--------------------------------------------------------------------------------
/dynamic-ghostpad-example.py:
--------------------------------------------------------------------------------
1 |
2 | #!/usr/bin/env python
3 |
4 | import sys, os
5 | import gi
6 | gi.require_version('Gst', '1.0')
7 | from gi.repository import Gst, GObject, Gtk
8 |
9 | class GTK_Main(object):
10 |
11 | def __init__(self):
12 | window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
13 | window.set_title("Vorbis-Player")
14 | window.set_default_size(500, 200)
15 | window.connect("destroy", Gtk.main_quit, "WM destroy")
16 | vbox = Gtk.VBox()
17 | window.add(vbox)
18 | self.entry = Gtk.Entry()
19 | vbox.pack_start(self.entry, False, False, 0)
20 | self.button = Gtk.Button("Start")
21 | vbox.add(self.button)
22 | self.button.connect("clicked", self.start_stop)
23 | window.show_all()
24 |
25 | self.player = Gst.Pipeline.new("player")
26 | source = Gst.ElementFactory.make("filesrc", "file-source")
27 | demuxer = Gst.ElementFactory.make("oggdemux", "demuxer")
28 | demuxer.connect("pad-added", self.demuxer_callback)
29 | self.audio_decoder = Gst.ElementFactory.make("vorbisdec", "vorbis-decoder")
30 | audioconv = Gst.ElementFactory.make("audioconvert", "converter")
31 | audiosink = Gst.ElementFactory.make("autoaudiosink", "audio-output")
32 |
33 | self.player.add(source)
34 | self.player.add(demuxer)
35 | self.player.add(self.audio_decoder)
36 | self.player.add(audioconv)
37 | self.player.add(audiosink)
38 |
39 | source.link(demuxer)
40 | self.audio_decoder.link(audioconv)
41 | audioconv.link(audiosink)
42 |
43 | bus = self.player.get_bus()
44 | bus.add_signal_watch()
45 | bus.connect("message", self.on_message)
46 |
47 | def start_stop(self, w):
48 | if self.button.get_label() == "Start":
49 | filepath = self.entry.get_text().strip()
50 | if os.path.isfile(filepath):
51 | filepath = os.path.realpath(filepath)
52 | self.button.set_label("Stop")
53 | self.player.get_by_name("file-source").set_property("location", filepath)
54 | self.player.set_state(Gst.State.PLAYING)
55 | else:
56 | self.player.set_state(Gst.State.NULL)
57 | self.button.set_label("Start")
58 |
59 | def on_message(self, bus, message):
60 | t = message.type
61 | if t == Gst.MessageType.EOS:
62 | self.player.set_state(Gst.State.NULL)
63 | self.button.set_label("Start")
64 | elif t == Gst.MessageType.ERROR:
65 | err, debug = message.parse_error()
66 | print("Error: %s" % err, debug)
67 | self.player.set_state(Gst.State.NULL)
68 | self.button.set_label("Start")
69 |
70 | def demuxer_callback(self, demuxer, pad):
71 | adec_pad = self.audio_decoder.get_static_pad("sink")
72 | pad.link(adec_pad)
73 |
74 |
75 | GObject.threads_init()
76 | Gst.init(None)
77 | GTK_Main()
78 | Gtk.main()
79 |
--------------------------------------------------------------------------------
/functions.js:
--------------------------------------------------------------------------------
1 | $( document ).ready (function () {
2 | $("pre.src-sh").each(function () {
3 | var lines = $( this ).text().split('\n');
4 | for (var ind = 0 ; ind < lines.length ; ind++) {
5 | if ( ! lines[ind] ) {
6 | continue;
7 | }
8 | lines[ind] = '