Development Team/Almanac/GStreamer

Where can I get additional resources and sample code on using the camera?

 * Programming_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