2 # Attempting to dynamically switch between input sources
4 # GdkX11 to get access to xid, GstVideo to get access to set_window_handle
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
14 # Create gui bits and bobs
16 self
.mainwindow
= Gtk
.Builder()
17 self
.mainwindow
.add_from_file("example5.glade")
20 "on_input1_clicked" : self
.SetInput1
,
21 "on_input2_clicked" : self
.SetInput2
,
22 "on_input3_clicked" : self
.SetInput3
,
23 "on_input4_clicked" : self
.SetInput4
,
24 "on_input5_clicked" : self
.SetInput5
,
25 "on_input6_clicked" : self
.SetInput6
,
26 "on_quit_clicked" : self
.OnQuit
,
29 self
.mainwindow
.connect_signals(signals
)
31 # Create GStreamer bits and bobs
36 # Some capabilities we want to share between different elements
37 jpegcaps
= Gst
.Caps
.from_string("image/jpeg,width=1280,height=720,framerate=30/1")
40 self
.pipeline
= Gst
.Pipeline()
45 self
.src1
= Gst
.ElementFactory
.make("v4l2src", "src1")
46 self
.src1
.set_property("device", "/dev/video1")
49 self
.src1caps
= Gst
.ElementFactory
.make("capsfilter", "src1caps")
50 self
.src1caps
.set_property("caps", jpegcaps
)
53 self
.src1jpegdec
= Gst
.ElementFactory
.make("jpegdec", "src1jpegdec")
56 self
.src1videoconvert
= Gst
.ElementFactory
.make("videoconvert", "src1videoconvert")
59 self
.src2
= Gst
.ElementFactory
.make("v4l2src", "src2")
60 self
.src2
.set_property("device", "/dev/video0")
63 self
.src2caps
= Gst
.ElementFactory
.make("capsfilter", "src2caps")
64 self
.src2caps
.set_property("caps", jpegcaps
)
67 self
.src2jpegdec
= Gst
.ElementFactory
.make("jpegdec", "src2jpegdec")
70 self
.src2videoconvert
= Gst
.ElementFactory
.make("videoconvert", "src2videoconvert")
73 self
.videomix
= Gst
.ElementFactory
.make("videomixer", "videomix")
74 self
.src1pad
= self
.videomix
.get_request_pad("sink_1")
75 self
.src1pad
.set_property("zorder", 2)
76 self
.src2pad
= self
.videomix
.get_request_pad("sink_2")
77 self
.src2pad
.set_property("zorder", 1)
80 self
.videosink
= Gst
.ElementFactory
.make("autovideosink", "videosink")
81 self
.videosink
.set_property("sync", False)
83 # Add initial elements to the pipeline
84 self
.pipeline
.add(self
.src1
)
85 self
.pipeline
.add(self
.src1caps
)
86 self
.pipeline
.add(self
.src1jpegdec
)
87 self
.pipeline
.add(self
.src1videoconvert
)
89 self
.pipeline
.add(self
.src2
)
90 self
.pipeline
.add(self
.src2caps
)
91 self
.pipeline
.add(self
.src2jpegdec
)
92 self
.pipeline
.add(self
.src2videoconvert
)
94 self
.pipeline
.add(self
.videomix
)
95 self
.pipeline
.add(self
.videosink
)
97 # Link the initial pipeline
98 self
.src1
.link(self
.src1caps
)
99 self
.src1caps
.link(self
.src1jpegdec
)
100 self
.src1jpegdec
.link(self
.src1videoconvert
)
101 self
.src1videoconvert
.link(self
.videomix
)
103 self
.src2
.link(self
.src2caps
)
104 self
.src2caps
.link(self
.src2jpegdec
)
105 self
.src2jpegdec
.link(self
.src2videoconvert
)
106 self
.src2videoconvert
.link(self
.videomix
)
108 self
.videomix
.link(self
.videosink
)
110 # Set up a bus to our pipeline to get notified when the video is ready
111 self
.bus
= self
.pipeline
.get_bus()
112 self
.bus
.enable_sync_message_emission()
113 self
.bus
.connect("sync-message::element", self
.OnSyncElement
)
115 # Summon the window and connect the window's close button to quit
116 self
.window
= self
.mainwindow
.get_object("mainwindow")
117 self
.window
.connect("delete-event", Gtk
.main_quit
)
118 self
.window
.show_all()
120 # Get window ID of the viewport widget from the GUI
121 self
.win_id
= self
.mainwindow
.get_object("viewport_main").get_window().get_xid()
124 self
.pipeline
.set_state(Gst
.State
.PLAYING
)
127 # When we get a message that video is ready to display, set the
128 # correct window id to hook it to our viewport
129 def OnSyncElement(self
, bus
, message
):
130 if message
.get_structure().get_name() == "prepare-window-handle":
131 print("prepare-window-handle")
132 message
.src
.set_window_handle(self
.win_id
)
134 def SetInput1(self
, widget
):
135 print("Switch to input 1")
136 self
.src1pad
.set_property("zorder", 2)
137 self
.src2pad
.set_property("zorder", 1)
139 def SetInput2(self
, widget
):
140 print("Switch to input 2")
141 self
.src1pad
.set_property("zorder", 1)
142 self
.src2pad
.set_property("zorder", 2)
144 def SetInput3(self
, widget
):
145 print("Switch to input 3")
147 def SetInput4(self
, widget
):
148 print("Switch to input 4")
150 def SetInput5(self
, widget
):
151 print("Switch to input 5")
153 def SetInput6(self
, widget
):
154 print("Switch to input 6")
156 def OnQuit(self
, widget
):
160 # Workaround to get Ctrl+C to terminate from command line
161 # ref: https://bugzilla.gnome.org/show_bug.cgi?id=622084#c12
162 signal
.signal(signal
.SIGINT
, signal
.SIG_DFL
)