[xiph-commits] r15050 - trunk/subtle
jmesquita at svn.xiph.org
jmesquita at svn.xiph.org
Fri Jun 20 15:24:28 PDT 2008
Author: jmesquita
Date: 2008-06-20 15:24:28 -0700 (Fri, 20 Jun 2008)
New Revision: 15050
Modified:
trunk/subtle/GPlayer.py
trunk/subtle/Subtle.py
Log:
We now count frames correctly and on the right place. Frame counting is done on GPlayer.py. We are ready now to support frame based timing subtitles.
Modified: trunk/subtle/GPlayer.py
===================================================================
--- trunk/subtle/GPlayer.py 2008-06-19 06:30:46 UTC (rev 15049)
+++ trunk/subtle/GPlayer.py 2008-06-20 22:24:28 UTC (rev 15050)
@@ -32,181 +32,180 @@
## GstPlayer class.
# Class for playing media in GStreamer.
class GstPlayer:
- ## Construstor
- # \param videowidget - VideoWidget class.
- def __init__(self, videowidget):
- self.playing = False
- bin = gst.Bin('my-bin')
- self.textoverlay = gst.element_factory_make('textoverlay')
- bin.add(self.textoverlay)
- pad = self.textoverlay.get_pad("video_sink")
- ghostpad = gst.GhostPad("sink", pad)
- bin.add_pad(ghostpad)
- color = gst.element_factory_make('ffmpegcolorspace')
- bin.add(color)
- scale = gst.element_factory_make('videoscale')
- bin.add(scale)
- videosink = gst.element_factory_make('autovideosink')
- bin.add(videosink)
- gst.element_link_many(self.textoverlay, color, scale, videosink)
- self.player = gst.element_factory_make("playbin", "player")
- self.player.set_property("video-sink", bin)
- self.videowidget = videowidget
+ ## Construstor
+ # \param videowidget - VideoWidget class.
+ def __init__(self, videowidget):
+ self.playing = False
+ bin = gst.Bin('my-bin')
+ self.textoverlay = gst.element_factory_make('textoverlay')
+ bin.add(self.textoverlay)
+ pad = self.textoverlay.get_pad("video_sink")
+ ghostpad = gst.GhostPad("sink", pad)
+ bin.add_pad(ghostpad)
+ color = gst.element_factory_make('ffmpegcolorspace')
+ bin.add(color)
+ scale = gst.element_factory_make('videoscale')
+ bin.add(scale)
+ self.videosink = gst.element_factory_make('autovideosink')
+ bin.add(self.videosink)
+ gst.element_link_many(self.textoverlay, color, scale, self.videosink)
+ self.player = gst.element_factory_make("playbin", "player")
+ self.player.set_property("video-sink", bin)
+ self.videowidget = videowidget
- bus = self.player.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)
-
+ bus = self.player.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)
+ self.cur_frame = 0
+
+ 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)
- ## \var playing
- # Bool variable, TRUE - if media is playing.
-
- ## \var player
- # GStreamer playerbin element.
-
- ## \var videowidget
- # GTK+ widget for video render.
-
-#==============================================================================
- 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
+ self.playing = False
+ elif t == gst.MESSAGE_EOS:
+ self.playing = False
-#==============================================================================
- def on_message(self, bus, message):
- t = message.type
- if t == gst.MESSAGE_ERROR:
- err, debug = message.parse_error()
- print "Error: %s" % err, debug
- self.playing = False
- elif t == gst.MESSAGE_EOS:
- self.playing = False
+ ## Set location.
+ # Set location of the source.
+ # \param location - URI of the source.
+ def set_location(self, location):
+ self.player.set_state(gst.STATE_NULL)
+ self.player.set_property('uri', location)
-#==============================================================================
- ## Set location.
- # Set location of the source.
- # \param location - URI of the source.
- def set_location(self, location):
- self.player.set_state(gst.STATE_NULL)
- self.player.set_property('uri', location)
+ ## Set Subtitle Text
+ # Set subtitle text to be overlayed.
+ # \param text - Text (may have pango tags)
+ # \param font - Pango FontDescrition for the text
+ def set_subtitle_text(self, text, font=None):
+ if font:
+ self.textoverlay.set_property('subtitle-font-desc', font)
+ self.textoverlay.set_property('text', text)
-#==============================================================================
- ## Set Subtitle Text
- # Set subtitle text to be overlayed.
- # \param text - Text (may have pango tags)
- # \param font - Pango FontDescrition for the text
- def set_subtitle_text(self, text, font=None):
- if font:
- self.textoverlay.set_property('subtitle-font-desc', font)
- self.textoverlay.set_property('text', text)
+ ## Get location.
+ # Get location of the source.
+ def get_location(self):
+ return self.player.get_property('uri')
-#==============================================================================
- ## Get location.
- # Get location of the source.
- def get_location(self):
- return self.player.get_property('uri')
+ def query_position(self):
+ "Returns a (position, duration) tuple"
+ try:
+ position, format = self.player.query_position(gst.FORMAT_TIME)
+ except:
+ position = gst.CLOCK_TIME_NONE
-#==============================================================================
- def query_position(self):
- "Returns a (position, duration) tuple"
- try:
- position, format = self.player.query_position(gst.FORMAT_TIME)
- except:
- position = gst.CLOCK_TIME_NONE
+ try:
+ duration, format = self.player.query_duration(gst.FORMAT_TIME)
+ except:
+ duration = gst.CLOCK_TIME_NONE
- try:
- duration, format = self.player.query_duration(gst.FORMAT_TIME)
- except:
- duration = gst.CLOCK_TIME_NONE
+ return (position, duration)
+
+ def query_frame(self, position):
+ "Query the frame position"
+ if position != gst.CLOCK_TIME_NONE:
+ pad = self.videosink.get_pad('sink')
+ caps = pad.get_negotiated_caps()
+ if caps is not None:
+ framerate = caps[0]['framerate']
+ position = position/1000000000
+ self.cur_frame = (float(position)*float(framerate.num))/float(framerate.denom)
+ return self.cur_frame
- return (position, duration)
+ ## Seek.
+ # Seek media.
+ # \param location - location to the seek.
+ def seek(self, location):
+ gst.debug("seeking to %r" % location)
+ event = gst.event_new_seek(1.0, gst.FORMAT_TIME,
+ gst.SEEK_FLAG_FLUSH,
+ gst.SEEK_TYPE_SET, location,
+ gst.SEEK_TYPE_NONE, 0)
-#==============================================================================
- ## Seek.
- # Seek media.
- # \param location - location to the seek.
- def seek(self, location):
- gst.debug("seeking to %r" % location)
- event = gst.event_new_seek(1.0, gst.FORMAT_TIME,
- gst.SEEK_FLAG_FLUSH,
- gst.SEEK_TYPE_SET, location,
- gst.SEEK_TYPE_NONE, 0)
+ res = self.player.send_event(event)
+ if res:
+ gst.info("setting new stream time to 0")
+ self.player.set_new_stream_time(0L)
+ else:
+ gst.error("seek to %r failed" % location)
- res = self.player.send_event(event)
- if res:
- gst.info("setting new stream time to 0")
- self.player.set_new_stream_time(0L)
- else:
- gst.error("seek to %r failed" % location)
+ ## Pause.
+ # Media pause.
+ def pause(self):
+ gst.info("pausing player")
+ self.player.set_state(gst.STATE_PAUSED)
+ self.playing = False
-#==============================================================================
- ## Pause.
- # Media pause.
- def pause(self):
- gst.info("pausing player")
- self.player.set_state(gst.STATE_PAUSED)
- self.playing = False
+ ## Play.
+ # Media play.
+ def play(self):
+ gst.info("playing player")
+ self.player.set_state(gst.STATE_PLAYING)
+ self.playing = True
-#==============================================================================
- ## Play.
- # Media play.
- def play(self):
- gst.info("playing player")
- self.player.set_state(gst.STATE_PLAYING)
- self.playing = True
+ ## Stop
+ # Media stop.
+ def stop(self):
+ self.player.set_state(gst.STATE_NULL)
+ self.playing = False
+ gst.info("stopped player")
-#==============================================================================
- ## Stop
- # Media stop.
- def stop(self):
- self.player.set_state(gst.STATE_NULL)
- self.playing = False
- gst.info("stopped player")
+ ## Get state.
+ # Get current state of the media.
+ # \param timeout - time out of the operation.
+ # \raturn state of the media.
+ def get_state(self, timeout=1):
+ return self.player.get_state(timeout=timeout)
-#==============================================================================
- ## Get state.
- # Get current state of the media.
- # \param timeout - time out of the operation.
- # \raturn state of the media.
- def get_state(self, timeout=1):
- return self.player.get_state(timeout=timeout)
+ ## Is playing
+ # \return TRUE if media is playing.
+ def is_playing(self):
+ return self.playing
-#==============================================================================
- ## Is playing
- # \return TRUE if media is playing.
- def is_playing(self):
- return self.playing
+ ## \var playing
+ # Bool variable, TRUE - if media is playing.
+ ## \var player
+ # GStreamer playerbin element.
+
+ ## \var videowidget
+ # GTK+ widget for video render.
+
#==============================================================================
## VideoWidget class.
# VideoWidget class for render video stream on GTK+ widget.
class VideoWidget:
- ## Constructor.
- # \param TArea - GTK+ drowing area widget.
- def __init__(self, TArea):
- self.Area=TArea
- self.imagesink = None
- self.Area.unset_flags(gtk.DOUBLE_BUFFERED)
+ ## Constructor.
+ # \param TArea - GTK+ drowing area widget.
+ def __init__(self, TArea):
+ self.Area=TArea
+ self.imagesink = None
+ self.Area.unset_flags(gtk.DOUBLE_BUFFERED)
- ## \var Area
- # GTK+ drowing area widget.
-
- ## \var imagesink
- # Sink element for
+ ## \var Area
+ # GTK+ drowing area widget.
- def do_expose_event(self, event):
- if self.imagesink:
- self.imagesink.expose()
- return False
- else:
- return True
+ ## \var imagesink
+ # Sink element for
- def set_sink(self, sink):
- assert self.Area.window.xid
- self.imagesink = sink
- self.imagesink.set_xwindow_id(self.Area.window.xid)
+ def do_expose_event(self, event):
+ if self.imagesink:
+ self.imagesink.expose()
+ return False
+ else:
+ return True
+
+ def set_sink(self, sink):
+ assert self.Area.window.xid
+ self.imagesink = sink
+ self.imagesink.set_xwindow_id(self.Area.window.xid)
Modified: trunk/subtle/Subtle.py
===================================================================
--- trunk/subtle/Subtle.py 2008-06-19 06:30:46 UTC (rev 15049)
+++ trunk/subtle/Subtle.py 2008-06-20 22:24:28 UTC (rev 15050)
@@ -844,10 +844,9 @@
self.labelHour.set_text("%02d"%Hour)
self.labelMin.set_text("%02d"%Min)
self.labelSec.set_text("%02d"%Sec)
- #BUG: We are not displaying that correctly
+ #BUG: We are not displaying that correctly
self.labelMSec.set_text("%09d"%MSec)
- #FIXME: We should know which media is playing
- self.lbl_cur_fps.set_text("%d"%(MSec/1/self.media[0].framerate))
+ self.lbl_cur_fps.set_text("%.2f"%(self.player.query_frame(self.p_position)))
return True
#==============================================================================
# MAIN:
More information about the commits
mailing list