home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / share / doc / python-gst0.10 / examples / play.py < prev    next >
Encoding:
Python Source  |  2006-07-31  |  8.8 KB  |  289 lines

  1. #!/usr/bin/env python
  2. # -*- Mode: Python -*-
  3. # vi:si:et:sw=4:sts=4:ts=4
  4.  
  5. import pygtk
  6. pygtk.require('2.0')
  7.  
  8. import sys
  9.  
  10. import gobject
  11.  
  12. import pygst
  13. pygst.require('0.10')
  14. import gst
  15. import gst.interfaces
  16. import gtk
  17.  
  18. class GstPlayer:
  19.     def __init__(self, videowidget):
  20.         self.playing = False
  21.         self.player = gst.element_factory_make("playbin", "player")
  22.         self.videowidget = videowidget
  23.         self.on_eos = False
  24.  
  25.         bus = self.player.get_bus()
  26.         bus.enable_sync_message_emission()
  27.         bus.add_signal_watch()
  28.         bus.connect('sync-message::element', self.on_sync_message)
  29.         bus.connect('message', self.on_message)
  30.  
  31.     def on_sync_message(self, bus, message):
  32.         if message.structure is None:
  33.             return
  34.         if message.structure.get_name() == 'prepare-xwindow-id':
  35.             self.videowidget.set_sink(message.src)
  36.             message.src.set_property('force-aspect-ratio', True)
  37.             
  38.     def on_message(self, bus, message):
  39.         t = message.type
  40.         if t == gst.MESSAGE_ERROR:
  41.             err, debug = message.parse_error()
  42.             print "Error: %s" % err, debug
  43.             if self.on_eos:
  44.                 self.on_eos()
  45.             self.playing = False
  46.         elif t == gst.MESSAGE_EOS:
  47.             if self.on_eos:
  48.                 self.on_eos()
  49.             self.playing = False
  50.  
  51.     def set_location(self, location):
  52.         self.player.set_property('uri', location)
  53.  
  54.     def query_position(self):
  55.         "Returns a (position, duration) tuple"
  56.         try:
  57.             position, format = self.player.query_position(gst.FORMAT_TIME)
  58.         except:
  59.             position = gst.CLOCK_TIME_NONE
  60.  
  61.         try:
  62.             duration, format = self.player.query_duration(gst.FORMAT_TIME)
  63.         except:
  64.             duration = gst.CLOCK_TIME_NONE
  65.  
  66.         return (position, duration)
  67.  
  68.     def seek(self, location):
  69.         """
  70.         @param location: time to seek to, in nanoseconds
  71.         """
  72.         gst.debug("seeking to %r" % location)
  73.         event = gst.event_new_seek(1.0, gst.FORMAT_TIME,
  74.             gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE,
  75.             gst.SEEK_TYPE_SET, location,
  76.             gst.SEEK_TYPE_NONE, 0)
  77.  
  78.         res = self.player.send_event(event)
  79.         if res:
  80.             gst.info("setting new stream time to 0")
  81.             self.player.set_new_stream_time(0L)
  82.         else:
  83.             gst.error("seek to %r failed" % location)
  84.  
  85.     def pause(self):
  86.         gst.info("pausing player")
  87.         self.player.set_state(gst.STATE_PAUSED)
  88.         self.playing = False
  89.  
  90.     def play(self):
  91.         gst.info("playing player")
  92.         self.player.set_state(gst.STATE_PLAYING)
  93.         self.playing = True
  94.         
  95.     def stop(self):
  96.         self.player.set_state(gst.STATE_NULL)
  97.         gst.info("stopped player")
  98.  
  99.     def get_state(self, timeout=1):
  100.         return self.player.get_state(timeout=timeout)
  101.  
  102.     def is_playing(self):
  103.         return self.playing
  104.     
  105. class VideoWidget(gtk.DrawingArea):
  106.     def __init__(self):
  107.         gtk.DrawingArea.__init__(self)
  108.         self.imagesink = None
  109.         self.unset_flags(gtk.DOUBLE_BUFFERED)
  110.  
  111.     def do_expose_event(self, event):
  112.         if self.imagesink:
  113.             self.imagesink.expose()
  114.             return False
  115.         else:
  116.             return True
  117.  
  118.     def set_sink(self, sink):
  119.         assert self.window.xid
  120.         self.imagesink = sink
  121.         self.imagesink.set_xwindow_id(self.window.xid)
  122.  
  123. class PlayerWindow(gtk.Window):
  124.     UPDATE_INTERVAL = 500
  125.     def __init__(self):
  126.         gtk.Window.__init__(self)
  127.         self.set_default_size(410, 325)
  128.  
  129.         self.create_ui()
  130.  
  131.         self.player = GstPlayer(self.videowidget)
  132.  
  133.         def on_eos():
  134.             self.player.seek(0L)
  135.             self.play_toggled()
  136.         self.player.on_eos = lambda *x: on_eos()
  137.         
  138.         self.update_id = -1
  139.         self.changed_id = -1
  140.         self.seek_timeout_id = -1
  141.  
  142.         self.p_position = gst.CLOCK_TIME_NONE
  143.         self.p_duration = gst.CLOCK_TIME_NONE
  144.  
  145.         def on_delete_event():
  146.             self.player.stop()
  147.             gtk.main_quit()
  148.         self.connect('delete-event', lambda *x: on_delete_event())
  149.  
  150.     def load_file(self, location):
  151.         self.player.set_location(location)
  152.                                   
  153.     def create_ui(self):
  154.         vbox = gtk.VBox()
  155.         self.add(vbox)
  156.  
  157.         self.videowidget = VideoWidget()
  158.         vbox.pack_start(self.videowidget)
  159.         
  160.         hbox = gtk.HBox()
  161.         vbox.pack_start(hbox, fill=False, expand=False)
  162.         
  163.         self.pause_image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE,
  164.                                                     gtk.ICON_SIZE_BUTTON)
  165.         self.pause_image.show()
  166.         self.play_image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PLAY,
  167.                                                    gtk.ICON_SIZE_BUTTON)
  168.         self.play_image.show()
  169.         self.button = button = gtk.Button()
  170.         button.add(self.play_image)
  171.         button.set_property('can-default', True)
  172.         button.set_focus_on_click(False)
  173.         button.show()
  174.         hbox.pack_start(button, False)
  175.         button.set_property('has-default', True)
  176.         button.connect('clicked', lambda *args: self.play_toggled())
  177.         
  178.         self.adjustment = gtk.Adjustment(0.0, 0.00, 100.0, 0.1, 1.0, 1.0)
  179.         hscale = gtk.HScale(self.adjustment)
  180.         hscale.set_digits(2)
  181.         hscale.set_update_policy(gtk.UPDATE_CONTINUOUS)
  182.         hscale.connect('button-press-event', self.scale_button_press_cb)
  183.         hscale.connect('button-release-event', self.scale_button_release_cb)
  184.         hscale.connect('format-value', self.scale_format_value_cb)
  185.         hbox.pack_start(hscale)
  186.         self.hscale = hscale
  187.  
  188.         self.videowidget.connect_after('realize',
  189.                                        lambda *x: self.play_toggled())
  190.  
  191.     def play_toggled(self):
  192.         self.button.remove(self.button.child)
  193.         if self.player.is_playing():
  194.             self.player.pause()
  195.             self.button.add(self.play_image)
  196.         else:
  197.             self.player.play()
  198.             if self.update_id == -1:
  199.                 self.update_id = gobject.timeout_add(self.UPDATE_INTERVAL,
  200.                                                      self.update_scale_cb)
  201.             self.button.add(self.pause_image)
  202.  
  203.     def scale_format_value_cb(self, scale, value):
  204.         if self.p_duration == -1:
  205.             real = 0
  206.         else:
  207.             real = value * self.p_duration / 100
  208.         
  209.         seconds = real / gst.SECOND
  210.  
  211.         return "%02d:%02d" % (seconds / 60, seconds % 60)
  212.  
  213.     def scale_button_press_cb(self, widget, event):
  214.         # see seek.c:start_seek
  215.         gst.debug('starting seek')
  216.         
  217.         self.button.set_sensitive(False)
  218.         self.was_playing = self.player.is_playing()
  219.         if self.was_playing:
  220.             self.player.pause()
  221.  
  222.         # don't timeout-update position during seek
  223.         if self.update_id != -1:
  224.             gobject.source_remove(self.update_id)
  225.             self.update_id = -1
  226.  
  227.         # make sure we get changed notifies
  228.         if self.changed_id == -1:
  229.             self.changed_id = self.hscale.connect('value-changed',
  230.                 self.scale_value_changed_cb)
  231.             
  232.     def scale_value_changed_cb(self, scale):
  233.         # see seek.c:seek_cb
  234.         real = long(scale.get_value() * self.p_duration / 100) # in ns
  235.         gst.debug('value changed, perform seek to %r' % real)
  236.         self.player.seek(real)
  237.         # allow for a preroll
  238.         self.player.get_state(timeout=50*gst.MSECOND) # 50 ms
  239.  
  240.     def scale_button_release_cb(self, widget, event):
  241.         # see seek.cstop_seek
  242.         widget.disconnect(self.changed_id)
  243.         self.changed_id = -1
  244.  
  245.         self.button.set_sensitive(True)
  246.         if self.seek_timeout_id != -1:
  247.             gobject.source_remove(self.seek_timeout_id)
  248.             self.seek_timeout_id = -1
  249.         else:
  250.             gst.debug('released slider, setting back to playing')
  251.             if self.was_playing:
  252.                 self.player.play()
  253.  
  254.         if self.update_id != -1:
  255.             self.error('Had a previous update timeout id')
  256.         else:
  257.             self.update_id = gobject.timeout_add(self.UPDATE_INTERVAL,
  258.                 self.update_scale_cb)
  259.  
  260.     def update_scale_cb(self):
  261.         self.p_position, self.p_duration = self.player.query_position()
  262.         if self.p_position != gst.CLOCK_TIME_NONE:
  263.             value = self.p_position * 100.0 / self.p_duration
  264.             self.adjustment.set_value(value)
  265.  
  266.         return True
  267.  
  268. def main(args):
  269.     def usage():
  270.         sys.stderr.write("usage: %s URI-OF-MEDIA-FILE\n" % args[0])
  271.         sys.exit(1)
  272.  
  273.     w = PlayerWindow()
  274.  
  275.     if len(args) != 2:
  276.         usage()
  277.  
  278.     if not gst.uri_is_valid(args[1]):
  279.         sys.stderr.write("Error: Invalid URI: %s\n" % args[1])
  280.         sys.exit(1)
  281.  
  282.     w.load_file(args[1])
  283.     w.show_all()
  284.  
  285.     gtk.main()
  286.  
  287. if __name__ == '__main__':
  288.     sys.exit(main(sys.argv))
  289.