quit function should reference self
[python-gstreamer-examples] / example5.py
1 #!/usr/bin/env python
2 # Attempting to dynamically switch between input sources
3
4 # GdkX11 to get access to xid, GstVideo to get access to set_window_handle
5 import gi, signal, time
6 gi.require_version('Gtk', '3.0')
7 gi.require_version('Gst', '1.0')
8 gi.require_version('GstVideo', '1.0')
9 from gi.repository import Gtk, Gst, GdkX11, GstVideo
10
11 stream1="rtmp://matuku.hig.no/live/planet.stream"
12
13 class Main:
14 def __init__(self):
15
16 # Create gui bits and bobs
17
18 self.mainwindow = Gtk.Builder()
19 self.mainwindow.add_from_file("example5.glade")
20
21 signals = {
22 "on_input1_clicked" : self.SetInput1,
23 "on_input2_clicked" : self.SetInput2,
24 "on_input3_clicked" : self.SetInput3,
25 "on_input4_clicked" : self.SetInput4,
26 "on_input5_clicked" : self.SetInput5,
27 "on_input6_clicked" : self.SetInput6,
28 "on_quit_clicked" : self.OnQuit,
29 }
30
31 self.mainwindow.connect_signals(signals)
32
33 # Create GStreamer bits and bobs
34
35 # Initiate Gstreamer
36 Gst.init(None)
37
38 # Some capabilities we want to share between different elements
39 jpegcaps = Gst.Caps.from_string("image/jpeg,width=1280,height=720,framerate=30/1")
40 xrawcaps = Gst.Caps.from_string("video/x-raw,width=1280,height=720,framerate=30/1")
41
42 # Set up the pipeline
43 self.pipeline = Gst.Pipeline()
44
45 # Add elements
46
47 # src1
48 self.src1 = Gst.ElementFactory.make("v4l2src", "src1")
49 self.src1.set_property("device", "/dev/video0")
50 self.src1caps = Gst.ElementFactory.make("capsfilter", "src1caps")
51 self.src1caps.set_property("caps", jpegcaps)
52 self.src1dec = Gst.ElementFactory.make("decodebin", "src1dec")
53
54 # src2
55 self.src2 = Gst.ElementFactory.make("videotestsrc", "src2")
56 self.src2.set_property("pattern", "ball")
57 self.src2caps = Gst.ElementFactory.make("capsfilter", "src2caps")
58 self.src2caps.set_property("caps", xrawcaps)
59 self.src2dec = Gst.ElementFactory.make("decodebin", "src2dec")
60
61 # src3
62 self.src3 = Gst.ElementFactory.make("rtmpsrc", "src3")
63 self.src3.set_property("location", stream1)
64 # self.src3caps = Gst.ElementFactory.make("capsfilter", "src3caps")
65 # self.src3caps.set_property("caps", xrawcaps)
66 self.src3dec = Gst.ElementFactory.make("decodebin", "src3dec")
67 self.src3crop = Gst.ElementFactory.make("aspectratiocrop", "src3crop")
68 self.src3crop.set_property("aspect-ratio", Gst.Fraction(16, 9))
69 self.src3crop.set_property("async-handling", True)
70 self.src3croppad = self.src3crop.get_static_pad("sink")
71 self.src3scale = Gst.ElementFactory.make("videoscale")
72 self.src3scalecaps = Gst.ElementFactory.make("capsfilter", "src3scalecaps")
73 self.src3scalecaps.set_property("caps", Gst.Caps.from_string("width=1280,height=720"))
74
75 # Video mix
76 self.videomix = Gst.ElementFactory.make("videomixer", "videomix")
77 self.src1pad = self.videomix.get_request_pad("sink_1")
78 self.src1pad.set_property("zorder", 3)
79 self.src2pad = self.videomix.get_request_pad("sink_2")
80 self.src2pad.set_property("zorder", 2)
81 self.src3pad = self.videomix.get_request_pad("sink_3")
82 self.src3pad.set_property("zorder", 1)
83
84 # Add main videosink
85 self.videosink = Gst.ElementFactory.make("xvimagesink", "videosink")
86 self.videosink.set_property("sync", False)
87
88 # Add initial elements to the pipeline
89 self.pipeline.add(self.src1)
90 self.pipeline.add(self.src1caps)
91 self.pipeline.add(self.src1dec)
92 self.src1dec.connect("pad-added", self.OnPadAdded, self.src1pad, self.videomix)
93
94 self.pipeline.add(self.src2)
95 self.pipeline.add(self.src2caps)
96 self.pipeline.add(self.src2dec)
97 self.src2dec.connect("pad-added", self.OnPadAdded, self.src2pad, self.videomix)
98
99 self.pipeline.add(self.src3)
100 # self.pipeline.add(self.src3caps)
101 self.pipeline.add(self.src3dec)
102 self.src3dec.connect("pad-added", self.OnPadAdded, self.src3croppad, self.src3scale)
103 self.pipeline.add(self.src3scale)
104 self.pipeline.add(self.src3scalecaps)
105
106 self.pipeline.add(self.videomix)
107 self.pipeline.add(self.videosink)
108
109 # Link the initial pipeline
110 if not self.src1.link(self.src1caps):
111 print("Failed to link src1 to src1caps")
112 if not self.src1caps.link(self.src1dec):
113 print("Failed to link src1caps to src1dec")
114 if not self.videomix.link(self.videosink):
115 print("Failed to link videomix to videosink")
116
117 if not self.src2.link(self.src2caps):
118 print("Failed to link src2 to src2caps")
119 if not self.src2caps.link(self.src2dec):
120 print("Failed to link src2caps to src2dec")
121
122 # if not self.src3.link(self.src3caps):
123 # print("Failed to link src3 to src3caps")
124 if not self.src3.link(self.src3dec):
125 print("Failed to link src3 to src3dec")
126 if not self.src3scale.link(self.src3scalecaps):
127 print("Failed to link src3scale to src3scalecaps")
128 if not self.src3scalecaps.link(self.src3crop):
129 print("Failed to link src3scalecaps to src3crop")
130 if not self.src3crop.link(self.src3cropcaps):
131 print("Failed to link src3crop to src3cropcaps")
132 if not self.src3cropcaps.link(self.videomix):
133 print("Failed to link src3cropcaps to videomix")
134
135 # Set up a bus to our pipeline to get notified when the video is ready
136 self.bus = self.pipeline.get_bus()
137 self.bus.enable_sync_message_emission()
138 self.bus.connect("sync-message::element", self.OnSyncElement)
139
140 # Summon the window and connect the window's close button to quit
141 self.window = self.mainwindow.get_object("mainwindow")
142 self.window.connect("delete-event", Gtk.main_quit)
143 self.window.show_all()
144
145 # Get window ID of the viewport widget from the GUI
146 self.win_id = self.mainwindow.get_object("viewport_main").get_window().get_xid()
147
148 # Play!
149 print(self.pipeline.set_state(Gst.State.READY))
150 print(self.pipeline.set_state(Gst.State.PLAYING))
151 self.pipeline.get_state
152
153
154 # When we get a message that video is ready to display, set the
155 # correct window id to hook it to our viewport
156 def OnSyncElement(self, bus, message):
157 if message.get_structure().get_name() == "prepare-window-handle":
158 print("prepare-window-handle")
159 message.src.set_window_handle(self.win_id)
160
161 def OnPadAdded(self, element, pad, sink, target):
162 print("Dynamic pad for " + element.name + " added, linking to " + target.name)
163 pad.link(sink)
164 element.link(target)
165
166 def SetInput1(self, widget):
167 print("Switch to input 1")
168 self.src1pad.set_property("zorder", 3)
169 self.src2pad.set_property("zorder", 2)
170 self.src3pad.set_property("zorder", 1)
171
172 def SetInput2(self, widget):
173 print("Switch to input 2")
174 self.src1pad.set_property("zorder", 2)
175 self.src2pad.set_property("zorder", 3)
176 self.src3pad.set_property("zorder", 1)
177
178 def SetInput3(self, widget):
179 print("Switch to input 3")
180 self.src1pad.set_property("zorder", 1)
181 self.src2pad.set_property("zorder", 2)
182 self.src3pad.set_property("zorder", 3)
183
184 def SetInput4(self, widget):
185 print("Switch to input 4")
186
187 def SetInput5(self, widget):
188 print("Switch to input 5")
189
190 def SetInput6(self, widget):
191 print("Switch to input 6")
192
193 def OnQuit(self, widget):
194 print("quit")
195 Gtk.main_quit()
196
197 # Workaround to get Ctrl+C to terminate from command line
198 # ref: https://bugzilla.gnome.org/show_bug.cgi?id=622084#c12
199 signal.signal(signal.SIGINT, signal.SIG_DFL)
200
201 start = Main()
202 Gtk.main()