python: update python examples to modern python, Gst, and Glib versions
[experiments/gstreamer.git] / python / gst-custom-player.py
1 #!/usr/bin/env python3
2
3 # Simple media player with GStreamer
4 #
5 # Copyright (C) 2013-2014  Antonio Ospite <ao2@ao2.it>
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 # References:
21 # http://pygstdocs.berlios.de/pygst-reference
22 # https://core.fluendo.com/gstreamer/svn/trunk/gst-fluendo-gdlsink/test/ismdplay.py
23
24 import sys
25 import os
26
27 import gi
28 gi.require_version('Gst', '1.0')
29 from gi.repository import Gst
30 Gst.init(None)
31
32 from gi.repository import GLib
33 from gi.repository import GObject
34
35 # The player window will have a fixed width and height.
36 # This is just to demonstrate the use of capabilities.
37 WIDTH = 640
38 HEIGHT = 300
39
40
41 class CustomVideoBin(Gst.Bin):
42     def __init__(self):
43         Gst.Bin.__init__(self, 'CustomVideoBin')
44
45         queue = Gst.ElementFactory.make('queue', 'vqueue')
46         self.add(queue)
47
48         rescale = Gst.ElementFactory.make("videoscale", "rescale")
49         self.add(rescale)
50         queue.link(rescale)
51
52         caps = Gst.Caps("video/x-raw,format=(fourcc)AYUV,width=%d,height=%d,pixel-aspect-ratio=1/1" % (WIDTH, HEIGHT))
53         capsfilter = Gst.ElementFactory.make("capsfilter", "filter")
54         capsfilter.set_property("caps", caps)
55         self.add(capsfilter)
56         rescale.link(capsfilter)
57
58         videoconvert = Gst.ElementFactory.make("videoconvert", "videoconvert")
59         self.add(videoconvert)
60         capsfilter.link(videoconvert)
61
62         videosink = Gst.ElementFactory.make("autovideosink", "vidoesink")
63         self.add(videosink)
64         videoconvert.link(videosink)
65
66         sink = queue.get_static_pad('sink')
67         self.add_pad(Gst.GhostPad('sink', sink))
68
69
70 class CustomAudioBin(Gst.Bin):
71     def __init__(self):
72         Gst.Bin.__init__(self, 'CustomAudioBin')
73
74         queue = Gst.ElementFactory.make('queue', 'aqueue')
75         self.add(queue)
76
77         audioconvert = Gst.ElementFactory.make("audioconvert", "audioconverter")
78         self.add(audioconvert)
79         queue.link(audioconvert)
80
81         audiosink = Gst.ElementFactory.make("autoaudiosink", "audiosink")
82         self.add(audiosink)
83         audioconvert.link(audiosink)
84
85         sink = queue.get_static_pad('sink')
86         self.add_pad(Gst.GhostPad('sink', sink))
87
88
89 class CustomPlayBin(Gst.Pipeline):
90     __gproperties__ = {
91         'source': (Gst.Element, "source", "Source element", GObject.ParamFlags.READABLE)
92     }
93
94     def __init__(self, uri=None):
95         Gst.Pipeline.__init__(self, 'CustomPlayBin')
96
97         self._playbin = Gst.ElementFactory.make("playbin", "playbin")
98         self.add(self._playbin)
99
100         self._playbin.set_property("video-sink", CustomVideoBin())
101         self._playbin.set_property("audio-sink", CustomAudioBin())
102
103         if uri:
104             self.set_uri(uri)
105
106     def set_uri(self, uri):
107         self._uri = uri
108         self._playbin.set_property("uri", self._uri)
109
110
111 class GstPlayer:
112     def __init__(self):
113
114         # The user can require some action at End Of Stream
115         self.eos_cb = None
116
117         self.pipeline = CustomPlayBin()
118
119         bus = self.pipeline.get_bus()
120         bus.add_signal_watch()
121         bus.connect('message::eos', self.on_eos)
122         bus.connect('message::tag', self.on_tag)
123         bus.connect('message::error', self.on_error)
124         bus.connect('message::state-changed', self.on_state_changed)
125
126     def on_eos(self, bus, msg):
127         print('on_eos')
128         self.stop()
129         if self.eos_cb:
130             self.eos_cb()
131
132     def on_tag(self, bus, msg):
133         print('on_tag:')
134         taglist = msg.parse_tag()
135         print('\t', taglist.to_string())
136
137     def on_error(self, bus, msg):
138         print('on_error')
139         error, debug = msg.parse_error()
140         print("Error: %s" % error, debug)
141         self.stop()
142
143     def on_state_changed(self, bus, msg):
144         print('on_state_changed')
145         if msg.src != self.pipeline:
146             return
147
148         old_state, new_state, pending = msg.parse_state_changed()
149
150     def set_location(self, location):
151         self.pipeline.set_uri(location)
152
153     def play(self):
154         self.pipeline.set_state(Gst.State.PLAYING)
155
156     def pause(self):
157         self.pipeline.set_state(Gst.State.PAUSED)
158
159     def stop(self):
160         self.pipeline.set_state(Gst.State.NULL)
161
162
163 class PlayerTUI():
164     def __init__(self, location):
165
166         self.player = GstPlayer()
167         self.player.eos_cb = self.quit
168
169         self.mainloop = GLib.MainLoop()
170
171         self.player.set_location(location)
172         self.player.play()
173
174         GLib.io_add_watch(sys.stdin, GLib.IO_IN, self.on_stdin)
175
176         try:
177             self.mainloop.run()
178         except KeyboardInterrupt:
179             self.quit()
180
181     def on_stdin(self, fd, event):
182         # The user has to send a newline fo this to go on
183         c = os.read(fd.fileno(), 1)
184
185         if c == "q":
186             self.quit()
187         elif c == "s":
188             self.player.pause()
189         elif c == "r":
190             self.player.play()
191
192         return True
193
194     def quit(self):
195         self.player.stop()
196         self.player = None
197         self.mainloop.quit()
198
199
200 def main(args):
201     def usage():
202         sys.stdout.write("usage: %s <URI-OF-MEDIA-FILE>\n" % args[0])
203
204     if len(args) != 2:
205         usage()
206         sys.exit(1)
207
208     uri = Gst.filename_to_uri(args[1])
209
210     tui = PlayerTUI(uri)
211
212 if __name__ == '__main__':
213     sys.exit(main(sys.argv))