Difference between revisions of "Development Team/Almanac/GStreamer"
< Development Team | Almanac
Jump to navigation
Jump to search
m |
|||
(11 intermediate revisions by 8 users not shown) | |||
Line 1: | Line 1: | ||
− | {{ | + | {{Almanac}} |
=== Where can I get additional resources and sample code on using the camera? === | === Where can I get additional resources and sample code on using the camera? === | ||
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 143: | Line 143: | ||
self.gplayWin.resize( 300, 400 ) | self.gplayWin.resize( 300, 400 ) | ||
self.gplayWin.show_all( ) | self.gplayWin.show_all( ) | ||
+ | </pre> | ||
+ | |||
+ | Alternatively, you could embed your video into a gtk.DrawingArea: | ||
+ | |||
+ | <pre> | ||
+ | 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) | ||
+ | |||
+ | </pre> | ||
+ | |||
+ | === 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. | ||
+ | |||
+ | <pre> | ||
+ | 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 | ||
</pre> | </pre> |
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