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("example4.glade")
20 "on_input1_clicked" : self
.SetInput1
,
21 "on_input2_clicked" : self
.SetInput2
,
22 "on_quit_clicked" : self
.OnQuit
,
25 self
.mainwindow
.connect_signals(signals
)
27 # Create GStreamer bits and bobs
32 # Some capabilities we want to share between different elements
33 commoncaps
= Gst
.Caps
.from_string("video/x-raw,width=1280,height=720,framerate=30/1")
36 self
.pipeline
= Gst
.Pipeline()
38 # Add a videotestsrc element, set it to pattern "ball" and some other properties
39 self
.ball
= Gst
.ElementFactory
.make("videotestsrc", "ball")
40 self
.ball
.set_property("pattern", "ball")
41 self
.ball
.set_property("flip", True)
43 # Add a capsfilter that we want to apply to our ball
44 self
.ballcaps
= Gst
.ElementFactory
.make("capsfilter", "ballcaps")
45 self
.ballcaps
.set_property("caps", commoncaps
)
48 self
.webcam
= Gst
.ElementFactory
.make("v4l2src", "webcam")
49 self
.webcam
.set_property("device", "/dev/video0")
52 self
.webcamcaps
= Gst
.ElementFactory
.make("capsfilter", "webcamcaps")
53 self
.webcamcaps
.set_property("caps", commoncaps
)
55 # Add a videosink (where the playback happens)
56 self
.videosink
= Gst
.ElementFactory
.make("autovideosink", "videosink")
57 self
.videosink
.set_property("sync", False)
59 # Add initial elements to the pipeline
60 self
.pipeline
.add(self
.ball
)
61 self
.pipeline
.add(self
.ballcaps
)
62 self
.pipeline
.add(self
.videosink
)
64 # Link the initial pipeline
65 self
.ball
.link(self
.ballcaps
)
66 self
.ballcaps
.link(self
.videosink
)
68 # Set up a bus to our pipeline to get notified when the video is ready
69 self
.bus
= self
.pipeline
.get_bus()
70 self
.bus
.enable_sync_message_emission()
71 self
.bus
.connect("sync-message::element", self
.OnSyncElement
)
73 # Summon the window and connect the window's close button to quit
74 self
.window
= self
.mainwindow
.get_object("mainwindow")
75 self
.window
.connect("delete-event", Gtk
.main_quit
)
76 self
.window
.show_all()
78 # Get window ID of the viewport widget from the GUI
79 self
.win_id
= self
.mainwindow
.get_object("viewport").get_window().get_xid()
82 self
.pipeline
.set_state(Gst
.State
.PLAYING
)
85 # When we get a message that video is ready to display, set the
86 # correct window id to hook it to our viewport
87 def OnSyncElement(self
, bus
, message
):
88 if message
.get_structure().get_name() == "prepare-window-handle":
89 print("prepare-window-handle")
90 message
.src
.set_window_handle(self
.win_id
)
92 def SetInput1(self
, widget
):
93 print("Switch to input 1")
94 # Halt current pipeline and tear it down
95 self
.pipeline
.set_state(Gst
.State
.READY
)
96 self
.webcamcaps
.unlink(self
.videosink
)
97 self
.pipeline
.remove(self
.webcam
)
98 self
.pipeline
.remove(self
.webcamcaps
)
99 # Construct new pipeline
100 self
.pipeline
.add(self
.ball
)
101 self
.pipeline
.add(self
.ballcaps
)
102 self
.ball
.link(self
.ballcaps
)
103 self
.ballcaps
.link(self
.videosink
)
104 self
.pipeline
.set_state(Gst
.State
.PLAYING
)
106 def SetInput2(self
, widget
):
107 print("Switch to input 2")
108 # Halt current pipeline and tear it down
109 self
.pipeline
.set_state(Gst
.State
.READY
)
110 self
.ballcaps
.unlink(self
.videosink
)
111 self
.pipeline
.remove(self
.ball
)
112 self
.pipeline
.remove(self
.ballcaps
)
113 # Construct new pipeline
114 self
.pipeline
.add(self
.webcam
)
115 self
.pipeline
.add(self
.webcamcaps
)
116 self
.webcam
.link(self
.webcamcaps
)
117 self
.webcamcaps
.link(self
.videosink
)
118 self
.pipeline
.set_state(Gst
.State
.PLAYING
)
120 def OnQuit(self
, widget
):
124 # Workaround to get Ctrl+C to terminate from command line
125 # ref: https://bugzilla.gnome.org/show_bug.cgi?id=622084#c12
126 signal
.signal(signal
.SIGINT
, signal
.SIG_DFL
)