| import gobject | |
| gobject.threads_init() | |
| import gtk | |
| gtk.gdk.threads_init() | |
| import hildon | |
| import gst | |
| import sys | |
| # VideoWidget taken from play.py in gst-python examples | |
| 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 MaemoGstView: | |
| def __init__(self): | |
| # hildon has one program instance per app, so get instance | |
| self.p = hildon.Program.get_instance() | |
| # set name of application: this shows in titlebar | |
| gtk.set_application_name("Maemo GStreamer VideoTest") | |
| # stackable window in case we want more windows in future in app | |
| self.w = hildon.StackableWindow() | |
| box = gtk.VBox() | |
| self.video_widget = VideoWidget() | |
| # video widget we want to expand to size | |
| box.pack_start(self.video_widget, True, True, 0) | |
| # a button finger height to play/pause | |
| self.button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, | |
| hildon.BUTTON_ARRANGEMENT_VERTICAL, title="Pause") | |
| self.button.connect_after("clicked", self.on_button_clicked) | |
| # don't want button to expand or fill, just stay finger height | |
| box.pack_start(self.button, False, False, 0) | |
| self.w.add(box) | |
| self.w.connect("delete-event", gtk.main_quit) | |
| self.p.add_window(self.w) | |
| self.w.show_all() | |
| self.start_streaming() | |
| def start_streaming(self): | |
| # we use ximagesink solely for screenshotting ability | |
| # less cpu usage would happen with videotestsrc ! xvimagesink | |
| self.pipeline = \ | |
| gst.parse_launch("videotestsrc ! videoscale ! ximagesink") | |
| bus = self.pipeline.get_bus() | |
| # need to connect to sync message handler so we get the sink to be | |
| # embedded at the right time and not have a temporary new window | |
| bus.enable_sync_message_emission() | |
| bus.add_signal_watch() | |
| bus.connect("sync-message::element", self.on_sync_message) | |
| bus.connect("message", self.on_message) | |
| self.pipeline.set_state(gst.STATE_PLAYING) | |
| def on_sync_message(self, bus, message): | |
| if message.structure is None: | |
| return | |
| if message.structure.get_name() == 'prepare-xwindow-id': | |
| # all this is needed to sync with the X server before giving the | |
| # x id to the sink | |
| gtk.gdk.threads_enter() | |
| gtk.gdk.display_get_default().sync() | |
| self.video_widget.set_sink(message.src) | |
| message.src.set_property("force-aspect-ratio", True) | |
| gtk.gdk.threads_leave() | |
| def on_message(self, bus, message): | |
| if message.type == gst.MESSAGE_ERROR: | |
| err, debug = message.parse_error() | |
| hildon.hildon_banner_show_information(self.w, '', | |
| "Error: %s" % err) | |
| def on_button_clicked(self, widget): | |
| success, state, pending = self.pipeline.get_state(1) | |
| # do not listen if in middle of state change | |
| if not pending: | |
| if state == gst.STATE_PLAYING: | |
| self.pipeline.set_state(gst.STATE_PAUSED) | |
| self.button.set_label("Play") | |
| else: | |
| self.pipeline.set_state(gst.STATE_PLAYING) | |
| self.button.set_label("Pause") | |
| def main(): | |
| view = MaemoGstView() | |
| gtk.main() | |
| if __name__ == '__main__': | |
| sys.exit(main()) |