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