Development Team/Almanac/GStreamer: Difference between revisions
Appearance
m moved Anal bleaching 15/Almanac/GStreamer to Development Team/Almanac/GStreamer over redirect: revert |
mNo edit summary |
||
| (2 intermediate revisions by 2 users not shown) | |||
| Line 50: | Line 50: | ||
def setFile(self, path): | def setFile(self, path): | ||
uri = "file://" + str( path ) | uri = "file://" + str( path ) | ||
if | if self.player.get_property('uri') == uri: | ||
self.seek(gst.SECOND*0) | self.seek(gst.SECOND*0) | ||
return | return | ||
| Line 57: | Line 57: | ||
self.player.set_property('uri', uri) | self.player.set_property('uri', uri) | ||
ext = uri[len(uri)-3:] | ext = uri[len(uri)-3:] | ||
if | if ext == "jpg": | ||
self.pause() | self.pause() | ||
else: | else: | ||
| Line 119: | Line 119: | ||
def set_sink(self, sink): | def set_sink(self, sink): | ||
if | if self.imagesink != None: | ||
assert self.window.xid | assert self.window.xid | ||
self.imagesink = None | self.imagesink = None | ||
| Line 240: | Line 240: | ||
def removeCallbacks( self ): | def removeCallbacks( self ): | ||
if | if self.UPDATE_SCALE_ID != 0: | ||
gobject.source_remove(self.UPDATE_SCALE_ID) | gobject.source_remove(self.UPDATE_SCALE_ID) | ||
self.UPDATE_SCALE_ID = 0 | self.UPDATE_SCALE_ID = 0 | ||
if | if self.CHANGED_ID != 0: | ||
gobject.source_remove(self.CHANGED_ID) | gobject.source_remove(self.CHANGED_ID) | ||
self.CHANGED_ID = 0 | self.CHANGED_ID = 0 | ||
| Line 266: | Line 266: | ||
def play_toggled(self): | def play_toggled(self): | ||
self.p_position, self.p_duration = self._gplay.queryPosition() | self.p_position, self.p_duration = self._gplay.queryPosition() | ||
if | if self.p_position == self.p_duration: | ||
self._gplay.seek(0) | self._gplay.seek(0) | ||
self._gplay.pause() | self._gplay.pause() | ||
| Line 331: | Line 331: | ||
if self.p_position != gst.CLOCK_TIME_NONE: | if self.p_position != gst.CLOCK_TIME_NONE: | ||
value = self.p_position * 100.0 / self.p_duration | value = self.p_position * 100.0 / self.p_duration | ||
if | if value > 99: | ||
value = 99 | value = 99 | ||
elif | elif value < 0: | ||
value = 0 | value = 0 | ||
self.adjustment.set_value(value) | self.adjustment.set_value(value) | ||
if self._gplay.is_playing() and | if self._gplay.is_playing() and self.p_position == self.p_duration: | ||
self._gplay.pause() | self._gplay.pause() | ||
self.set_button_play() | self.set_button_play() | ||
Latest revision as of 13:29, 2 February 2011
For Developers: almanac · api · bugs · gitorious · cgit · download · people · OLPC: wiki · activities · trac · cgit · build index · repository · firmware · Fedora: packages
Where can I get additional resources and sample code on using the camera?
How can I embed video files in my activity?
Sugar, by default, can play back audio (encoded in Vorbis) and video (encoded in Theora) files in ogg containers.
The following file will be helpful for embedding video or audio files into your activity. After the code posting is a code snippet showing how to use this.
import gtk
import pygtk
pygtk.require('2.0')
import sys
import pygst
pygst.require('0.10')
import gst
import gst.interfaces
import gobject
import time
gobject.threads_init()
class Gplay:
def __init__(self):
self.window = None
self.playing = False
self.player = gst.element_factory_make("playbin", "playbin")
xis = gst.element_factory_make("xvimagesink", "xvimagesink")
self.player.set_property("video-sink", xis)
bus = self.player.get_bus()
bus.enable_sync_message_emission()
bus.add_signal_watch()
self.SYNC_ID = bus.connect('sync-message::element', self._onSyncMessageCb)
def _onSyncMessageCb(self, bus, message):
if message.structure is None:
return True
if message.structure.get_name() == 'prepare-xwindow-id':
self.window.set_sink(message.src)
message.src.set_property('force-aspect-ratio', True)
return True
def setFile(self, path):
uri = "file://" + str( path )
if self.player.get_property('uri') == uri:
self.seek(gst.SECOND*0)
return
self.player.set_state(gst.STATE_READY)
self.player.set_property('uri', uri)
ext = uri[len(uri)-3:]
if ext == "jpg":
self.pause()
else:
self.play()
def queryPosition(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
return (position, duration)
def seek(self, time):
event = gst.event_new_seek(1.0, gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE, gst.SEEK_TYPE_SET, time, gst.SEEK_TYPE_NONE, 0)
res = self.player.send_event(event)
if res:
self.player.set_new_stream_time(0L)
def pause(self):
self.playing = False
self.player.set_state(gst.STATE_PAUSED)
def play(self):
self.playing = True
self.player.set_state(gst.STATE_PLAYING)
def stop(self):
self.playing = False
self.player.set_state(gst.STATE_NULL)
self.nextMovie()
def get_state(self, timeout=1):
return self.player.get_state(timeout=timeout)
def is_playing(self):
return self.playing
class PlayVideoWindow(gtk.Window):
def __init__(self):
gtk.Window.__init__(self)
self.imagesink = None
self.unset_flags(gtk.DOUBLE_BUFFERED)
self.set_flags(gtk.APP_PAINTABLE)
def set_sink(self, sink):
if self.imagesink != None:
assert self.window.xid
self.imagesink = None
del self.imagesink
self.imagesink = sink
self.imagesink.set_xwindow_id(self.window.xid)
And here is a code snippet showing how you would use this file to embed media playback in your activity:
#this is our video playback window self.gplay = Gplay( ) self.gplayWin = PlayVideoWindow( ) self.gplay.window = self.gplayWin self.gplayWin.set_type_hint( gtk.gdk.WINDOW_TYPE_HINT_DIALOG ) self.gplayWin.set_decorated( False ) self.gplayWin.set_transient_for( self ) #activity subclass self.gplayWin.move( 100, 100 ) self.gplayWin.resize( 300, 400 ) self.gplayWin.show_all( )
Alternatively, you could embed your video into a gtk.DrawingArea:
class VideoWidget(gtk.DrawingArea):
def __init__(self):
gtk.DrawingArea.__init__(self)
self.set_events(gtk.gdk.POINTER_MOTION_MASK |
gtk.gdk.POINTER_MOTION_HINT_MASK |
gtk.gdk.EXPOSURE_MASK |
gtk.gdk.KEY_PRESS_MASK |
gtk.gdk.KEY_RELEASE_MASK)
self.imagesink = None
self.unset_flags(gtk.DOUBLE_BUFFERED)
self.set_flags(gtk.APP_PAINTABLE)
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)
How can I add play/pause buttons and a scrubber to my audio or video?
The widget below is pre-configured to work with the gplay class above. This widget takes two gtk.Images in its constructor.
import gtk
import pygtk
pygtk.require('2.0')
import pygst
pygst.require('0.10')
import gst
import gst.interfaces
import gobject
import sugar.graphics.style
class GScrub(gtk.Window):
def __init__(self, gplay, playImg, pauseImg):
gtk.Window.__init__(self)
self._gplay = gplay
self._playImg = playImg
self._pauseImg = pauseImg
self.UPDATE_INTERVAL = 500
self.UPDATE_SCALE_ID = 0
self.CHANGED_ID = 0
self.was_playing = False
self.p_position = gst.CLOCK_TIME_NONE
self.p_duration = gst.CLOCK_TIME_NONE
self.hbox = gtk.HBox()
self.hbox.modify_bg( gtk.STATE_NORMAL, sugar.graphics.style.COLOR_BLACK.get_gdk_color() )
self.hbox.modify_bg( gtk.STATE_INSENSITIVE, sugar.graphics.style.COLOR_BLACK.get_gdk_color() )
self.add( self.hbox )
self.button = gtk.Button()
buttBox = gtk.EventBox()
buttBox.add(self.button)
buttBox.modify_bg( gtk.STATE_NORMAL, sugar.graphics.style.COLOR_BLACK.get_gdk_color() )
self.button.set_image( self._playImg )
self.button.set_property('can-default', True)
self.button.set_relief(gtk.RELIEF_NONE)
self.button.set_size_request( 55, 55 )
buttBox.set_size_request( 55, 55 )
self.button.show()
buttBox.modify_bg( gtk.STATE_NORMAL, sugar.graphics.style.COLOR_BLACK.get_gdk_color() )
self.button.modify_bg( gtk.STATE_ACTIVE, sugar.graphics.style.COLOR_BLACK.get_gdk_color() )
self.button.connect('clicked', self._buttonClickedCb)
self.hbox.pack_start(buttBox, expand=False)
self.adjustment = gtk.Adjustment(0.0, 0.00, 100.0, 0.1, 1.0, 1.0)
self.hscale = gtk.HScale(self.adjustment)
self.hscale.set_draw_value(False)
self.hscale.set_update_policy(gtk.UPDATE_CONTINUOUS)
hscaleBox = gtk.EventBox()
hscaleBox.modify_bg( gtk.STATE_NORMAL, sugar.graphics.style.COLOR_BLACK.get_gdk_color() )
hscaleBox.add( self.hscale )
self.hscale.connect('button-press-event', self._scaleButtonPressCb)
self.hscale.connect('button-release-event', self._scaleButtonReleaseCb)
self.hbox.pack_start(hscaleBox, expand=True)
def removeCallbacks( self ):
if self.UPDATE_SCALE_ID != 0:
gobject.source_remove(self.UPDATE_SCALE_ID)
self.UPDATE_SCALE_ID = 0
if self.CHANGED_ID != 0:
gobject.source_remove(self.CHANGED_ID)
self.CHANGED_ID = 0
def reset(self):
self.adjustment.set_value(0)
def _buttonClickedCb(self, widget):
self.play_toggled()
def set_button_play(self):
self.button.set_image(self._playImg)
def set_button_pause(self):
self.button.set_image(self._pauseImg)
def play_toggled(self):
self.p_position, self.p_duration = self._gplay.queryPosition()
if self.p_position == self.p_duration:
self._gplay.seek(0)
self._gplay.pause()
if self._gplay.is_playing():
self._gplay.pause()
self.set_button_play()
else:
#if self._gplay.error:
# #todo: check if we have "error", and also to disable everything
# self.button.set_disabled()
#else:
self.doPlay()
def doPlay(self):
self._gplay.play()
if self.UPDATE_SCALE_ID == 0:
self.UPDATE_SCALE_ID = gobject.timeout_add(self.UPDATE_INTERVAL, self._updateScaleCb)
self.set_button_pause()
def _scaleButtonPressCb(self, widget, event):
#self.button.set_sensitive(False)
self.was_playing = self._gplay.is_playing()
if self.was_playing:
self._gplay.pause()
# don't timeout-update position during seek
if self.UPDATE_SCALE_ID != 0:
gobject.source_remove(self.UPDATE_SCALE_ID)
self.UPDATE_SCALE_ID = 0
# make sure we get changed notifies
if self.CHANGED_ID == 0:
self.CHANGED_ID = self.hscale.connect('value-changed', self._scaleValueChangedCb)
def _scaleButtonReleaseCb(self, widget, event):
# see seek.cstop_seek
widget.disconnect(self.CHANGED_ID)
self.CHANGED_ID = 0
#self.button.set_sensitive(True)
if self.was_playing:
self._gplay.play()
if self.UPDATE_SCALE_ID != 0:
pass
#print('Had a previous update timeout id')
else:
self.UPDATE_SCALE_ID = gobject.timeout_add(self.UPDATE_INTERVAL, self._updateScaleCb)
def _scaleValueChangedCb(self, scale):
real = long(scale.get_value() * self.p_duration / 100) # in ns
self._gplay.seek(real)
# allow for a preroll
self._gplay.get_state(timeout=50*gst.MSECOND) # 50 ms
def _updateScaleCb(self):
self.p_position, self.p_duration = self._gplay.queryPosition()
if self.p_position != gst.CLOCK_TIME_NONE:
value = self.p_position * 100.0 / self.p_duration
if value > 99:
value = 99
elif value < 0:
value = 0
self.adjustment.set_value(value)
if self._gplay.is_playing() and self.p_position == self.p_duration:
self._gplay.pause()
self.set_button_play()
return True