diff --git a/ChangeLog b/ChangeLog index 55e069d810..ce397273fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2007-12-18 Andy Wingo + + * examples/switch.py: New file, a basic demo for a single-stream + switcher. Could be expanded later -- look at + flumotion.component.combiners.switch.switch for some inspiration. + 2007-12-18 Tim-Philipp Müller * Makefile.am: diff --git a/common b/common index 67b8f4e3c5..970759077c 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 67b8f4e3c576945f4d778c9040876af3a5a0756e +Subproject commit 970759077c95ee4e85650db023ac6f974e2aa5e1 diff --git a/examples/switch.py b/examples/switch.py new file mode 100755 index 0000000000..af33cc6e66 --- /dev/null +++ b/examples/switch.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +import pygtk +pygtk.require('2.0') + +import sys + +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') +import gst +import gst.interfaces +import gtk + +class SwitchTest: + def __init__(self, videowidget): + self.playing = False + pipestr = ('videotestsrc pattern=0 ! queue ! s.sink0' + ' videotestsrc pattern=1 ! queue ! s.sink1' + ' switch name=s ! autovideosink') + self.pipeline = gst.parse_launch(pipestr) + self.videowidget = videowidget + + bus = self.pipeline.get_bus() + bus.enable_sync_message_emission() + bus.add_signal_watch() + bus.connect('sync-message::element', self.on_sync_message) + bus.connect('message', self.on_message) + + def on_sync_message(self, bus, message): + if message.structure is None: + return + if message.structure.get_name() == 'prepare-xwindow-id': + self.videowidget.set_sink(message.src) + message.src.set_property('force-aspect-ratio', True) + + def on_message(self, bus, message): + t = message.type + if t == gst.MESSAGE_ERROR: + err, debug = message.parse_error() + print "Error: %s" % err, debug + if self.on_eos: + self.on_eos() + self.playing = False + elif t == gst.MESSAGE_EOS: + if self.on_eos: + self.on_eos() + self.playing = False + + def play(self): + self.playing = True + gst.info("playing player") + self.pipeline.set_state(gst.STATE_PLAYING) + + def stop(self): + self.pipeline.set_state(gst.STATE_NULL) + gst.info("stopped player") + self.playing = False + + def get_state(self, timeout=1): + return self.pipeline.get_state(timeout=timeout) + + def is_playing(self): + return self.playing + + def switch(self, padname): + switch = self.pipeline.get_by_name('s') + stop_time = switch.emit('block') + newpad = switch.get_static_pad(padname) + start_time = newpad.get_property('running-time') + + gst.warning('stop time = %d' % (stop_time,)) + gst.warning('stop time = %s' % (gst.TIME_ARGS(stop_time),)) + + gst.warning('start time = %d' % (start_time,)) + gst.warning('start time = %s' % (gst.TIME_ARGS(start_time),)) + + gst.warning('switching from %r to %r' + % (switch.get_property('active-pad'), padname)) + switch.emit('switch', padname, stop_time, start_time) + +class VideoWidget(gtk.DrawingArea): + def __init__(self): + gtk.DrawingArea.__init__(self) + self.imagesink = None + self.unset_flags(gtk.DOUBLE_BUFFERED) + + def do_expose_event(self, event): + if self.imagesink: + self.imagesink.expose() + return False + else: + return True + + def set_sink(self, sink): + assert self.window.xid + self.imagesink = sink + self.imagesink.set_xwindow_id(self.window.xid) + +class SwitchWindow(gtk.Window): + UPDATE_INTERVAL = 500 + def __init__(self): + gtk.Window.__init__(self) + self.set_default_size(410, 325) + + self.create_ui() + self.player = SwitchTest(self.videowidget) + self.populate_combobox() + + self.update_id = -1 + self.changed_id = -1 + self.seek_timeout_id = -1 + + self.p_position = gst.CLOCK_TIME_NONE + self.p_duration = gst.CLOCK_TIME_NONE + + def on_delete_event(): + self.player.stop() + gtk.main_quit() + self.connect('delete-event', lambda *x: on_delete_event()) + + def load_file(self, location): + self.player.set_location(location) + + def play(self): + self.player.play() + + def populate_combobox(self): + switch = self.player.pipeline.get_by_name('s') + for i, pad in enumerate([p for p in switch.pads() + if p.get_direction() == gst.PAD_SINK]): + self.combobox.append_text(pad.get_name()) + if switch.get_property('active-pad') == pad.get_name(): + self.combobox.set_active(i) + if self.combobox.get_active() == -1: + self.combobox.set_active(0) + + def combobox_changed(self): + model = self.combobox.get_model() + row = model[self.combobox.get_active()] + padname, = row + self.player.switch(padname) + + def create_ui(self): + vbox = gtk.VBox() + self.add(vbox) + + self.videowidget = VideoWidget() + vbox.pack_start(self.videowidget) + + hbox = gtk.HBox() + vbox.pack_start(hbox, fill=False, expand=False) + + self.combobox = combobox = gtk.combo_box_new_text() + combobox.show() + hbox.pack_start(combobox) + + self.combobox.connect('changed', + lambda *x: self.combobox_changed()) + + self.videowidget.connect_after('realize', + lambda *x: self.play()) + +def main(args): + def usage(): + sys.stderr.write("usage: %s\n" % args[0]) + return 1 + + # Need to register our derived widget types for implicit event + # handlers to get called. + gobject.type_register(SwitchWindow) + gobject.type_register(VideoWidget) + + if len(args) != 1: + return usage() + + w = SwitchWindow() + w.show_all() + gtk.main() + return 0 + +if __name__ == '__main__': + sys.exit(main(sys.argv))