3 # vi:si:et:sw=4:sts=4:ts=4
11 gobject.threads_init()
18 gtk.gdk.threads_init()
21 def __init__(self, videowidget):
23 pipestr = ('videotestsrc pattern=0 ! queue ! s.sink0'
24 ' videotestsrc pattern=1 ! queue ! s.sink1'
25 ' input-selector name=s ! autovideosink')
26 self.pipeline = gst.parse_launch(pipestr)
27 self.videowidget = videowidget
29 bus = self.pipeline.get_bus()
30 bus.enable_sync_message_emission()
31 bus.add_signal_watch()
32 bus.connect('sync-message::element', self.on_sync_message)
33 bus.connect('message', self.on_message)
35 def on_sync_message(self, bus, message):
36 if message.structure is None:
38 if message.structure.get_name() == 'prepare-xwindow-id':
39 # Sync with the X server before giving the X-id to the sink
40 gtk.gdk.threads_enter()
41 gtk.gdk.display_get_default().sync()
42 self.videowidget.set_sink(message.src)
43 message.src.set_property('force-aspect-ratio', True)
44 gtk.gdk.threads_leave()
46 def on_message(self, bus, message):
48 if t == gst.MESSAGE_ERROR:
49 err, debug = message.parse_error()
50 print "Error: %s" % err, debug
54 elif t == gst.MESSAGE_EOS:
61 gst.info("playing player")
62 self.pipeline.set_state(gst.STATE_PLAYING)
65 self.pipeline.set_state(gst.STATE_NULL)
66 gst.info("stopped player")
69 def get_state(self, timeout=1):
70 return self.pipeline.get_state(timeout=timeout)
75 def switch(self, padname):
76 switch = self.pipeline.get_by_name('s')
77 stop_time = switch.emit('block')
78 newpad = switch.get_static_pad(padname)
79 start_time = newpad.get_property('running-time')
81 gst.warning('stop time = %d' % (stop_time,))
82 gst.warning('stop time = %s' % (gst.TIME_ARGS(stop_time),))
84 gst.warning('start time = %d' % (start_time,))
85 gst.warning('start time = %s' % (gst.TIME_ARGS(start_time),))
87 gst.warning('switching from %r to %r'
88 % (switch.get_property('active-pad'), padname))
89 switch.emit('switch', newpad, stop_time, start_time)
91 class VideoWidget(gtk.DrawingArea):
93 gtk.DrawingArea.__init__(self)
95 self.unset_flags(gtk.DOUBLE_BUFFERED)
97 def do_expose_event(self, event):
99 self.imagesink.expose()
104 def set_sink(self, sink):
105 assert self.window.xid
106 self.imagesink = sink
107 self.imagesink.set_xwindow_id(self.window.xid)
109 class SwitchWindow(gtk.Window):
110 UPDATE_INTERVAL = 500
112 gtk.Window.__init__(self)
113 self.set_default_size(410, 325)
116 self.player = SwitchTest(self.videowidget)
117 self.populate_combobox()
121 self.seek_timeout_id = -1
123 self.p_position = gst.CLOCK_TIME_NONE
124 self.p_duration = gst.CLOCK_TIME_NONE
126 def on_delete_event():
129 self.connect('delete-event', lambda *x: on_delete_event())
131 def load_file(self, location):
132 self.player.set_location(location)
137 def populate_combobox(self):
138 switch = self.player.pipeline.get_by_name('s')
139 for i, pad in enumerate([p for p in switch.pads()
140 if p.get_direction() == gst.PAD_SINK]):
141 self.combobox.append_text(pad.get_name())
142 if switch.get_property('active-pad') == pad.get_name():
143 self.combobox.set_active(i)
144 if self.combobox.get_active() == -1:
145 self.combobox.set_active(0)
147 def combobox_changed(self):
148 model = self.combobox.get_model()
149 row = model[self.combobox.get_active()]
151 self.player.switch(padname)
157 self.videowidget = VideoWidget()
158 vbox.pack_start(self.videowidget)
161 vbox.pack_start(hbox, fill=False, expand=False)
163 self.combobox = combobox = gtk.combo_box_new_text()
165 hbox.pack_start(combobox)
167 self.combobox.connect('changed',
168 lambda *x: self.combobox_changed())
170 self.videowidget.connect_after('realize',
171 lambda *x: self.play())
175 sys.stderr.write("usage: %s\n" % args[0])
178 # Need to register our derived widget types for implicit event
179 # handlers to get called.
180 gobject.type_register(SwitchWindow)
181 gobject.type_register(VideoWidget)
191 if __name__ == '__main__':
192 sys.exit(main(sys.argv))