Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPootle daemon <pootle@sugarlabs.org>2009-04-30 18:41:25 (GMT)
committer Pootle daemon <pootle@sugarlabs.org>2009-04-30 18:41:25 (GMT)
commit54aa87226609cc31f1adb1802734e590ecccf71f (patch)
tree16a72857aeb415ed1d8e36328bbfe702f61c1f25
parentf94b7440eaeebac247566fd8a31a7283343d72a8 (diff)
parent32b3af2dcf4b5ce855c07b3056e8c52e740dcc44 (diff)
Merge branch 'master' of gitorious@git.sugarlabs.org:record/mainline
-rw-r--r--.gitignore27
-rw-r--r--MANIFEST363
-rw-r--r--NEWS19
-rwxr-xr-x_camera.sobin32196 -> 0 bytes
-rw-r--r--activity/activity.info8
-rw-r--r--aplay.py39
-rwxr-xr-xbin/Record.sh4
-rw-r--r--button.py136
-rw-r--r--camerac/Makefile (renamed from Makefile)26
-rw-r--r--camerac/__init__.py21
-rw-r--r--camerac/camera.c (renamed from _camera.c)6
-rw-r--r--color.py66
-rw-r--r--constants.py672
-rw-r--r--glive.py927
-rw-r--r--glivex.py147
-rw-r--r--gplay.py160
-rw-r--r--greplay.py84
-rw-r--r--gst/AUTHORS0
-rw-r--r--gst/COPYING674
-rw-r--r--gst/ChangeLog0
-rw-r--r--gst/INSTALL291
-rw-r--r--gst/Makefile.am20
-rw-r--r--gst/NEWS0
-rw-r--r--gst/README0
-rwxr-xr-xgst/autogen.sh92
-rw-r--r--gst/configure.ac136
-rw-r--r--gst/gst-autogen.sh308
-rw-r--r--gst/gstvalve.c311
-rw-r--r--gst/gstvalve.h82
-rw-r--r--gst/gstvideorate.c877
-rw-r--r--gst/gstvideorate.h81
-rw-r--r--gst/m4/Makefile.am1
-rw-r--r--gst/m4/as-compiler-flag.m425
-rw-r--r--gst/m4/as-version.m466
-rw-r--r--instance.py50
-rw-r--r--model.py639
-rw-r--r--p5.py228
-rw-r--r--p5_button.py196
-rw-r--r--po/zh_TW.po2
-rw-r--r--port/AUTHORS1
-rw-r--r--port/COPYING340
-rw-r--r--port/NEWS8
-rw-r--r--port/README13
-rw-r--r--port/TODO0
-rw-r--r--port/__init__.py0
-rw-r--r--port/json.py33
-rw-r--r--record.py906
-rw-r--r--recorded.py282
-rw-r--r--recordtube.py226
-rw-r--r--serialize.py567
-rwxr-xr-xsetup.py3
-rw-r--r--ui.py4112
-rw-r--r--utils.py126
53 files changed, 8136 insertions, 5265 deletions
diff --git a/.gitignore b/.gitignore
index 5d1e468..a458ac0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,28 @@
-_camera.o
+*.o
+*.so
+linux*
dist
locale
+
+aclocal.m4
+autom4te.cache
+autoregen.sh
+config.log
+config.status
+configure
+libtool
+stamp-h1
+*.la
+config.h
+*.in
+Makefile
+config.guess
+config.sub
+depcomp
+ltmain.sh
+install-sh
+missing
+.deps
+.libs
+*.lo
+
diff --git a/MANIFEST b/MANIFEST
deleted file mode 100644
index 557abf7..0000000
--- a/MANIFEST
+++ /dev/null
@@ -1,363 +0,0 @@
-COPYING
-Makefile
-NEWS
-_camera.c
-_camera.so
-button.py
-color.py
-constants.py
-glive.py
-gplay.py
-greplay.py
-instance.py
-model.py
-p5.py
-p5_button.py
-record.py
-recorded.py
-recordtube.py
-serialize.py
-setup.py
-toolbarcombobox.py
-tray.py
-ui.py
-utils.py
-_camera.o
-activity/activity-record.svg
-activity/activity.info
-gfx/corner-info.svg
-gfx/full-insensitive.png
-gfx/info-on.svg
-gfx/max-enlarge.svg
-gfx/max-reduce.svg
-gfx/media-circle.png
-gfx/media-insensitive.png
-gfx/media-pause.png
-gfx/media-play.png
-gfx/media-record-red.png
-gfx/media-record.png
-gfx/media-record.svg
-gfx/object-audio.svg
-gfx/object-photo.svg
-gfx/object-video.svg
-gfx/photoShutter.wav
-gfx/xo-guy.svg
-icons/media-audio.svg
-icons/media-photo.svg
-icons/media-video.svg
-po/Record.pot
-po/af.po
-po/am.po
-po/ar.po
-po/ay.po
-po/bg.po
-po/bn.po
-po/bn_IN.po
-po/ca.po
-po/de.po
-po/dz.po
-po/el.po
-po/en.po
-po/es.po
-po/fa.po
-po/fa_AF.po
-po/ff.po
-po/fr.po
-po/gu.po
-po/ha.po
-po/hi.po
-po/ht.po
-po/ig.po
-po/is.po
-po/it.po
-po/ja.po
-po/km.po
-po/ko.po
-po/mk.po
-po/ml.po
-po/mn.po
-po/mr.po
-po/mvo.po
-po/nb.po
-po/ne.po
-po/nl.po
-po/pa.po
-po/pap.po
-po/pis.po
-po/pl.po
-po/ps.po
-po/pseudo.po
-po/pt.po
-po/pt_BR.po
-po/qu.po
-po/ro.po
-po/ru.po
-po/rw.po
-po/sd.po
-po/si.po
-po/sl.po
-po/ta.po
-po/te.po
-po/th.po
-po/tpi.po
-po/tr.po
-po/ur.po
-po/yo.po
-po/zh_CN.po
-po/zh_TW.po
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-po/vi.po
-po/sk.po
-po/cs.po
-po/bi.po
-po/na.po
-po/sw.po
-po/sv.po
-locale/ay/activity.linfo
-locale/ay/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/af/activity.linfo
-locale/af/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ar/activity.linfo
-locale/ar/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/is/activity.linfo
-locale/is/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ht/activity.linfo
-locale/ht/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/tr/activity.linfo
-locale/tr/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/pt_BR/activity.linfo
-locale/pt_BR/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/yo/activity.linfo
-locale/yo/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/sd/activity.linfo
-locale/sd/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/mn/activity.linfo
-locale/mn/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ca/activity.linfo
-locale/ca/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/zh_TW/activity.linfo
-locale/zh_TW/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ig/activity.linfo
-locale/ig/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ja/activity.linfo
-locale/ja/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/am/activity.linfo
-locale/am/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/qu/activity.linfo
-locale/qu/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/vi/activity.linfo
-locale/vi/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ps/activity.linfo
-locale/ps/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/hi/activity.linfo
-locale/hi/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/gu/activity.linfo
-locale/gu/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/sk/activity.linfo
-locale/sk/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/de/activity.linfo
-locale/de/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ur/activity.linfo
-locale/ur/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ta/activity.linfo
-locale/ta/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ha/activity.linfo
-locale/ha/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/bg/activity.linfo
-locale/bg/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/pt/activity.linfo
-locale/pt/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/pap/activity.linfo
-locale/pap/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/it/activity.linfo
-locale/it/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/tpi/activity.linfo
-locale/tpi/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/mk/activity.linfo
-locale/mk/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/el/activity.linfo
-locale/el/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ru/activity.linfo
-locale/ru/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/nl/activity.linfo
-locale/nl/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/fa_AF/activity.linfo
-locale/fa_AF/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/pa/activity.linfo
-locale/pa/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/rw/activity.linfo
-locale/rw/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/fr/activity.linfo
-locale/fr/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/sw/activity.linfo
-locale/sw/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/te/activity.linfo
-locale/te/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/fa/activity.linfo
-locale/fa/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/zh_CN/activity.linfo
-locale/zh_CN/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/en/activity.linfo
-locale/en/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/mvo/activity.linfo
-locale/mvo/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/sl/activity.linfo
-locale/sl/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/th/activity.linfo
-locale/th/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ro/activity.linfo
-locale/ro/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/sv/activity.linfo
-locale/sv/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/dz/activity.linfo
-locale/dz/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/es/activity.linfo
-locale/es/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/km/activity.linfo
-locale/km/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/na/activity.linfo
-locale/na/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ne/activity.linfo
-locale/ne/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/cs/activity.linfo
-locale/cs/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/bi/activity.linfo
-locale/bi/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/pl/activity.linfo
-locale/pl/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/bn_IN/activity.linfo
-locale/bn_IN/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/si/activity.linfo
-locale/si/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/mr/activity.linfo
-locale/mr/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ff/activity.linfo
-locale/ff/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/nb/activity.linfo
-locale/nb/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/pis/activity.linfo
-locale/pis/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ml/activity.linfo
-locale/ml/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/ko/activity.linfo
-locale/ko/LC_MESSAGES/org.laptop.RecordActivity.mo
-locale/bn/activity.linfo
-locale/bn/LC_MESSAGES/org.laptop.RecordActivity.mo
-glivex.py
diff --git a/NEWS b/NEWS
index a6f687d..4b5db4f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,22 @@
+63
+
+* Change only volumes for "Capture" channels and let user change others
+* Record controls only appear on second launch #762
+
+62
+
+* Select quality for enconding video
+* Unmute/set-to-max capture channels
+ workaround code until sugar controls capture volumes in the shell
+* Revert two pass video encoding to support limited hardware
+* Save GUI state in Journal objects
+
+61
+
+* Use uuid and do not md5 video files
+* Fallback to ximagesink if xvimagesink is unaccessible
+* Use one pass for encodings
+
60
* pipeline rework; makes the activity work with new gstreamer
diff --git a/_camera.so b/_camera.so
deleted file mode 100755
index ec00d95..0000000
--- a/_camera.so
+++ /dev/null
Binary files differ
diff --git a/activity/activity.info b/activity/activity.info
index 04d5623..ad7ad8b 100644
--- a/activity/activity.info
+++ b/activity/activity.info
@@ -1,9 +1,9 @@
[Activity]
name = Record
-service_name = org.laptop.RecordActivity
-class = record.Record
+bundle_id = org.laptop.RecordActivity
+exec = Record.sh
icon = activity-record
-activity_version = 60
+activity_version = 63
show_launcher = yes
license = MIT
-update_url = http://wiki.laptop.org/go/Activities/G1G1
+update_url = http://activities.sugarlabs.org/en-US/sugar/addon/4081
diff --git a/aplay.py b/aplay.py
new file mode 100644
index 0000000..596d880
--- /dev/null
+++ b/aplay.py
@@ -0,0 +1,39 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gst
+
+import logging
+logger = logging.getLogger('record:aplay.py')
+
+def play(file):
+ player.set_state(gst.STATE_NULL)
+ player.props.uri = 'file://' + file
+ player.set_state(gst.STATE_PLAYING)
+
+def _gstmessage_cb(bus, message):
+ if message.type == gst.MESSAGE_EOS:
+ player.set_state(gst.STATE_NULL)
+ elif message.type == gst.MESSAGE_ERROR:
+ err, debug = message.parse_error()
+ logger.error('play_pipe: %s %s' % (err, debug))
+ player.set_state(gst.STATE_NULL)
+
+player = gst.element_factory_make('playbin')
+fakesink = gst.element_factory_make('fakesink')
+player.set_property("video-sink", fakesink)
+
+bus = player.get_bus()
+bus.add_signal_watch()
+bus.connect('message', _gstmessage_cb)
diff --git a/bin/Record.sh b/bin/Record.sh
new file mode 100755
index 0000000..8dc1c0c
--- /dev/null
+++ b/bin/Record.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+root=`cd $(dirname $0)/..; pwd`
+export GST_PLUGIN_PATH="$GST_PLUGIN_PATH:$root/gst"
+exec sugar-activity record.Record "$@"
diff --git a/button.py b/button.py
index 460139d..14b9700 100644
--- a/button.py
+++ b/button.py
@@ -12,97 +12,97 @@ from constants import Constants
import utils
class RecdButton(TrayButton, gobject.GObject):
- def __init__(self, ui, recd):
- TrayButton.__init__(self)
- self.ui = ui
- self.recd = recd
+ def __init__(self, ui, recd):
+ TrayButton.__init__(self)
+ self.ui = ui
+ self.recd = recd
- img = self.getImg( )
- self.set_icon_widget( img )
+ img = self.getImg( )
+ self.set_icon_widget( img )
- self.ACTIVATE_COPY_ID = 0
- self.ACTIVATE_REMOVE_ID = 0
- self.setup_rollover_options( recd.title )
+ self.ACTIVATE_COPY_ID = 0
+ self.ACTIVATE_REMOVE_ID = 0
+ self.setup_rollover_options( recd.title )
- def getImg( self ):
- img = gtk.Image()
- ipb = self.recd.getThumbPixbuf()
- xoff = 8
- yoff = 8
- pb = None
- if (self.recd.type == Constants.TYPE_PHOTO):
- if (self.recd.buddy):
- thumbPhotoSvg = utils.loadSvg(Constants.thumbPhotoSvgData, self.recd.colorStroke.hex, self.recd.colorFill.hex)
- pb = thumbPhotoSvg.get_pixbuf()
- else:
- pb = Constants.thumbPhotoSvg.get_pixbuf()
+ def getImg( self ):
+ img = gtk.Image()
+ ipb = self.recd.getThumbPixbuf()
+ xoff = 8
+ yoff = 8
+ pb = None
+ if (self.recd.type == Constants.TYPE_PHOTO):
+ if (self.recd.buddy):
+ thumbPhotoSvg = utils.loadSvg(Constants.thumbPhotoSvgData, self.recd.colorStroke.hex, self.recd.colorFill.hex)
+ pb = thumbPhotoSvg.get_pixbuf()
+ else:
+ pb = Constants.thumbPhotoSvg.get_pixbuf()
- elif (self.recd.type == Constants.TYPE_VIDEO):
- if (self.recd.buddy):
- thumbVideoSvg = utils.loadSvg(Constants.thumbVideoSvgData, self.recd.colorStroke.hex, self.recd.colorFill.hex)
- pb = thumbVideoSvg.get_pixbuf()
- else:
- pb = Constants.thumbVideoSvg.get_pixbuf()
+ elif (self.recd.type == Constants.TYPE_VIDEO):
+ if (self.recd.buddy):
+ thumbVideoSvg = utils.loadSvg(Constants.thumbVideoSvgData, self.recd.colorStroke.hex, self.recd.colorFill.hex)
+ pb = thumbVideoSvg.get_pixbuf()
+ else:
+ pb = Constants.thumbVideoSvg.get_pixbuf()
- elif (self.recd.type == Constants.TYPE_AUDIO):
- if (self.recd.buddy):
- thumbAudioSvg = utils.loadSvg(Constants.thumbAudioSvgData, self.recd.colorStroke.hex, self.recd.colorFill.hex)
- pb = thumbAudioSvg.get_pixbuf()
- else:
- pb = Constants.thumbAudioSvg.get_pixbuf()
+ elif (self.recd.type == Constants.TYPE_AUDIO):
+ if (self.recd.buddy):
+ thumbAudioSvg = utils.loadSvg(Constants.thumbAudioSvgData, self.recd.colorStroke.hex, self.recd.colorFill.hex)
+ pb = thumbAudioSvg.get_pixbuf()
+ else:
+ pb = Constants.thumbAudioSvg.get_pixbuf()
- img.set_from_pixbuf(pb)
- img.show()
- ipb.composite(pb, xoff, yoff, ipb.get_width(), ipb.get_height(), xoff, yoff, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
- img.set_from_pixbuf(pb)
+ img.set_from_pixbuf(pb)
+ img.show()
+ ipb.composite(pb, xoff, yoff, ipb.get_width(), ipb.get_height(), xoff, yoff, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
+ img.set_from_pixbuf(pb)
- gc.collect()
+ gc.collect()
- return img
+ return img
- def setButtClickedId( self, id ):
- self.BUTT_CLICKED_ID = id
+ def setButtClickedId( self, id ):
+ self.BUTT_CLICKED_ID = id
- def getButtClickedId( self ):
- return self.BUTT_CLICKED_ID
+ def getButtClickedId( self ):
+ return self.BUTT_CLICKED_ID
- def setup_rollover_options( self, info ):
- palette = Palette(info)
- self.set_palette(palette)
+ def setup_rollover_options( self, info ):
+ palette = Palette(info)
+ self.set_palette(palette)
- self.rem_menu_item = gtk.MenuItem( Constants.istrRemove )
- self.ACTIVATE_REMOVE_ID = self.rem_menu_item.connect('activate', self._itemRemoveCb)
- palette.menu.append(self.rem_menu_item)
- self.rem_menu_item.show()
+ self.rem_menu_item = gtk.MenuItem( Constants.istrRemove )
+ self.ACTIVATE_REMOVE_ID = self.rem_menu_item.connect('activate', self._itemRemoveCb)
+ palette.menu.append(self.rem_menu_item)
+ self.rem_menu_item.show()
- self.addCopyMenuItem()
+ self.addCopyMenuItem()
- def addCopyMenuItem( self ):
- if (self.recd.buddy and not self.recd.downloadedFromBuddy):
- return
- if (self.ACTIVATE_COPY_ID != 0):
- return
+ def addCopyMenuItem( self ):
+ if (self.recd.buddy and not self.recd.downloadedFromBuddy):
+ return
+ if (self.ACTIVATE_COPY_ID != 0):
+ return
- self.copy_menu_item = gtk.MenuItem( Constants.istrCopyToClipboard )
- self.ACTIVATE_COPY_ID = self.copy_menu_item.connect('activate', self._itemCopyToClipboardCb)
- self.get_palette().menu.append(self.copy_menu_item)
- self.copy_menu_item.show()
+ self.copy_menu_item = gtk.MenuItem( Constants.istrCopyToClipboard )
+ self.ACTIVATE_COPY_ID = self.copy_menu_item.connect('activate', self._itemCopyToClipboardCb)
+ self.get_palette().menu.append(self.copy_menu_item)
+ self.copy_menu_item.show()
- def cleanUp( self ):
- self.rem_menu_item.disconnect( self.ACTIVATE_REMOVE_ID )
- if (self.ACTIVATE_COPY_ID != 0):
- self.copy_menu_item.disconnect( self.ACTIVATE_COPY_ID )
+ def cleanUp( self ):
+ self.rem_menu_item.disconnect( self.ACTIVATE_REMOVE_ID )
+ if (self.ACTIVATE_COPY_ID != 0):
+ self.copy_menu_item.disconnect( self.ACTIVATE_COPY_ID )
- def _itemRemoveCb(self, widget):
- self.ui.deleteThumbSelection( self.recd )
+ def _itemRemoveCb(self, widget):
+ self.ui.deleteThumbSelection( self.recd )
- def _itemCopyToClipboardCb(self, widget):
- self.ui.copyToClipboard( self.recd ) \ No newline at end of file
+ def _itemCopyToClipboardCb(self, widget):
+ self.ui.copyToClipboard( self.recd ) \ No newline at end of file
diff --git a/Makefile b/camerac/Makefile
index 265b3ee..12f6429 100644
--- a/Makefile
+++ b/camerac/Makefile
@@ -17,21 +17,23 @@ PYCAIRO_INCLUDES=`pkg-config --cflags pycairo`
PYCAIRO_LIBS=`pkg-config --libs pycairo`
INCLUDES=-I. -I/usr/include/${PYTHON} ${GLIB_INCLUDES} ${PYGTK_INCLUDES} ${CAIRO_INCLUDES} ${PYCAIRO_INCLUDES} ${GTK_INCLUDES}
-ARCHFLAGS=-m32 -march=i386 -mtune=generic
OPTFLAGS=-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -fasynchronous-unwind-tables
-CFLAGS=-g -fPIC -DPIC
-LDFLAGS=-shared -nostdlib -Wl,--export-dynamic -pthread
+CFLAGS=-g -fPIC -DPIC $(OPTFLAGS) $(INCLUDES)
+LDFLAGS=-shared -nostdlib -Wl,--export-dynamic -pthread ${GLIB_LIBS} ${PYGTK_LIBS} ${CAIRO_LIBS} ${PYCAIRO_LIBS} ${GTK_LIBS}
-all: build link
+ARCH = $(shell arch | grep 64 >/dev/null && echo linux64 || echo linux32)
+LIB_DIR = $(ARCH)_$(PYVER)
-build: _camera.o
-_camera.o: _camera.c
- gcc ${INCLUDES} ${ARCHFLAGS} ${OPTFLAGS} ${CFLAGS} -c _camera.c -o _camera.o
+all: camera.so
+ rm -rf $(LIB_DIR)
+ mkdir $(LIB_DIR)
+ strip -s $^
+ mv $^ $(LIB_DIR)/
+ touch $(LIB_DIR)/__init__.py
-link: _camera.so
-_camera.so: _camera.o
- g++ ${LDFLAGS} _camera.o ${GLIB_LIBS} ${PYGTK_LIBS} ${CAIRO_LIBS} ${PYCAIRO_LIBS} ${GTK_LIBS} -Wl,-soname -Wl,_camera.so -o _camera.so
+camera.so: camera.o
+ $(CXX) $(LDFLAGS) -o $@ $^
clean:
- @find -name "*.o" -exec rm {} \;
- @find -name "*.so" -exec rm {} \;
+ rm -f *.o
+ rm -f *.so
diff --git a/camerac/__init__.py b/camerac/__init__.py
new file mode 100644
index 0000000..dba55ae
--- /dev/null
+++ b/camerac/__init__.py
@@ -0,0 +1,21 @@
+import os
+import sys
+import logging
+
+_sys_path = sys.path
+_root_path = os.path.dirname(__file__)
+
+for i in os.listdir(_root_path):
+ path = os.path.join(_root_path, i)
+ if (os.path.isdir(path)):
+ sys.path = _sys_path + [os.path.join('.', path)]
+ try:
+ from camera import *
+ logging.debug('use %s blobs' % path)
+ _sys_path = None
+ break
+ except Exception, e:
+ logging.debug('skip %s blobs: %s' % (path, e))
+
+if _sys_path:
+ raise('cannot find proper binary blobs')
diff --git a/_camera.c b/camerac/camera.c
index 694f0a4..cf4795d 100644
--- a/_camera.c
+++ b/camerac/camera.c
@@ -260,17 +260,17 @@ py_camera_register_classes(PyObject *d)
}
DL_EXPORT(void)
-init_camera(void)
+initcamera(void)
{
PyObject *m, *d;
Pycairo_IMPORT;
- m = Py_InitModule ("_camera", py_camera_functions);
+ m = Py_InitModule ("camera", py_camera_functions);
d = PyModule_GetDict (m);
py_camera_register_classes (d);
if (PyErr_Occurred ()) {
- Py_FatalError ("can't initialise module _camera");
+ Py_FatalError ("can't initialise module camera");
}
}
diff --git a/color.py b/color.py
index 3a9b954..f544405 100644
--- a/color.py
+++ b/color.py
@@ -22,50 +22,50 @@ import gtk
class Color:
- def __init__(self):
- pass
+ def __init__(self):
+ pass
- def init_rgba(self, r, g, b, a):
- self._ro = r
- self._go = g
- self._bo = b
- self._ao = a;
- self._r = self._ro / 255.0
- self._g = self._go / 255.0
- self._b = self._bo / 255.0
- self._a = self._ao / 255.0
+ def init_rgba(self, r, g, b, a):
+ self._ro = r
+ self._go = g
+ self._bo = b
+ self._ao = a;
+ self._r = self._ro / 255.0
+ self._g = self._go / 255.0
+ self._b = self._bo / 255.0
+ self._a = self._ao / 255.0
- self._opaque = False
- if (self._a == 1):
- self.opaque = True
+ self._opaque = False
+ if (self._a == 1):
+ self.opaque = True
- rgb_tup = ( self._ro, self._go, self._bo )
- self.hex = self.rgb_to_hex( rgb_tup )
- self.gColor = gtk.gdk.color_parse( self.hex )
+ rgb_tup = ( self._ro, self._go, self._bo )
+ self.hex = self.rgb_to_hex( rgb_tup )
+ self.gColor = gtk.gdk.color_parse( self.hex )
- def init_gdk(self, col):
- self.init_hex( col.get_html() )
+ def init_gdk(self, col):
+ self.init_hex( col.get_html() )
- def init_hex(self, hex):
- cTup = self.hex_to_rgb( hex )
- self.init_rgba( cTup[0], cTup[1], cTup[2], 255 )
+ def init_hex(self, hex):
+ cTup = self.hex_to_rgb( hex )
+ self.init_rgba( cTup[0], cTup[1], cTup[2], 255 )
- def get_int(self):
- return int(self._a * 255) + (int(self._b * 255) << 8) + (int(self._g * 255) << 16) + (int(self._r * 255) << 24)
+ def get_int(self):
+ return int(self._a * 255) + (int(self._b * 255) << 8) + (int(self._g * 255) << 16) + (int(self._r * 255) << 24)
- def rgb_to_hex(self, rgb_tup):
- hexcolor = '#%02x%02x%02x' % rgb_tup
- return hexcolor
+ def rgb_to_hex(self, rgb_tup):
+ hexcolor = '#%02x%02x%02x' % rgb_tup
+ return hexcolor
- def hex_to_rgb(self, h):
- c = eval('0x' + h[1:])
- r = (c >> 16) & 0xFF
- g = (c >> 8) & 0xFF
- b = c & 0xFF
- return (int(r), int(g), int(b)) \ No newline at end of file
+ def hex_to_rgb(self, h):
+ c = eval('0x' + h[1:])
+ r = (c >> 16) & 0xFF
+ g = (c >> 8) & 0xFF
+ b = c & 0xFF
+ return (int(r), int(g), int(b)) \ No newline at end of file
diff --git a/constants.py b/constants.py
index 64fbc4f..0da125a 100644
--- a/constants.py
+++ b/constants.py
@@ -10,345 +10,345 @@ from instance import Instance
from sugar import profile
from color import Color
import utils
-import _camera
+import camerac
import cairo
import pango
import pangocairo
class Constants:
- VERSION = 54
-
- SERVICE = "org.laptop.Record"
- IFACE = SERVICE
- PATH = "/org/laptop/Record"
- activityId = None
-
- recdTitle = "title"
- recdTags = "tags"
- recdTime = "time"
- recdRecorderName = "photographer"
- recdRecorderHash = "recorderHash"
- recdColorStroke = "colorStroke"
- recdColorFill = "colorFill"
- recdHashKey = "hashKey"
- recdBuddy = "buddy"
- recdMediaMd5 = "mediaMd5"
- recdThumbMd5 = "thumbMd5"
- recdMediaBytes = "mediaBytes"
- recdThumbBytes = "thumbBytes"
- recdBase64Thumb = "base64Thumb"
- recdDatastoreId = "datastoreId"
- recdAudioImage = "audioImage"
- recdAlbum = "album"
- recdType = "type"
- recdRecd = "recd"
- recdRecordVersion = "version"
-
- keyName = "name"
- keyMime = "mime"
- keyExt = "ext"
- keyIstr = "istr"
-
- MODE_PHOTO = 0
- MODE_VIDEO = 1
- MODE_AUDIO = 2
- TYPE_PHOTO = MODE_PHOTO
- TYPE_VIDEO = MODE_VIDEO
- TYPE_AUDIO = MODE_AUDIO
-
- TIMER_0 = 0
- TIMER_5 = 5
- TIMER_10 = 10
- TIMERS = []
- TIMERS.append(TIMER_0)
- TIMERS.append(TIMER_5)
- TIMERS.append(TIMER_10)
-
- DURATION_2 = 2
- DURATION_4 = 4
- DURATION_6 = 6
- DURATIONS = []
- DURATIONS.append(DURATION_2)
- DURATIONS.append(DURATION_4)
- DURATIONS.append(DURATION_6)
-
- colorBlack = Color()
- colorBlack.init_rgba( 0, 0, 0, 255 )
- colorWhite = Color()
- colorWhite.init_rgba( 255, 255, 255, 255 )
- colorRed = Color()
- colorRed.init_rgba( 255, 0, 0, 255)
- colorGreen = Color()
- colorGreen.init_rgba( 0, 255, 0, 255)
- colorBlue = Color()
- colorBlue.init_rgba( 0, 0, 255, 255)
- colorButton = Color()
- colorButton.init_gdk( sugar.graphics.style.COLOR_BUTTON_GREY )
-
- gfxPath = os.path.join(activity.get_bundle_path(), "gfx")
- soundClick = os.path.join(gfxPath, 'photoShutter.wav')
-
-
- #defensive method against variables not translated correctly
- def _(s):
- #todo: permanent variable
- istrsTest = {}
- for i in range (0,4):
- istrsTest[str(i)] = str(i)
-
- i = s
- try:
- #test translating the string with many replacements
- i = gt(s)
- test = i % istrsTest
- except:
- #if it doesn't work, revert
- i = s
-
- return i
-
-
- istrActivityName = _('Record')
- istrPhoto = _('Photo')
- istrVideo = _('Video')
- istrAudio = _('Audio')
- istrTimelapse = _('Time Lapse')
- istrAnimation = _('Animation')
- istrPanorama = _('Panorama')
- istrInterview= _('Interview')
- #TRANS: photo by photographer, e.g., "Photo by Mary"
- istrBy = _("%(1)s by %(2)s")
- istrTitle = _('Title:')
- istrRecorder = _('Recorder:')
- istrDate = _('Date:')
- istrTags = _('Tags:')
- istrSaving = _('Saving')
- istrFinishedRecording = _("Finished recording")
- istrHoursMinutesSecondsRemaining = _("%(1)s hours, %(2)s minutes, %(3)s seconds remaining")
- istrMinutesSecondsRemaining = _("%(1)s minutes, %(2)s seconds remaining")
- istrHoursRemaining = _("%(1)s hours remaining")
- istrMinutesRemaining = _("%(1)s minutes remaining")
- istrSecondsRemaining = _("%(1)s seconds remaining")
- istrHours = _("%(1)s hours")
- istrMinutes = _("%(1)s minutes")
- istrSeconds = _("%(1)s seconds")
- istrRemove = _("Remove")
- istrStoppedRecording = _("Stopped recording")
- istrCopyToClipboard = _("Copy to clipboard")
- istrTimer = _("Timer:")
- istrDuration = _("Duration:")
- istrNow = _("Immediate")
- istrPlay = _("Play")
- istrPause = _("Pause")
- istrAddFrame = _("Add frame")
- istrRemoveFrame = _("Remove frame")
- istrFramesPerSecond = _("%(1)s frames per second")
- istrQuality = _("Quality")
- istrDefault = _("Default")
- istrBestQuality = _("Best")
- istrHighQuality = _("High")
- istrLowQuality = _("Low")
- istrLargeFile = _("Large file")
- istrSmallFile = _("Small file")
- istrSilent = _("Silent")
- istrRotate = _("Rotate")
- istrWidth = _("Width")
- istrHeight = _("Height")
- istrClickToTakePicture = _("Click to take picture")
- istrClickToAddPicture = _("Click to add picture")
- #TRANS: Downloading Photo from Mary
- istrDownloadingFrom = _("Downloading %(1)s from %(2)s")
- #TRANS: Cannot download this Photo
- istrCannotDownload = _("Cannot download this %(1)s")
- #TRANS: Save Photo to:
- istrSaveTo = _("Save %(1)s to:")
- istrYourDiskIsFull = _("Your %(1)s is full")
- istrJournal = _("Journal")
- istrUSB = _("USB")
- istrCompactFlash = _("SD Card")
- istrPreferences = _("Preferences")
- istrFreeSpace = _("Free space:")
- #TRANS: 7 photos
- istrNumPhotos = _("%(1)s photos")
- istrBitrate = _("Bitrate")
- istrMaxBitrate = _("Maximum Bitrate")
- istrMinBitrate = _("Minumum Bitrate")
- istrManageBitrate = _("Manage Bitrate")
- istrBorder = _("Border")
- istrCenter = _("Center")
- istrFrames = _("Frames")
- istrKeyframeAuto = _("Automatic keyframe detection")
- istrKeyframeForce = _("Force keyframe")
- istrKeyframeFrequency = _("Keyframe frequency")
- istrKeyframeMinDist = _("Keyframe minimum distance")
- istrKeyframeThreshold = _("Keyframe threshold")
- istrNoiseSensitivity = _("Noise Sensitivity")
- istrQuick = _("Quick")
- istrSharpness = _("Sharpness")
- istrCapacity = _("Capacity")
-
- mediaTypes = {}
- mediaTypes[TYPE_PHOTO] = {keyName:"photo", keyMime:"image/jpeg", keyExt:"jpg", keyIstr:istrPhoto}
- mediaTypes[TYPE_VIDEO] = {keyName:"video", keyMime:"video/ogg", keyExt:"ogg", keyIstr:istrVideo}
- mediaTypes[TYPE_AUDIO] = {keyName:"audio", keyMime:"audio/ogg", keyExt:"ogg", keyIstr:istrAudio}
-
- thumbPhotoSvgData = None
- thumbPhotoSvg = None
- thumbVideoSvg = None
- maxEnlargeSvg = None
- maxReduceSvg = None
- infoOnSvg = None
- xoGuySvgData = None
-
- recImg = None
- recRedImg = None
- recCircleCairo = None
- recInsensitiveImg = None
- recPlayImg = None
- recPauseImg = None
- countdownImgs = {}
-
- dim_CONTROLBAR_HT = 55
-
- keepFreeKbOnXo = 200000
-
- def __init__( self, ca ):
- self.__class__.activityId = ca._activity_id
-
- thumbPhotoSvgPath = os.path.join(self.__class__.gfxPath, 'object-photo.svg')
- thumbPhotoSvgFile = open(thumbPhotoSvgPath, 'r')
- self.__class__.thumbPhotoSvgData = thumbPhotoSvgFile.read()
- self.__class__.thumbPhotoSvg = utils.loadSvg(self.__class__.thumbPhotoSvgData, Instance.colorStroke.hex, Instance.colorFill.hex)
- thumbPhotoSvgFile.close()
-
- thumbVideoSvgPath = os.path.join(self.__class__.gfxPath, 'object-video.svg')
- thumbVideoSvgFile = open(thumbVideoSvgPath, 'r')
- self.__class__.thumbVideoSvgData = thumbVideoSvgFile.read()
- self.__class__.thumbVideoSvg = utils.loadSvg(self.__class__.thumbVideoSvgData, Instance.colorStroke.hex, Instance.colorFill.hex)
- thumbVideoSvgFile.close()
-
- thumbAudioSvgPath = os.path.join(self.__class__.gfxPath, 'object-audio.svg')
- thumbAudioSvgFile = open(thumbAudioSvgPath, 'r')
- self.__class__.thumbAudioSvgData = thumbAudioSvgFile.read()
- self.__class__.thumbAudioSvg = utils.loadSvg(self.__class__.thumbAudioSvgData, Instance.colorStroke.hex, Instance.colorFill.hex)
- thumbAudioSvgFile.close()
-
- maxEnlargeSvgPath = os.path.join(self.__class__.gfxPath, 'max-enlarge.svg')
- maxEnlargeSvgFile = open(maxEnlargeSvgPath, 'r')
- maxEnlargeSvgData = maxEnlargeSvgFile.read()
- self.__class__.maxEnlargeSvg = utils.loadSvg(maxEnlargeSvgData, None, None )
- maxEnlargeSvgFile.close()
-
- maxReduceSvgPath = os.path.join(self.__class__.gfxPath, 'max-reduce.svg')
- maxReduceSvgFile = open(maxReduceSvgPath, 'r')
- maxReduceSvgData = maxReduceSvgFile.read()
- self.__class__.maxReduceSvg = utils.loadSvg(maxReduceSvgData, None, None )
- maxReduceSvgFile.close()
-
- infoOnSvgPath = os.path.join(self.__class__.gfxPath, 'corner-info.svg')
- infoOnSvgFile = open(infoOnSvgPath, 'r')
- infoOnSvgData = infoOnSvgFile.read()
- self.__class__.infoOnSvg = utils.loadSvg(infoOnSvgData, None, None )
- infoOnSvgFile.close()
-
- xoGuySvgPath = os.path.join(self.__class__.gfxPath, 'xo-guy.svg')
- xoGuySvgFile = open(xoGuySvgPath, 'r')
- self.__class__.xoGuySvgData = xoGuySvgFile.read()
- xoGuySvgFile.close()
-
- recFile = os.path.join(self.__class__.gfxPath, 'media-record.png')
- recPixbuf = gtk.gdk.pixbuf_new_from_file(recFile)
- self.__class__.recImg = gtk.Image()
- self.__class__.recImg.set_from_pixbuf( recPixbuf )
-
- recRedFile = os.path.join(self.__class__.gfxPath, 'media-record-red.png')
- recRedPixbuf = gtk.gdk.pixbuf_new_from_file(recRedFile)
- self.__class__.recRedImg = gtk.Image()
- self.__class__.recRedImg.set_from_pixbuf( recRedPixbuf )
-
- recCircleFile = os.path.join(self.__class__.gfxPath, 'media-circle.png')
- recCirclePixbuf = gtk.gdk.pixbuf_new_from_file(recCircleFile)
- self.__class__.recCircleCairo = _camera.cairo_surface_from_gdk_pixbuf(recCirclePixbuf)
-
- recInsFile = os.path.join(self.__class__.gfxPath, 'media-insensitive.png')
- recInsPixbuf = gtk.gdk.pixbuf_new_from_file(recInsFile)
- self.__class__.recInsensitiveImg = gtk.Image()
- self.__class__.recInsensitiveImg.set_from_pixbuf( recInsPixbuf )
-
- fullInsFile = os.path.join(self.__class__.gfxPath, 'full-insensitive.png')
- fullInsPixbuf = gtk.gdk.pixbuf_new_from_file(fullInsFile)
- self.__class__.fullInsensitiveImg = gtk.Image()
- self.__class__.fullInsensitiveImg.set_from_pixbuf( fullInsPixbuf )
-
- recPlayFile = os.path.join(self.__class__.gfxPath, 'media-play.png')
- recPlayPixbuf = gtk.gdk.pixbuf_new_from_file(recPlayFile)
- self.__class__.recPlayImg = gtk.Image()
- self.__class__.recPlayImg.set_from_pixbuf( recPlayPixbuf )
-
- recPauseFile = os.path.join(self.__class__.gfxPath, 'media-pause.png')
- recPausePixbuf = gtk.gdk.pixbuf_new_from_file(recPauseFile)
- self.__class__.recPauseImg = gtk.Image()
- self.__class__.recPauseImg.set_from_pixbuf( recPausePixbuf )
-
- self._ts = self.__class__.TIMERS
- longestTime = self._ts[len(self._ts)-1]
- for i in range (0, longestTime):
- self.createCountdownPng( i )
-
-
- def createCountdownPng(self, num):
- todisk = True
-
- rendered = False
- if (todisk):
- path = os.path.join(Instance.dataPath, str(num)+".png")
- if (os.path.exists(path)):
- rendered = True
-
-
- if (not rendered):
- w = self.__class__.dim_CONTROLBAR_HT
- h = w
- if (todisk):
- cimg = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
- ctx = cairo.Context(cimg)
- else:
- pixmap = gtk.gdk.Pixmap(None, w, h, 24)
- ctx = pixmap.cairo_create()
- ctx.rectangle(0, 0, w, h)
- ctx.set_source_rgb(0, 0, 0)
- ctx.fill()
- x = 0
- y = 4
- ctx.translate(x,y)
- ctx.set_source_surface (self.__class__.recCircleCairo, 0, 0)
- ctx.paint()
- ctx.translate(-x,-y)
-
- ctx.set_source_rgb(255, 255, 255)
- pctx = pangocairo.CairoContext(ctx)
- play = pctx.create_layout()
- font = pango.FontDescription("sans 30")
- play.set_font_description(font)
- play.set_text( ""+str(num) )
- dim = play.get_pixel_extents()
- ctx.translate( -dim[0][0], -dim[0][1] )
- xoff = (w-dim[0][2])/2
- yoff = (h-dim[0][3])/2
- ctx.translate( xoff, yoff )
- ctx.translate( -3, 0 )
- pctx.show_layout(play)
-
- img = gtk.Image()
- if (todisk):
- path = os.path.join(Instance.dataPath, str(num)+".png")
- if (not rendered):
- path = utils.getUniqueFilepath(path, 0)
- cimg.write_to_png(path)
- numPixbuf = gtk.gdk.pixbuf_new_from_file(path)
- img.set_from_pixbuf( numPixbuf )
- else:
- img.set_from_pixmap(pixmap, None)
-
- self.__class__.countdownImgs[int(num)] = img
+ VERSION = 54
+
+ SERVICE = "org.laptop.Record"
+ IFACE = SERVICE
+ PATH = "/org/laptop/Record"
+ activityId = None
+
+ recdTitle = "title"
+ recdTags = "tags"
+ recdTime = "time"
+ recdRecorderName = "photographer"
+ recdRecorderHash = "recorderHash"
+ recdColorStroke = "colorStroke"
+ recdColorFill = "colorFill"
+ recdHashKey = "hashKey"
+ recdBuddy = "buddy"
+ recdMediaMd5 = "mediaMd5"
+ recdThumbMd5 = "thumbMd5"
+ recdMediaBytes = "mediaBytes"
+ recdThumbBytes = "thumbBytes"
+ recdBase64Thumb = "base64Thumb"
+ recdDatastoreId = "datastoreId"
+ recdAudioImage = "audioImage"
+ recdAlbum = "album"
+ recdType = "type"
+ recdRecd = "recd"
+ recdRecordVersion = "version"
+
+ keyName = "name"
+ keyMime = "mime"
+ keyExt = "ext"
+ keyIstr = "istr"
+
+ MODE_PHOTO = 0
+ MODE_VIDEO = 1
+ MODE_AUDIO = 2
+ TYPE_PHOTO = MODE_PHOTO
+ TYPE_VIDEO = MODE_VIDEO
+ TYPE_AUDIO = MODE_AUDIO
+
+ TIMER_0 = 0
+ TIMER_5 = 5
+ TIMER_10 = 10
+ TIMERS = []
+ TIMERS.append(TIMER_0)
+ TIMERS.append(TIMER_5)
+ TIMERS.append(TIMER_10)
+
+ DURATION_2 = 2
+ DURATION_4 = 4
+ DURATION_6 = 6
+ DURATIONS = []
+ DURATIONS.append(DURATION_2)
+ DURATIONS.append(DURATION_4)
+ DURATIONS.append(DURATION_6)
+
+ colorBlack = Color()
+ colorBlack.init_rgba( 0, 0, 0, 255 )
+ colorWhite = Color()
+ colorWhite.init_rgba( 255, 255, 255, 255 )
+ colorRed = Color()
+ colorRed.init_rgba( 255, 0, 0, 255)
+ colorGreen = Color()
+ colorGreen.init_rgba( 0, 255, 0, 255)
+ colorBlue = Color()
+ colorBlue.init_rgba( 0, 0, 255, 255)
+ colorButton = Color()
+ colorButton.init_gdk( sugar.graphics.style.COLOR_BUTTON_GREY )
+
+ gfxPath = os.path.join(activity.get_bundle_path(), "gfx")
+ soundClick = os.path.join(gfxPath, 'photoShutter.wav')
+
+
+ #defensive method against variables not translated correctly
+ def _(s):
+ #todo: permanent variable
+ istrsTest = {}
+ for i in range (0,4):
+ istrsTest[str(i)] = str(i)
+
+ i = s
+ try:
+ #test translating the string with many replacements
+ i = gt(s)
+ test = i % istrsTest
+ except:
+ #if it doesn't work, revert
+ i = s
+
+ return i
+
+
+ istrActivityName = _('Record')
+ istrPhoto = _('Photo')
+ istrVideo = _('Video')
+ istrAudio = _('Audio')
+ istrTimelapse = _('Time Lapse')
+ istrAnimation = _('Animation')
+ istrPanorama = _('Panorama')
+ istrInterview= _('Interview')
+ #TRANS: photo by photographer, e.g., "Photo by Mary"
+ istrBy = _("%(1)s by %(2)s")
+ istrTitle = _('Title:')
+ istrRecorder = _('Recorder:')
+ istrDate = _('Date:')
+ istrTags = _('Tags:')
+ istrSaving = _('Saving')
+ istrFinishedRecording = _("Finished recording")
+ istrHoursMinutesSecondsRemaining = _("%(1)s hours, %(2)s minutes, %(3)s seconds remaining")
+ istrMinutesSecondsRemaining = _("%(1)s minutes, %(2)s seconds remaining")
+ istrHoursRemaining = _("%(1)s hours remaining")
+ istrMinutesRemaining = _("%(1)s minutes remaining")
+ istrSecondsRemaining = _("%(1)s seconds remaining")
+ istrHours = _("%(1)s hours")
+ istrMinutes = _("%(1)s minutes")
+ istrSeconds = _("%(1)s seconds")
+ istrRemove = _("Remove")
+ istrStoppedRecording = _("Stopped recording")
+ istrCopyToClipboard = _("Copy to clipboard")
+ istrTimer = _("Timer:")
+ istrDuration = _("Duration:")
+ istrNow = _("Immediate")
+ istrPlay = _("Play")
+ istrPause = _("Pause")
+ istrAddFrame = _("Add frame")
+ istrRemoveFrame = _("Remove frame")
+ istrFramesPerSecond = _("%(1)s frames per second")
+ istrQuality = _("Quality")
+ istrDefault = _("Default")
+ istrBestQuality = _("Best")
+ istrHighQuality = _("High")
+ istrLowQuality = _("Low")
+ istrLargeFile = _("Large file")
+ istrSmallFile = _("Small file")
+ istrSilent = _("Silent")
+ istrRotate = _("Rotate")
+ istrWidth = _("Width")
+ istrHeight = _("Height")
+ istrClickToTakePicture = _("Click to take picture")
+ istrClickToAddPicture = _("Click to add picture")
+ #TRANS: Downloading Photo from Mary
+ istrDownloadingFrom = _("Downloading %(1)s from %(2)s")
+ #TRANS: Cannot download this Photo
+ istrCannotDownload = _("Cannot download this %(1)s")
+ #TRANS: Save Photo to:
+ istrSaveTo = _("Save %(1)s to:")
+ istrYourDiskIsFull = _("Your %(1)s is full")
+ istrJournal = _("Journal")
+ istrUSB = _("USB")
+ istrCompactFlash = _("SD Card")
+ istrPreferences = _("Preferences")
+ istrFreeSpace = _("Free space:")
+ #TRANS: 7 photos
+ istrNumPhotos = _("%(1)s photos")
+ istrBitrate = _("Bitrate")
+ istrMaxBitrate = _("Maximum Bitrate")
+ istrMinBitrate = _("Minumum Bitrate")
+ istrManageBitrate = _("Manage Bitrate")
+ istrBorder = _("Border")
+ istrCenter = _("Center")
+ istrFrames = _("Frames")
+ istrKeyframeAuto = _("Automatic keyframe detection")
+ istrKeyframeForce = _("Force keyframe")
+ istrKeyframeFrequency = _("Keyframe frequency")
+ istrKeyframeMinDist = _("Keyframe minimum distance")
+ istrKeyframeThreshold = _("Keyframe threshold")
+ istrNoiseSensitivity = _("Noise Sensitivity")
+ istrQuick = _("Quick")
+ istrSharpness = _("Sharpness")
+ istrCapacity = _("Capacity")
+
+ mediaTypes = {}
+ mediaTypes[TYPE_PHOTO] = {keyName:"photo", keyMime:"image/jpeg", keyExt:"jpg", keyIstr:istrPhoto}
+ mediaTypes[TYPE_VIDEO] = {keyName:"video", keyMime:"video/ogg", keyExt:"ogg", keyIstr:istrVideo}
+ mediaTypes[TYPE_AUDIO] = {keyName:"audio", keyMime:"audio/ogg", keyExt:"ogg", keyIstr:istrAudio}
+
+ thumbPhotoSvgData = None
+ thumbPhotoSvg = None
+ thumbVideoSvg = None
+ maxEnlargeSvg = None
+ maxReduceSvg = None
+ infoOnSvg = None
+ xoGuySvgData = None
+
+ recImg = None
+ recRedImg = None
+ recCircleCairo = None
+ recInsensitiveImg = None
+ recPlayImg = None
+ recPauseImg = None
+ countdownImgs = {}
+
+ dim_CONTROLBAR_HT = 55
+
+ keepFreeKbOnXo = 100000
+
+ def __init__( self, ca ):
+ self.__class__.activityId = ca._activity_id
+
+ thumbPhotoSvgPath = os.path.join(self.__class__.gfxPath, 'object-photo.svg')
+ thumbPhotoSvgFile = open(thumbPhotoSvgPath, 'r')
+ self.__class__.thumbPhotoSvgData = thumbPhotoSvgFile.read()
+ self.__class__.thumbPhotoSvg = utils.loadSvg(self.__class__.thumbPhotoSvgData, Instance.colorStroke.hex, Instance.colorFill.hex)
+ thumbPhotoSvgFile.close()
+
+ thumbVideoSvgPath = os.path.join(self.__class__.gfxPath, 'object-video.svg')
+ thumbVideoSvgFile = open(thumbVideoSvgPath, 'r')
+ self.__class__.thumbVideoSvgData = thumbVideoSvgFile.read()
+ self.__class__.thumbVideoSvg = utils.loadSvg(self.__class__.thumbVideoSvgData, Instance.colorStroke.hex, Instance.colorFill.hex)
+ thumbVideoSvgFile.close()
+
+ thumbAudioSvgPath = os.path.join(self.__class__.gfxPath, 'object-audio.svg')
+ thumbAudioSvgFile = open(thumbAudioSvgPath, 'r')
+ self.__class__.thumbAudioSvgData = thumbAudioSvgFile.read()
+ self.__class__.thumbAudioSvg = utils.loadSvg(self.__class__.thumbAudioSvgData, Instance.colorStroke.hex, Instance.colorFill.hex)
+ thumbAudioSvgFile.close()
+
+ maxEnlargeSvgPath = os.path.join(self.__class__.gfxPath, 'max-enlarge.svg')
+ maxEnlargeSvgFile = open(maxEnlargeSvgPath, 'r')
+ maxEnlargeSvgData = maxEnlargeSvgFile.read()
+ self.__class__.maxEnlargeSvg = utils.loadSvg(maxEnlargeSvgData, None, None )
+ maxEnlargeSvgFile.close()
+
+ maxReduceSvgPath = os.path.join(self.__class__.gfxPath, 'max-reduce.svg')
+ maxReduceSvgFile = open(maxReduceSvgPath, 'r')
+ maxReduceSvgData = maxReduceSvgFile.read()
+ self.__class__.maxReduceSvg = utils.loadSvg(maxReduceSvgData, None, None )
+ maxReduceSvgFile.close()
+
+ infoOnSvgPath = os.path.join(self.__class__.gfxPath, 'corner-info.svg')
+ infoOnSvgFile = open(infoOnSvgPath, 'r')
+ infoOnSvgData = infoOnSvgFile.read()
+ self.__class__.infoOnSvg = utils.loadSvg(infoOnSvgData, None, None )
+ infoOnSvgFile.close()
+
+ xoGuySvgPath = os.path.join(self.__class__.gfxPath, 'xo-guy.svg')
+ xoGuySvgFile = open(xoGuySvgPath, 'r')
+ self.__class__.xoGuySvgData = xoGuySvgFile.read()
+ xoGuySvgFile.close()
+
+ recFile = os.path.join(self.__class__.gfxPath, 'media-record.png')
+ recPixbuf = gtk.gdk.pixbuf_new_from_file(recFile)
+ self.__class__.recImg = gtk.Image()
+ self.__class__.recImg.set_from_pixbuf( recPixbuf )
+
+ recRedFile = os.path.join(self.__class__.gfxPath, 'media-record-red.png')
+ recRedPixbuf = gtk.gdk.pixbuf_new_from_file(recRedFile)
+ self.__class__.recRedImg = gtk.Image()
+ self.__class__.recRedImg.set_from_pixbuf( recRedPixbuf )
+
+ recCircleFile = os.path.join(self.__class__.gfxPath, 'media-circle.png')
+ recCirclePixbuf = gtk.gdk.pixbuf_new_from_file(recCircleFile)
+ self.__class__.recCircleCairo = camerac.cairo_surface_from_gdk_pixbuf(recCirclePixbuf)
+
+ recInsFile = os.path.join(self.__class__.gfxPath, 'media-insensitive.png')
+ recInsPixbuf = gtk.gdk.pixbuf_new_from_file(recInsFile)
+ self.__class__.recInsensitiveImg = gtk.Image()
+ self.__class__.recInsensitiveImg.set_from_pixbuf( recInsPixbuf )
+
+ fullInsFile = os.path.join(self.__class__.gfxPath, 'full-insensitive.png')
+ fullInsPixbuf = gtk.gdk.pixbuf_new_from_file(fullInsFile)
+ self.__class__.fullInsensitiveImg = gtk.Image()
+ self.__class__.fullInsensitiveImg.set_from_pixbuf( fullInsPixbuf )
+
+ recPlayFile = os.path.join(self.__class__.gfxPath, 'media-play.png')
+ recPlayPixbuf = gtk.gdk.pixbuf_new_from_file(recPlayFile)
+ self.__class__.recPlayImg = gtk.Image()
+ self.__class__.recPlayImg.set_from_pixbuf( recPlayPixbuf )
+
+ recPauseFile = os.path.join(self.__class__.gfxPath, 'media-pause.png')
+ recPausePixbuf = gtk.gdk.pixbuf_new_from_file(recPauseFile)
+ self.__class__.recPauseImg = gtk.Image()
+ self.__class__.recPauseImg.set_from_pixbuf( recPausePixbuf )
+
+ self._ts = self.__class__.TIMERS
+ longestTime = self._ts[len(self._ts)-1]
+ for i in range (0, longestTime):
+ self.createCountdownPng( i )
+
+
+ def createCountdownPng(self, num):
+ todisk = True
+
+ rendered = False
+ if (todisk):
+ path = os.path.join(Instance.dataPath, str(num)+".png")
+ if (os.path.exists(path)):
+ rendered = True
+
+
+ if (not rendered):
+ w = self.__class__.dim_CONTROLBAR_HT
+ h = w
+ if (todisk):
+ cimg = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
+ ctx = cairo.Context(cimg)
+ else:
+ pixmap = gtk.gdk.Pixmap(None, w, h, 24)
+ ctx = pixmap.cairo_create()
+ ctx.rectangle(0, 0, w, h)
+ ctx.set_source_rgb(0, 0, 0)
+ ctx.fill()
+ x = 0
+ y = 4
+ ctx.translate(x,y)
+ ctx.set_source_surface (self.__class__.recCircleCairo, 0, 0)
+ ctx.paint()
+ ctx.translate(-x,-y)
+
+ ctx.set_source_rgb(255, 255, 255)
+ pctx = pangocairo.CairoContext(ctx)
+ play = pctx.create_layout()
+ font = pango.FontDescription("sans 30")
+ play.set_font_description(font)
+ play.set_text( ""+str(num) )
+ dim = play.get_pixel_extents()
+ ctx.translate( -dim[0][0], -dim[0][1] )
+ xoff = (w-dim[0][2])/2
+ yoff = (h-dim[0][3])/2
+ ctx.translate( xoff, yoff )
+ ctx.translate( -3, 0 )
+ pctx.show_layout(play)
+
+ img = gtk.Image()
+ if (todisk):
+ path = os.path.join(Instance.dataPath, str(num)+".png")
+ if (not rendered):
+ path = utils.getUniqueFilepath(path, 0)
+ cimg.write_to_png(path)
+ numPixbuf = gtk.gdk.pixbuf_new_from_file(path)
+ img.set_from_pixbuf( numPixbuf )
+ else:
+ img.set_from_pixmap(pixmap, None)
+
+ self.__class__.countdownImgs[int(num)] = img
diff --git a/glive.py b/glive.py
index ae7480c..99d6b7a 100644
--- a/glive.py
+++ b/glive.py
@@ -18,541 +18,440 @@
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
-
+import re
import os
import gtk
import pygtk
pygtk.require('2.0')
-import sys
import gst
-import gst.interfaces
import pygst
pygst.require('0.10')
import time
-import threading
import gobject
gobject.threads_init()
+import logging
+logger = logging.getLogger('record:glive.py')
+
+from sugar.activity.activity import get_activity_root
+
from instance import Instance
from constants import Constants
-import record
import utils
import ui
-class Glive:
- def __init__(self, pca):
- self.window = None
- self.ca = pca
- self._eos_cb = None
-
- self.playing = False
- self.picExposureOpen = False
-
- self.AUDIO_TRANSCODE_ID = 0
- self.TRANSCODE_ID = 0
- self.VIDEO_TRANSCODE_ID = 0
-
- self.PHOTO_MODE_PHOTO = 0
- self.PHOTO_MODE_AUDIO = 1
-
- self.TRANSCODE_UPDATE_INTERVAL = 200
-
-
- self.VIDEO_WIDTH_SMALL = 160
- self.VIDEO_HEIGHT_SMALL = 120
- self.VIDEO_FRAMERATE_SMALL = 10
-
- self.VIDEO_WIDTH_LARGE = 200
- self.VIDEO_HEIGHT_LARGE = 150
- self.VIDEO_FRAMERATE_SMALL = 10
-
- self.pipeline = gst.Pipeline("my-pipeline")
- self.createPhotoBin()
- self.createAudioBin()
- self.createVideoBin()
- self.createPipeline()
-
- self.thumbPipes = []
- self.muxPipes = []
-
- bus = self.pipeline.get_bus()
- bus.enable_sync_message_emission()
- bus.add_signal_watch()
- self.SYNC_ID = bus.connect('sync-message::element', self._onSyncMessageCb)
- self.MESSAGE_ID = bus.connect('message', self._onMessageCb)
-
- def createPhotoBin ( self ):
- queue = gst.element_factory_make("queue", "pbqueue")
- queue.set_property("leaky", True)
- queue.set_property("max-size-buffers", 1)
-
- colorspace = gst.element_factory_make("ffmpegcolorspace", "pbcolorspace")
- jpeg = gst.element_factory_make("jpegenc", "pbjpeg")
-
- sink = gst.element_factory_make("fakesink", "pbsink")
- self.HANDOFF_ID = sink.connect("handoff", self.copyPic)
- sink.set_property("signal-handoffs", True)
-
- self.photobin = gst.Bin("photobin")
- self.photobin.add(queue, colorspace, jpeg, sink)
-
- gst.element_link_many(queue, colorspace, jpeg, sink)
-
- pad = queue.get_static_pad("sink")
- self.photobin.add_pad(gst.GhostPad("sink", pad))
-
- def createAudioBin ( self ):
- src = gst.element_factory_make("alsasrc", "absrc")
- srccaps = gst.Caps("audio/x-raw-int,rate=16000,channels=1,depth=16")
-
- enc = gst.element_factory_make("wavenc", "abenc")
-
- sink = gst.element_factory_make("filesink", "absink")
- sink.set_property("location", os.path.join(Instance.instancePath, "output.wav"))
-
- self.audiobin = gst.Bin("audiobin")
- self.audiobin.add(src, enc, sink)
-
- src.link(enc, srccaps)
- enc.link(sink)
-
- def createVideoBin ( self ):
- queue = gst.element_factory_make("queue", "vbqueue")
-
- rate = gst.element_factory_make("videorate", "vbrate")
- ratecaps = gst.Caps('video/x-raw-yuv,framerate='+str(self.VIDEO_FRAMERATE_SMALL)+'/1')
+TMP_OGV = os.path.join(get_activity_root(), 'instance', 'output.ogv')
+TMP_OGG = os.path.join(get_activity_root(), 'instance', 'output.ogg')
+TMP_WAV = os.path.join(get_activity_root(), 'instance', 'output.wav')
- scale = gst.element_factory_make("videoscale", "vbscale")
- scalecaps = gst.Caps('video/x-raw-yuv,width='+str(self.VIDEO_WIDTH_SMALL)+',height='+str(self.VIDEO_HEIGHT_SMALL))
+PLAYBACK_WIDTH = 640
+PLAYBACK_HEIGHT = 480
- colorspace = gst.element_factory_make("ffmpegcolorspace", "vbcolorspace")
-
- enc = gst.element_factory_make("theoraenc", "vbenc")
- enc.set_property("quality", 16)
-
- mux = gst.element_factory_make("oggmux", "vbmux")
-
- sink = gst.element_factory_make("filesink", "vbfile")
- sink.set_property("location", os.path.join(Instance.instancePath, "output.ogg"))
-
- self.videobin = gst.Bin("videobin")
- self.videobin.add(queue, rate, scale, colorspace, enc, mux, sink)
-
- queue.link(rate)
- rate.link(scale, ratecaps)
- scale.link(colorspace, scalecaps)
- gst.element_link_many(colorspace, enc, mux, sink)
-
- pad = queue.get_static_pad("sink")
- self.videobin.add_pad(gst.GhostPad("sink", pad))
-
- def createPipeline ( self ):
- src = gst.element_factory_make("v4l2src", "camsrc")
- try:
- # old gst-plugins-good does not have this property
- src.set_property("queue-size", 2)
- except:
- pass
-
- tee = gst.element_factory_make("tee", "tee")
- queue = gst.element_factory_make("queue", "dispqueue")
- xvsink = gst.element_factory_make("xvimagesink", "xvsink")
- self.pipeline.add(src, tee, queue, xvsink)
- gst.element_link_many(src, tee, queue, xvsink)
-
- def thumbPipe(self):
- return self.thumbPipes[ len(self.thumbPipes)-1 ]
-
-
- def thumbEl(self, name):
- return self.thumbPipe().get_by_name(name)
-
-
- def muxPipe(self):
- return self.muxPipes[ len(self.muxPipes)-1 ]
-
-
- def muxEl(self, name):
- return self.muxPipe().get_by_name(name)
-
-
- def play(self):
- self.pipeline.set_state(gst.STATE_PLAYING)
- self.playing = True
-
- def pause(self):
- self.pipeline.set_state(gst.STATE_PAUSED)
- self.playing = False
-
-
- def stop(self):
- self.pipeline.set_state(gst.STATE_NULL)
- self.playing = False
-
- def is_playing(self):
- return self.playing
-
- def idlePlayElement(self, element):
- element.set_state(gst.STATE_PLAYING)
- return False
-
- def stopRecordingAudio( self ):
- self.audiobin.set_state(gst.STATE_NULL)
- self.pipeline.remove(self.audiobin)
- gobject.idle_add( self.stoppedRecordingAudio )
-
-
- def stoppedRecordingVideo(self):
- if ( len(self.thumbPipes) > 0 ):
- thumbline = self.thumbPipes[len(self.thumbPipes)-1]
- thumbline.get_by_name('thumbFakesink').disconnect(self.THUMB_HANDOFF_ID)
-
- oggFilepath = os.path.join(Instance.instancePath, "output.ogg") #ogv
- if (not os.path.exists(oggFilepath)):
- self.record = False
- self.ca.m.cannotSaveVideo()
- self.ca.m.stoppedRecordingVideo()
- return
- oggSize = os.path.getsize(oggFilepath)
- if (oggSize <= 0):
- self.record = False
- self.ca.m.cannotSaveVideo()
- self.ca.m.stoppedRecordingVideo()
- return
-
- line = 'filesrc location=' + str(oggFilepath) + ' name=thumbFilesrc ! oggdemux name=thumbOggdemux ! theoradec name=thumbTheoradec ! tee name=thumbTee ! queue name=thumbQueue ! ffmpegcolorspace name=thumbFfmpegcolorspace ! jpegenc name=thumbJPegenc ! fakesink name=thumbFakesink'
- thumbline = gst.parse_launch(line)
- thumbQueue = thumbline.get_by_name('thumbQueue')
- thumbQueue.set_property("leaky", True)
- thumbQueue.set_property("max-size-buffers", 1)
- thumbTee = thumbline.get_by_name('thumbTee')
- thumbFakesink = thumbline.get_by_name('thumbFakesink')
- self.THUMB_HANDOFF_ID = thumbFakesink.connect("handoff", self.copyThumbPic)
- thumbFakesink.set_property("signal-handoffs", True)
- self.thumbPipes.append(thumbline)
- self.thumbExposureOpen = True
- gobject.idle_add( self.idlePlayElement, thumbline )
-
-
- def stoppedRecordingAudio( self ):
- record.Record.log.debug("stoppedRecordingAudio")
- if (self.audioPixbuf != None):
- audioFilepath = os.path.join(Instance.instancePath, "output.wav")#self.el("audioFilesink").get_property("location")
- if (not os.path.exists(audioFilepath)):
- self.record = False
- self.audio = False
- self.ca.m.cannotSaveVideo()
- return
- wavSize = os.path.getsize(audioFilepath)
- if (wavSize <= 0):
- self.record = False
- self.ca.m.cannotSaveVideo()
- return
-
- self.ca.ui.setPostProcessPixBuf(self.audioPixbuf)
-
- line = 'filesrc location=' + str(audioFilepath) + ' name=audioFilesrc ! wavparse name=audioWavparse ! audioconvert name=audioAudioconvert ! vorbisenc name=audioVorbisenc ! oggmux name=audioOggmux ! filesink name=audioFilesink'
- audioline = gst.parse_launch(line)
-
- taglist = self.getTags(Constants.TYPE_AUDIO)
- base64AudioSnapshot = utils.getStringFromPixbuf(self.audioPixbuf)
- taglist[gst.TAG_EXTENDED_COMMENT] = "coverart="+str(base64AudioSnapshot)
- vorbisEnc = audioline.get_by_name('audioVorbisenc')
- vorbisEnc.merge_tags(taglist, gst.TAG_MERGE_REPLACE_ALL)
-
- audioFilesink = audioline.get_by_name('audioFilesink')
- audioOggFilepath = os.path.join(Instance.instancePath, "output.ogg")
- audioFilesink.set_property("location", audioOggFilepath )
-
- audioBus = audioline.get_bus()
- audioBus.add_signal_watch()
- self.AUDIO_TRANSCODE_ID = audioBus.connect('message', self._onMuxedAudioMessageCb, audioline)
- self.TRANSCODE_ID = gobject.timeout_add(self.TRANSCODE_UPDATE_INTERVAL, self._transcodeUpdateCb, audioline)
- gobject.idle_add( self.idlePlayElement, audioline )
- else:
- self.record = False
- self.audio = False
- self.ca.m.cannotSaveVideo()
-
-
- def getTags( self, type ):
- tl = gst.TagList()
- tl[gst.TAG_ARTIST] = str(Instance.nickName)
- tl[gst.TAG_COMMENT] = "olpc"
- #this is unfortunately, unreliable
- #record.Record.log.debug("self.ca.metadata['title']->" + str(self.ca.metadata['title']) )
- tl[gst.TAG_ALBUM] = "olpc" #self.ca.metadata['title']
- tl[gst.TAG_DATE] = utils.getDateString(int(time.time()))
- stringType = Constants.mediaTypes[type][Constants.keyIstr]
- tl[gst.TAG_TITLE] = Constants.istrBy % {"1":stringType, "2":str(Instance.nickName)}
- return tl
-
- def blockedCb(self, x, y, z):
- pass
-
- def _takePhoto(self):
- if self.picExposureOpen:
- return
-
- self.picExposureOpen = True
- pad = self.photobin.get_static_pad("sink")
- pad.set_blocked_async(True, self.blockedCb, None)
- self.pipeline.add(self.photobin)
- self.photobin.set_state(gst.STATE_PLAYING)
- self.pipeline.get_by_name("tee").link(self.photobin)
- pad.set_blocked_async(False, self.blockedCb, None)
-
- def takePhoto(self):
- self.photoMode = self.PHOTO_MODE_PHOTO
- self._takePhoto()
-
- def copyPic(self, fsink, buffer, pad, user_data=None):
- if not self.picExposureOpen:
- return
-
- pad = self.photobin.get_static_pad("sink")
- pad.set_blocked_async(True, self.blockedCb, None)
- self.pipeline.get_by_name("tee").unlink(self.photobin)
- self.pipeline.remove(self.photobin)
- pad.set_blocked_async(False, self.blockedCb, None)
-
- self.picExposureOpen = False
- pic = gtk.gdk.pixbuf_loader_new_with_mime_type("image/jpeg")
- pic.write( buffer )
- pic.close()
- pixBuf = pic.get_pixbuf()
- del pic
-
- self.savePhoto( pixBuf )
-
-
- def savePhoto(self, pixbuf):
- if self.photoMode == self.PHOTO_MODE_AUDIO:
- self.audioPixbuf = pixbuf
- else:
- self.ca.m.savePhoto(pixbuf)
-
-
- def startRecordingVideo(self):
- self.record = True
- self.audio = True
-
- # It would be nicer to connect the video/audio-recording elements
- # without stopping the pipeline. However, that seems to cause a
- # very long delay at the start of the video recording where the first
- # frame is 'frozen' for several seconds. MikeS from #gstreamer
- # suggested that the videorate element might not be receiving a
- # "new segment" signal soon enough.
- #
- # Stopping the pipeline while we reshuffle neatly works around this
- # with minimal user experience impact.
- self.pipeline.set_state(gst.STATE_NULL)
- self.pipeline.add(self.videobin)
- self.pipeline.get_by_name("tee").link(self.videobin)
- self.pipeline.add(self.audiobin)
- self.pipeline.set_state(gst.STATE_PLAYING)
-
- def startRecordingAudio(self):
- self.audioPixbuf = None
-
- self.photoMode = self.PHOTO_MODE_AUDIO
- self._takePhoto()
-
- self.record = True
- self.pipeline.add(self.audiobin)
- self.audiobin.set_state(gst.STATE_PLAYING)
-
- def stopRecordingVideo(self):
- # Similarly to as when we start recording, we also stop the pipeline
- # while we are adjusting the pipeline to stop recording. If we do
- # it on-the-fly, the following video live feed to the screen becomes
- # several seconds delayed. Weird!
- self._eos_cb = self.stopRecordingVideoEOS
- self.pipeline.get_by_name('camsrc').send_event(gst.event_new_eos())
- self.audiobin.get_by_name('absrc').send_event(gst.event_new_eos())
-
- def stopRecordingVideoEOS(self):
- self.pipeline.set_state(gst.STATE_NULL)
- self.pipeline.get_by_name("tee").unlink(self.videobin)
- self.pipeline.remove(self.videobin)
- self.pipeline.remove(self.audiobin)
- self.pipeline.set_state(gst.STATE_PLAYING)
- gobject.idle_add( self.stoppedRecordingVideo )
-
-
- def copyThumbPic(self, fsink, buffer, pad, user_data=None):
- if (self.thumbExposureOpen):
- self.thumbExposureOpen = False
- pic = gtk.gdk.pixbuf_loader_new_with_mime_type("image/jpeg")
- pic.write(buffer)
- pic.close()
- self.thumbBuf = pic.get_pixbuf()
- del pic
- self.thumbEl('thumbTee').unlink(self.thumbEl('thumbQueue'))
-
- oggFilepath = os.path.join(Instance.instancePath, "output.ogg") #ogv
- if (self.audio):
- self.ca.ui.setPostProcessPixBuf(self.thumbBuf)
-
- wavFilepath = os.path.join(Instance.instancePath, "output.wav")
- muxFilepath = os.path.join(Instance.instancePath, "mux.ogg") #ogv
-
- muxline = gst.parse_launch('filesrc location=' + str(oggFilepath) + ' name=muxVideoFilesrc ! oggdemux name=muxOggdemux ! theoradec name=muxTheoradec ! theoraenc name=muxTheoraenc ! oggmux name=muxOggmux ! filesink location=' + str(muxFilepath) + ' name=muxFilesink filesrc location=' + str(wavFilepath) + ' name=muxAudioFilesrc ! wavparse name=muxWavparse ! audioconvert name=muxAudioconvert ! vorbisenc name=muxVorbisenc ! muxOggmux.')
- taglist = self.getTags(Constants.TYPE_VIDEO)
- vorbisEnc = muxline.get_by_name('muxVorbisenc')
- vorbisEnc.merge_tags(taglist, gst.TAG_MERGE_REPLACE_ALL)
-
- muxBus = muxline.get_bus()
- muxBus.add_signal_watch()
- self.VIDEO_TRANSCODE_ID = muxBus.connect('message', self._onMuxedVideoMessageCb, muxline)
- self.muxPipes.append(muxline)
- #add a listener here to monitor % of transcoding...
- self.TRANSCODE_ID = gobject.timeout_add(self.TRANSCODE_UPDATE_INTERVAL, self._transcodeUpdateCb, muxline)
- muxline.set_state(gst.STATE_PLAYING)
- else:
- self.record = False
- self.audio = False
- self.ca.m.saveVideo(self.thumbBuf, str(oggFilepath), self.VIDEO_WIDTH_SMALL, self.VIDEO_HEIGHT_SMALL)
- self.ca.m.stoppedRecordingVideo()
-
-
- def _transcodeUpdateCb( self, pipe ):
- position, duration = self.queryPosition( pipe )
- if position != gst.CLOCK_TIME_NONE:
- value = position * 100.0 / duration
- value = value/100.0
- self.ca.ui.progressWindow.updateProgress(value, Constants.istrSaving)
- return True
-
-
- def queryPosition( self, pipe ):
- try:
- position, format = pipe.query_position(gst.FORMAT_TIME)
- except:
- position = gst.CLOCK_TIME_NONE
-
- try:
- duration, format = pipe.query_duration(gst.FORMAT_TIME)
- except:
- duration = gst.CLOCK_TIME_NONE
-
- return (position, duration)
-
-
- def _onMuxedVideoMessageCb(self, bus, message, pipe):
- t = message.type
- if (t == gst.MESSAGE_EOS):
- self.record = False
- self.audio = False
- gobject.source_remove(self.VIDEO_TRANSCODE_ID)
- self.VIDEO_TRANSCODE_ID = 0
- gobject.source_remove(self.TRANSCODE_ID)
- self.TRANSCODE_ID = 0
- pipe.set_state(gst.STATE_NULL)
- pipe.get_bus().remove_signal_watch()
- pipe.get_bus().disable_sync_message_emission()
-
- wavFilepath = os.path.join(Instance.instancePath, "output.wav")
- oggFilepath = os.path.join(Instance.instancePath, "output.ogg") #ogv
- muxFilepath = os.path.join(Instance.instancePath, "mux.ogg") #ogv
- os.remove( wavFilepath )
- os.remove( oggFilepath )
- self.ca.m.saveVideo(self.thumbBuf, str(muxFilepath), self.VIDEO_WIDTH_SMALL, self.VIDEO_HEIGHT_SMALL)
- self.ca.m.stoppedRecordingVideo()
- return False
- else:
- return True
-
-
- def _onMuxedAudioMessageCb(self, bus, message, pipe):
- t = message.type
- if (t == gst.MESSAGE_EOS):
- record.Record.log.debug("audio gst.MESSAGE_EOS")
- self.record = False
- self.audio = False
- gobject.source_remove(self.AUDIO_TRANSCODE_ID)
- self.AUDIO_TRANSCODE_ID = 0
- gobject.source_remove(self.TRANSCODE_ID)
- self.TRANSCODE_ID = 0
- pipe.set_state(gst.STATE_NULL)
- pipe.get_bus().remove_signal_watch()
- pipe.get_bus().disable_sync_message_emission()
-
- wavFilepath = os.path.join(Instance.instancePath, "output.wav")
- oggFilepath = os.path.join(Instance.instancePath, "output.ogg")
- os.remove( wavFilepath )
- self.ca.m.saveAudio(oggFilepath, self.audioPixbuf)
- return False
- else:
- return True
-
-
- def _onSyncMessageCb(self, bus, message):
- if message.structure is None:
- return
- if message.structure.get_name() == 'prepare-xwindow-id':
- self.window.set_sink(message.src)
- message.src.set_property('force-aspect-ratio', True)
-
-
- def _onMessageCb(self, bus, message):
- t = message.type
- if t == gst.MESSAGE_EOS:
- if self._eos_cb:
- cb = self._eos_cb
- self._eos_cb = None
- cb()
- elif t == gst.MESSAGE_ERROR:
- #todo: if we come out of suspend/resume with errors, then get us back up and running...
- #todo: handle "No space left on the resource.gstfilesink.c"
- #err, debug = message.parse_error()
- pass
-
- def abandonMedia(self):
- self.stop()
-
- if (self.AUDIO_TRANSCODE_ID != 0):
- gobject.source_remove(self.AUDIO_TRANSCODE_ID)
- self.AUDIO_TRANSCODE_ID = 0
- if (self.TRANSCODE_ID != 0):
- gobject.source_remove(self.TRANSCODE_ID)
- self.TRANSCODE_ID = 0
- if (self.VIDEO_TRANSCODE_ID != 0):
- gobject.source_remove(self.VIDEO_TRANSCODE_ID)
- self.VIDEO_TRANSCODE_ID = 0
-
- wavFilepath = os.path.join(Instance.instancePath, "output.wav")
- if (os.path.exists(wavFilepath)):
- os.remove(wavFilepath)
- oggFilepath = os.path.join(Instance.instancePath, "output.ogg") #ogv
- if (os.path.exists(oggFilepath)):
- os.remove(oggFilepath)
- muxFilepath = os.path.join(Instance.instancePath, "mux.ogg") #ogv
- if (os.path.exists(muxFilepath)):
- os.remove(muxFilepath)
+OGG_TRAITS = {
+ 0: { 'width': 160, 'height': 120, 'quality': 16 },
+ 1: { 'width': 400, 'height': 300, 'quality': 16 },
+ 2: { 'width': 640, 'height': 480, 'quality': 32 } }
+class Glive:
+ def play(self):
+ logger.debug('play')
+
+ if not self.play_pipe:
+ self.src_str = \
+ 'v4l2src ' \
+ '! video/x-raw-yuv,width=%s,height=%s ' \
+ % (PLAYBACK_WIDTH, PLAYBACK_HEIGHT)
+ self.play_str = \
+ 'xvimagesink force-aspect-ratio=true name=xsink'
+
+ self.play_pipe = gst.parse_launch(
+ '%s ' \
+ '! valve name=valve ' \
+ '! queue name=queue ' \
+ '! %s' \
+ % (self.src_str, self.play_str))
+ self.valve = self.play_pipe.get_by_name('valve')
+
+ def message_cb(bus, message):
+ if message.type == gst.MESSAGE_ERROR:
+ err, debug = message.parse_error()
+ logger.error('play_pipe: %s %s' % (err, debug))
+
+ if not self.fallback:
+ logger.warning('use fallback_bin')
+ self.fallback = True
+
+ self.play_str = \
+ 'ffmpegcolorspace ' \
+ '! ximagesink force-aspect-ratio=true ' \
+ ' name=xsink'
+
+ self.play_pipe.remove(
+ self.play_pipe.get_by_name('xsink'))
+
+ c = gst.element_factory_make('ffmpegcolorspace')
+ s = gst.element_factory_make('ximagesink', 'xsink')
+ s.props.force_aspect_ratio = True
+
+ self.play_pipe.add(c, s)
+ gst.element_link_many(
+ self.play_pipe.get_by_name('queue'), c, s)
+
+ if [i for i in self.pipeline.get_state() \
+ if id(i) == id(gst.STATE_PLAYING)]:
+ self.pipeline = None
+ self._switch_pipe(self.play_pipe)
+
+ bus = self.play_pipe.get_bus()
+ bus.add_signal_watch()
+ bus.connect('message', message_cb)
+
+ self._switch_pipe(self.play_pipe)
+
+ def thumb_play(self, use_fallback=False):
+ if not self.fallback and not use_fallback:
+ # use xv to scale video
+ self.play()
+ return
+
+ logger.debug('thumb_play')
+
+ if not self.fallback_pipe:
+ self.fallback_pipe = gst.parse_launch(
+ '%s ' \
+ '! queue ' \
+ '! videoscale ' \
+ '! video/x-raw-yuv,width=%s,height=%s ' \
+ '! ffmpegcolorspace ' \
+ '! ximagesink force-aspect-ratio=true name=xsink' \
+ % (self.src_str, ui.UI.dim_PIPW, ui.UI.dim_PIPH))
+
+ def message_cb(bus, message):
+ if message.type == gst.MESSAGE_ERROR:
+ err, debug = message.parse_error()
+ logger.error('fallback_pipe: %s %s' % (err, debug))
+
+ bus = self.fallback_pipe.get_bus()
+ bus.add_signal_watch()
+ bus.connect('message', message_cb)
+
+ self._switch_pipe(self.fallback_pipe)
+
+ def pause(self):
+ logger.debug('pause')
+ if self.pipeline:
+ self.pipeline.set_state(gst.STATE_PAUSED)
+
+ def stop(self):
+ logger.debug('stop')
+ if self.pipeline:
+ self.pipeline.set_state(gst.STATE_NULL)
+
+ def takePhoto(self, after_photo_cb=None):
+ logger.debug('takePhoto')
+
+ if not self.photo:
+ def sink_handoff(sink, buffer, pad, self):
+ sink.props.signal_handoffs = False
+
+ pixbuf = gtk.gdk.pixbuf_loader_new_with_mime_type('image/jpeg')
+ pixbuf.write(buffer)
+ pixbuf.close()
+
+ structure = gst.Structure('record.photo')
+ structure['pixbuf'] = pixbuf.get_pixbuf()
+ msg = gst.message_new_custom(gst.MESSAGE_APPLICATION, sink,
+ structure)
+ self.play_pipe.get_bus().post(msg)
+
+ self.photo = gst.element_factory_make('ffmpegcolorspace')
+ self.photo_jpegenc = gst.element_factory_make('jpegenc')
+ self.photo_sink = gst.element_factory_make('fakesink')
+ self.photo_sink.connect('handoff', sink_handoff, self)
+
+ def message_cb(bus, message, self):
+ if message.type == gst.MESSAGE_APPLICATION \
+ and message.structure.get_name() == 'record.photo':
+ self.valve.props.drop = True
+ self.play_pipe.remove(self.photo)
+ self.play_pipe.remove(self.photo_jpegenc)
+ self.play_pipe.remove(self.photo_sink)
+ self.valve.link(self.play_pipe.get_by_name('queue'))
+ self.valve.props.drop = False
+ self.after_photo_cb(self, message.structure['pixbuf'])
+
+ bus = self.play_pipe.get_bus()
+ bus.add_signal_watch()
+ bus.connect('message', message_cb, self)
+
+ def process_cb(self, pixbuf):
+ self.ca.m.savePhoto(pixbuf)
+ self._switch_pipe(self.play_pipe)
+
+ self.after_photo_cb = after_photo_cb and after_photo_cb or process_cb
+
+ self.valve.props.drop = True
+ self.valve.unlink(self.play_pipe.get_by_name('queue'))
+ self.play_pipe.add(self.photo, self.photo_jpegenc, self.photo_sink)
+ gst.element_link_many(self.valve, self.photo, self.photo_jpegenc,
+ self.photo_sink)
+ self.photo_sink.props.signal_handoffs = True
+ self.valve.props.drop = False
+
+ self._switch_pipe(self.play_pipe)
+
+ def startRecordingVideo(self, quality):
+ logger.debug('startRecordingVideo quality=%s' % quality)
+
+ if not self.video_pipe or quality != self.ogg_quality:
+ self.video_pipe = gst.parse_launch( \
+ '%s ' \
+ '! tee name=tee ' \
+ 'tee.! queue ! %s ' \
+ 'tee.! queue ' \
+ '! ffmpegcolorspace ' \
+ '! videorate skip_to_first=true ' \
+ '! video/x-raw-yuv,framerate=10/1 ' \
+ '! videoscale ' \
+ '! video/x-raw-yuv,width=%s,height=%s ' \
+ '! theoraenc quality=%s ' \
+ '! oggmux ' \
+ '! filesink location=%s ' \
+ 'alsasrc ' \
+ '! queue ' \
+ '! audio/x-raw-int,rate=16000,channels=1,depth=16 ' \
+ '! wavenc ' \
+ '! filesink location=%s ' \
+ % (self.src_str, self.play_str,
+ OGG_TRAITS[quality]['width'],
+ OGG_TRAITS[quality]['height'],
+ OGG_TRAITS[quality]['quality'],
+ TMP_OGV, TMP_WAV))
+
+ def message_cb(bus, message, self):
+ if message.type == gst.MESSAGE_ERROR:
+ err, debug = message.parse_error()
+ logger.error('video_pipe: %s %s' % (err, debug))
+
+ bus = self.video_pipe.get_bus()
+ bus.add_signal_watch()
+ bus.connect('message', message_cb, self)
+
+ def process_cb(self, pixbuf):
+ self.pixbuf = pixbuf
+ self._switch_pipe(self.video_pipe)
+
+ self.ogg_quality = quality
+ # take photo first
+ self.takePhoto(process_cb)
+
+ def stopRecordingVideo(self):
+ logger.debug('stopRecordingVideo')
+
+ self._switch_pipe(self.play_pipe)
+
+ if not os.path.exists(TMP_OGV) \
+ or not os.path.exists(TMP_WAV):
+ self.ca.m.cannotSaveVideo()
+ self.ca.m.stoppedRecordingVideo()
+ return
+
+ if os.path.getsize(TMP_OGV) <= 0 \
+ or os.path.getsize(TMP_WAV) <= 0:
+ self.ca.m.cannotSaveVideo()
+ self.ca.m.stoppedRecordingVideo()
+ return
+
+ if self.mux_pipe:
+ self.mux_pipe.set_state(gst.STATE_NULL)
+ del self.mux_pipe
+
+ self.mux_pipe = gst.parse_launch( \
+ 'filesrc location=%s ' \
+ '! oggdemux ' \
+ '! theoraparse ' \
+ '! oggmux name=mux ' \
+ '! filesink location=%s ' \
+ 'filesrc location=%s ' \
+ '! wavparse ' \
+ '! audioconvert ' \
+ '! vorbisenc name=vorbisenc ' \
+ '! mux.' \
+ % (TMP_OGV, TMP_OGG, TMP_WAV))
+
+ taglist = self.getTags(Constants.TYPE_VIDEO)
+ vorbisenc = self.mux_pipe.get_by_name('vorbisenc')
+ vorbisenc.merge_tags(taglist, gst.TAG_MERGE_REPLACE_ALL)
+
+ def done(bus, message, self):
+ if message.type == gst.MESSAGE_ERROR:
+ err, debug = message.parse_error()
+ logger.error('audio_pipe: %s %s' % (err, debug))
+ return
+ elif message.type != gst.MESSAGE_EOS:
+ return
+
+ logger.debug('stopRecordingVideo.done')
+ self.mux_pipe.set_state(gst.STATE_NULL)
+
+ os.remove(TMP_OGV)
+ os.remove(TMP_WAV)
+
+ ogg_w = OGG_TRAITS[self.ogg_quality]['width']
+ ogg_h = OGG_TRAITS[self.ogg_quality]['height']
+
+ thumb = self.pixbuf.scale_simple(ogg_w, ogg_h,
+ gtk.gdk.INTERP_HYPER)
+
+ self.ca.ui.setPostProcessPixBuf(thumb)
+ self.ca.m.saveVideo(thumb, TMP_OGG, ogg_w, ogg_h)
+ self.ca.m.stoppedRecordingVideo()
+ self.ca.ui.updateVideoComponents()
+
+ bus = self.mux_pipe.get_bus()
+ bus.add_signal_watch()
+ bus.connect('message', done, self)
+
+ self.mux_pipe.set_state(gst.STATE_PLAYING)
+
+ def startRecordingAudio(self):
+ logger.debug('startRecordingAudio')
+
+ # XXX re-create pipe every time
+ # to supress gst glitches during the second invoking
+ if True:
+ self.audio_pipe = gst.parse_launch( \
+ '%s ' \
+ '! queue ' \
+ '! %s ' \
+ 'alsasrc ' \
+ '! queue ' \
+ '! audioconvert ' \
+ '! vorbisenc name=vorbisenc ' \
+ '! oggmux ' \
+ '! filesink location=%s ' \
+ % (self.src_str, self.play_str, TMP_OGG))
+
+ def message_cb(bus, message, self):
+ if message.type == gst.MESSAGE_ERROR:
+ err, debug = message.parse_error()
+ logger.error('audio_pipe: %s %s' % (err, debug))
+
+ bus = self.audio_pipe.get_bus()
+ bus.add_signal_watch()
+ bus.connect('message', message_cb, self)
+
+ def process_cb(self, pixbuf):
+ taglist = self.getTags(Constants.TYPE_AUDIO)
+ cover = utils.getStringFromPixbuf(pixbuf)
+ taglist[gst.TAG_EXTENDED_COMMENT] = 'coverart=%s' % cover
+
+ vorbisenc = self.audio_pipe.get_by_name('vorbisenc')
+ vorbisenc.merge_tags(taglist, gst.TAG_MERGE_REPLACE_ALL)
+
+ self.pixbuf = pixbuf
+ self._switch_pipe(self.audio_pipe)
+
+ # take photo first
+ self.takePhoto(process_cb)
+
+ def stopRecordingAudio( self ):
+ logger.debug('stopRecordingAudio')
+
+ self._switch_pipe(self.play_pipe)
+
+ if (not os.path.exists(TMP_OGG)):
+ self.ca.m.cannotSaveVideo()
+ return
+ if (os.path.getsize(TMP_OGG) <= 0):
+ self.ca.m.cannotSaveVideo()
+ return
+
+ self.ca.ui.setPostProcessPixBuf(self.pixbuf)
+ self.ca.m.saveAudio(TMP_OGG, self.pixbuf)
+
+ def abandonMedia(self):
+ logger.debug('abandonMedia')
+ self.stop()
+
+ if (self.AUDIO_TRANSCODE_ID != 0):
+ gobject.source_remove(self.AUDIO_TRANSCODE_ID)
+ self.AUDIO_TRANSCODE_ID = 0
+ if (self.TRANSCODE_ID != 0):
+ gobject.source_remove(self.TRANSCODE_ID)
+ self.TRANSCODE_ID = 0
+ if (self.VIDEO_TRANSCODE_ID != 0):
+ gobject.source_remove(self.VIDEO_TRANSCODE_ID)
+ self.VIDEO_TRANSCODE_ID = 0
+
+ if (os.path.exists(TMP_OGG)):
+ os.remove(TMP_OGG)
+
+ def __init__(self, pca):
+ self.window = None
+ self.ca = pca
+
+ self.pipeline = None
+ self.play_pipe = None
+ self.fallback_pipe = None
+ self.photo = None
+ self.video_pipe = None
+ self.mux_pipe = None
+ self.audio_pipe = None
+
+ self.fallback = False
+
+ # XXX since sugar doesn't control capture volumes (see #800)
+ # we have to do it by ourselves
+ alsasrc = gst.element_factory_make('alsasrc')
+ alsasrc.set_state(gst.STATE_PAUSED)
+ for i in alsasrc.list_tracks():
+ if i.props.flags & gst.interfaces.MIXER_TRACK_INPUT \
+ and re.search('capture', i.label, flags=re.IGNORECASE):
+ alsasrc.set_record(i, True)
+ volume = i.props.min_volume \
+ + int((i.props.max_volume - i.props.min_volume) \
+ / 100. * 90.)
+ alsasrc.set_volume(i, tuple([volume] * i.props.num_channels))
+ logger.debug('Set volume %s to %s' % (volume, i.label))
+ alsasrc.set_state(gst.STATE_NULL)
+ del alsasrc
+
+ def _switch_pipe(self, new_pipe):
+ if self.pipeline != new_pipe:
+ if self.pipeline:
+ self.pipeline.set_state(gst.STATE_NULL)
+ self.pipeline = new_pipe
+
+ if self.pipeline:
+ xsink = new_pipe.get_by_name('xsink')
+ if xsink:
+ xsink.set_xwindow_id(self.window.window.xid)
+ self.pipeline.set_state(gst.STATE_PLAYING)
+
+ def getTags( self, type ):
+ tl = gst.TagList()
+ tl[gst.TAG_ARTIST] = str(Instance.nickName)
+ tl[gst.TAG_COMMENT] = "sugar"
+ #this is unfortunately, unreliable
+ #record.Record.log.debug("self.ca.metadata['title']->" + str(self.ca.metadata['title']) )
+ tl[gst.TAG_ALBUM] = "sugar" #self.ca.metadata['title']
+ tl[gst.TAG_DATE] = utils.getDateString(int(time.time()))
+ stringType = Constants.mediaTypes[type][Constants.keyIstr]
+ tl[gst.TAG_TITLE] = Constants.istrBy % {"1":stringType, "2":str(Instance.nickName)}
+ return tl
class LiveVideoWindow(gtk.Window):
- def __init__(self, bgd ):
- gtk.Window.__init__(self)
-
- self.imagesink = None
- self.glive = None
-
- self.modify_bg( gtk.STATE_NORMAL, bgd )
- self.modify_bg( gtk.STATE_INSENSITIVE, bgd )
- self.unset_flags(gtk.DOUBLE_BUFFERED)
- self.set_flags(gtk.APP_PAINTABLE)
+ def __init__(self, bgd ):
+ gtk.Window.__init__(self)
- def set_glive(self, pglive):
- self.glive = pglive
- self.glive.window = self
+ self.glive = None
- def set_sink(self, sink):
- if (self.imagesink != None):
- assert self.window.xid
- self.imagesink = None
- del self.imagesink
+ self.modify_bg( gtk.STATE_NORMAL, bgd )
+ self.modify_bg( gtk.STATE_INSENSITIVE, bgd )
+ self.unset_flags(gtk.DOUBLE_BUFFERED)
+ self.set_flags(gtk.APP_PAINTABLE)
- self.imagesink = sink
- self.imagesink.set_xwindow_id(self.window.xid)
+ def set_glive(self, pglive):
+ self.glive = pglive
+ self.glive.window = self
diff --git a/glivex.py b/glivex.py
deleted file mode 100644
index 5b8267f..0000000
--- a/glivex.py
+++ /dev/null
@@ -1,147 +0,0 @@
-#Copyright (c) 2008, Media Modifications Ltd.
-
-#Permission is hereby granted, free of charge, to any person obtaining a copy
-#of this software and associated documentation files (the "Software"), to deal
-#in the Software without restriction, including without limitation the rights
-#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-#copies of the Software, and to permit persons to whom the Software is
-#furnished to do so, subject to the following conditions:
-
-#The above copyright notice and this permission notice shall be included in
-#all copies or substantial portions of the Software.
-
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-#THE SOFTWARE.
-
-# This class is a cut-down version of glive which uses an ximagesink
-# rather than an xvimagesink. This is used in video playback mode, where
-# our only Xv port is used for Theora playback.
-#
-# I tried to modify the glive pipeline to allow swapping an xvimagesink for
-# an ximagesink and vice-versa, but that didn't work out (all kinds of strange
-# behaviour, perhaps a gstreamer bug). So we resort to using a separate
-# pipeline - ugly, but it works...
-
-import os
-import gtk
-import pygtk
-pygtk.require('2.0')
-import sys
-import gst
-import gst.interfaces
-import pygst
-pygst.require('0.10')
-import time
-import threading
-import gobject
-gobject.threads_init()
-
-from instance import Instance
-from constants import Constants
-import record
-import utils
-import ui
-
-class GliveX:
- def __init__(self, pca):
- self.window = None
- self.ca = pca
-
- self.playing = False
-
- self.pipeline = gst.Pipeline("slow-pipeline")
- self.createPipeline()
-
- bus = self.pipeline.get_bus()
- bus.enable_sync_message_emission()
- bus.add_signal_watch()
- self.SYNC_ID = bus.connect('sync-message::element', self._onSyncMessageCb)
- self.MESSAGE_ID = bus.connect('message', self._onMessageCb)
-
- def createPipeline ( self ):
- src = gst.element_factory_make("v4l2src", "camsrc")
- try:
- # old gst-plugins-good does not have this property
- src.set_property("queue-size", 2)
- except:
- pass
-
- queue = gst.element_factory_make("queue", "dispqueue")
- queue.set_property("leaky", True)
- queue.set_property('max-size-buffers', 1)
-
- scale = gst.element_factory_make("videoscale", "scale")
- scalecaps = gst.Caps('video/x-raw-yuv,width='+str(ui.UI.dim_PIPW)+',height='+str(ui.UI.dim_PIPH))
- colorspace = gst.element_factory_make("ffmpegcolorspace", "colorspace")
- xsink = gst.element_factory_make("ximagesink", "xsink")
- self.pipeline.add(src, queue, scale, colorspace, xsink)
- gst.element_link_many(src, queue, scale)
- scale.link(colorspace, scalecaps)
- colorspace.link(xsink)
-
- def play(self):
- self.pipeline.set_state(gst.STATE_PLAYING)
- self.playing = True
-
- def pause(self):
- self.pipeline.set_state(gst.STATE_PAUSED)
- self.playing = False
-
- def stop(self):
- self.pipeline.set_state(gst.STATE_NULL)
- self.playing = False
-
- def is_playing(self):
- return self.playing
-
- def idlePlayElement(self, element):
- element.set_state(gst.STATE_PLAYING)
- return False
-
- def _onSyncMessageCb(self, bus, message):
- if message.structure is None:
- return
- if message.structure.get_name() == 'prepare-xwindow-id':
- self.window.set_sink(message.src)
- message.src.set_property('force-aspect-ratio', True)
-
- def _onMessageCb(self, bus, message):
- t = message.type
- if t == gst.MESSAGE_EOS:
- #print("MESSAGE_EOS")
- pass
- elif t == gst.MESSAGE_ERROR:
- #todo: if we come out of suspend/resume with errors, then get us back up and running...
- #todo: handle "No space left on the resource.gstfilesink.c"
- #err, debug = message.parse_error()
- pass
-
-class SlowLiveVideoWindow(gtk.Window):
- def __init__(self, bgd ):
- gtk.Window.__init__(self)
-
- self.imagesink = None
- self.glivex = None
-
- self.modify_bg( gtk.STATE_NORMAL, bgd )
- self.modify_bg( gtk.STATE_INSENSITIVE, bgd )
- self.unset_flags(gtk.DOUBLE_BUFFERED)
- self.set_flags(gtk.APP_PAINTABLE)
-
- def set_glivex(self, pglivex):
- self.glivex = pglivex
- self.glivex.window = self
-
- 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)
diff --git a/gplay.py b/gplay.py
index e8572e0..e459563 100644
--- a/gplay.py
+++ b/gplay.py
@@ -32,123 +32,103 @@ import gobject
import time
gobject.threads_init()
+import logging
+logger = logging.getLogger('record:gplay.py')
+
import record
class Gplay:
- def __init__(self):
- self.window = None
- self.players = []
- self.playing = False
- self.nextMovie()
-
- def nextMovie(self):
- if ( len(self.players) > 0 ):
- self.playing = False
- self.getPlayer().set_property("video-sink", None)
- self.getPlayer().get_bus().disconnect(self.SYNC_ID)
- self.getPlayer().get_bus().remove_signal_watch()
- self.getPlayer().get_bus().disable_sync_message_emission()
-
- player = gst.element_factory_make("playbin", "playbin")
- xis = gst.element_factory_make("xvimagesink", "xvimagesink")
- player.set_property("video-sink", xis)
- bus = player.get_bus()
- bus.enable_sync_message_emission()
- bus.add_signal_watch()
- self.SYNC_ID = bus.connect('sync-message::element', self.onSyncMessage)
- self.players.append(player)
-
+ def __init__(self, ca):
+ self.ca = ca
+ self.window = None
+ self.players = []
+ self.playing = False
- def getPlayer(self):
- return self.players[len(self.players)-1]
+ self.player = gst.element_factory_make('playbin')
+ bus = self.player.get_bus()
+ bus.enable_sync_message_emission()
+ bus.add_signal_watch()
+ bus.connect('message', self._onMessageCb)
- def onSyncMessage(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 _onMessageCb(self, bus, message):
+ if message.type == gst.MESSAGE_ERROR:
+ err, debug = message.parse_error()
+ logger.error('_onMessageCb: error=%s debug=%s' % (err, debug))
+ def setLocation(self, location):
+ if (self.player.get_property('uri') == location):
+ self.seek(gst.SECOND*0)
+ return
- def setLocation(self, location):
- if (self.getPlayer().get_property('uri') == location):
- self.seek(gst.SECOND*0)
- return
+ self.player.set_state(gst.STATE_READY)
+ self.player.set_property('uri', location)
+ ext = location[len(location)-3:]
+ record.Record.log.debug("setLocation: ext->"+str(ext))
+ if (ext == "jpg"):
+ self.pause()
- self.getPlayer().set_state(gst.STATE_READY)
- self.getPlayer().set_property('uri', location)
- ext = location[len(location)-3:]
- record.Record.log.debug("setLocation: ext->"+str(ext))
- if (ext == "jpg"):
- self.pause()
+ def queryPosition(self):
+ "Returns a (position, duration) tuple"
+ try:
+ position, format = self.player.query_position(gst.FORMAT_TIME)
+ except:
+ position = gst.CLOCK_TIME_NONE
- def queryPosition(self):
- "Returns a (position, duration) tuple"
- try:
- position, format = self.getPlayer().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.getPlayer().query_duration(gst.FORMAT_TIME)
- except:
- duration = gst.CLOCK_TIME_NONE
+ return (position, duration)
- return (position, duration)
+ def seek(self, location):
+ event = gst.event_new_seek(1.0, gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE, gst.SEEK_TYPE_SET, location, gst.SEEK_TYPE_NONE, 0)
+ res = self.player.send_event(event)
+ if res:
+ self.player.set_new_stream_time(0L)
- def seek(self, location):
- event = gst.event_new_seek(1.0, gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE, gst.SEEK_TYPE_SET, location, gst.SEEK_TYPE_NONE, 0)
- res = self.getPlayer().send_event(event)
- if res:
- self.getPlayer().set_new_stream_time(0L)
+ def pause(self):
+ self.playing = False
+ self.player.set_state(gst.STATE_PAUSED)
- def pause(self):
- self.playing = False
- self.getPlayer().set_state(gst.STATE_PAUSED)
+ def play(self):
+ if not self.player.props.video_sink:
+ if self.ca.glive.fallback:
+ sink = gst.element_factory_make('ximagesink')
+ else:
+ sink = gst.element_factory_make('xvimagesink')
+ sink.props.force_aspect_ratio = True
+ self.player.props.video_sink = sink
- def play(self):
- self.playing = True
- self.getPlayer().set_state(gst.STATE_PLAYING)
+ self.player.props.video_sink.set_xwindow_id(self.window.window.xid)
+ self.playing = True
+ self.player.set_state(gst.STATE_PLAYING)
- def stop(self):
- self.playing = False
- self.getPlayer().set_state(gst.STATE_NULL)
- self.nextMovie()
+ def stop(self):
+ self.playing = False
+ self.player.set_state(gst.STATE_NULL)
- def get_state(self, timeout=1):
- return self.getPlayer().get_state(timeout=timeout)
+ def get_state(self, timeout=1):
+ return self.player.get_state(timeout=timeout)
- def is_playing(self):
- return self.playing
+ def is_playing(self):
+ return self.playing
class PlayVideoWindow(gtk.Window):
- def __init__(self, bgd):
- gtk.Window.__init__(self)
-
- self.imagesink = None
-
- self.modify_bg( gtk.STATE_NORMAL, bgd )
- self.modify_bg( gtk.STATE_INSENSITIVE, bgd )
- 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
+ def __init__(self, bgd):
+ gtk.Window.__init__(self)
- self.imagesink = sink
- self.imagesink.set_xwindow_id(self.window.xid) \ No newline at end of file
+ self.modify_bg( gtk.STATE_NORMAL, bgd )
+ self.modify_bg( gtk.STATE_INSENSITIVE, bgd )
+ self.unset_flags(gtk.DOUBLE_BUFFERED)
+ self.set_flags(gtk.APP_PAINTABLE)
diff --git a/greplay.py b/greplay.py
index a2b763b..67758a1 100644
--- a/greplay.py
+++ b/greplay.py
@@ -30,51 +30,51 @@ import utils
class Greplay(gobject.GObject):
- __gsignals__ = {
- 'coverart-found':
- (gobject.SIGNAL_RUN_FIRST, None, [object])
- }
+ __gsignals__ = {
+ 'coverart-found':
+ (gobject.SIGNAL_RUN_FIRST, None, [object])
+ }
- def findAlbumArt( self, path ):
- record.Record.log.debug("getAlbumArt")
- if (path == None):
- record.Record.log.debug("getAlbumArt: path==None")
- self.emit('coverart-found', None)
- return
- if (not os.path.exists(path)):
- record.Record.log.debug("getAlbumArt: path doesn't exist")
- self.emit('coverart-found', None)
- return
+ def findAlbumArt( self, path ):
+ record.Record.log.debug("getAlbumArt")
+ if (path == None):
+ record.Record.log.debug("getAlbumArt: path==None")
+ self.emit('coverart-found', None)
+ return
+ if (not os.path.exists(path)):
+ record.Record.log.debug("getAlbumArt: path doesn't exist")
+ self.emit('coverart-found', None)
+ return
- self.pp = gst.parse_launch("filesrc location="+str(path)+" ! oggdemux ! vorbisdec ! fakesink")
- self.pp.get_bus().add_signal_watch()
- self.pp.get_bus().connect("message", self._onMessageCb)
- self.pp.set_state(gst.STATE_PLAYING)
+ self.pp = gst.parse_launch("filesrc location="+str(path)+" ! oggdemux ! vorbisdec ! fakesink")
+ self.pp.get_bus().add_signal_watch()
+ self.pp.get_bus().connect("message", self._onMessageCb)
+ self.pp.set_state(gst.STATE_PLAYING)
- def _onMessageCb(self, bus, message):
- t = message.type
- if t == gst.MESSAGE_EOS:
- record.Record.log.debug("Greplay:MESSAGE_EOS")
- self.emit('coverart-found', None)
- self.pp.set_state(gst.STATE_NULL)
- return False
- elif t == gst.MESSAGE_ERROR:
- record.Record.log.debug("Greplay:MESSAGE_ERROR")
- self.emit('coverart-found', None)
- self.pp.set_state(gst.STATE_NULL)
- return False
- elif t == gst.MESSAGE_TAG:
- tags = message.parse_tag()
- for tag in tags.keys():
- if (str(tag) == "extended-comment"):
- record.Record.log.debug("Found the tag!")
- #todo, check for tagname
- base64imgString = str(tags[tag])[len("coverart="):]
+ def _onMessageCb(self, bus, message):
+ t = message.type
+ if t == gst.MESSAGE_EOS:
+ record.Record.log.debug("Greplay:MESSAGE_EOS")
+ self.emit('coverart-found', None)
+ self.pp.set_state(gst.STATE_NULL)
+ return False
+ elif t == gst.MESSAGE_ERROR:
+ record.Record.log.debug("Greplay:MESSAGE_ERROR")
+ self.emit('coverart-found', None)
+ self.pp.set_state(gst.STATE_NULL)
+ return False
+ elif t == gst.MESSAGE_TAG:
+ tags = message.parse_tag()
+ for tag in tags.keys():
+ if (str(tag) == "extended-comment"):
+ record.Record.log.debug("Found the tag!")
+ #todo, check for tagname
+ base64imgString = str(tags[tag])[len("coverart="):]
- pixbuf = utils.getPixbufFromString(base64imgString)
- self.pp.set_state(gst.STATE_NULL)
- self.emit('coverart-found', pixbuf)
- return False
- return True
+ pixbuf = utils.getPixbufFromString(base64imgString)
+ self.pp.set_state(gst.STATE_NULL)
+ self.emit('coverart-found', pixbuf)
+ return False
+ return True
diff --git a/gst/AUTHORS b/gst/AUTHORS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gst/AUTHORS
diff --git a/gst/COPYING b/gst/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/gst/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/gst/ChangeLog b/gst/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gst/ChangeLog
diff --git a/gst/INSTALL b/gst/INSTALL
new file mode 100644
index 0000000..8b82ade
--- /dev/null
+++ b/gst/INSTALL
@@ -0,0 +1,291 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008 Free Software Foundation, Inc.
+
+ This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+ Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package. The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system.
+
+ Running `configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+ 6. Often, you can also type `make uninstall' to remove the installed
+ files again.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+ On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor. Like
+this:
+
+ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CPP="gcc -E" CXXCPP="g++ -E"
+
+ This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+ By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Particular systems
+==================
+
+ On HP-UX, the default C compiler is not ANSI C compatible. If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+ ./configure CC="cc -Ae"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file. The option `-nodtk' can be used as
+a workaround. If GNU CC is not installed, it is therefore recommended
+to try
+
+ ./configure CC="cc"
+
+and if that doesn't work, try
+
+ ./configure CC="cc -nodtk"
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug. Until the bug is fixed you can use this workaround:
+
+ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+ Print a summary of the options unique to this package's
+ `configure', and exit. The `short' variant lists options used
+ only in the top level, while the `recursive' variant lists options
+ also present in any nested packages.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+ Use DIR as the installation prefix. *Note Installation Names::
+ for more details, including other options available for fine-tuning
+ the installation locations.
+
+`--no-create'
+`-n'
+ Run the configure checks, but stop before creating any output
+ files.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/gst/Makefile.am b/gst/Makefile.am
new file mode 100644
index 0000000..31e0a31
--- /dev/null
+++ b/gst/Makefile.am
@@ -0,0 +1,20 @@
+plugin_LTLIBRARIES = libgstvideorate.la libgstvalve.la
+
+libgstvideorate_la_SOURCES = gstvideorate.c gstvideorate.h
+libgstvideorate_la_CFLAGS = $(GST_CFLAGS) $(GST_AUDIO_CFLAGS)
+libgstvideorate_la_LIBADD = $(GST_LIBS) $(GST_AUDIO_LIBS)
+libgstvideorate_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstvideorate_la_LIBTOOLFLAGS = --tag=disable-static
+
+libgstvalve_la_SOURCES = gstvalve.c gstvalve.h
+libgstvalve_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(ERROR_CFLAGS)
+libgstvalve_la_LIBADD = $(GST_LIBS_LIBS)
+libgstvalve_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS)
+libgstvalve_la_LIBTOOLFLAGS = --tag=disable-static
+
+ARCH = $(shell arch | grep 64 >/dev/null && echo linux64 || echo linux32)
+
+dist_xo: all
+ rm -rf $(ARCH)
+ mkdir $(ARCH)
+ cp .libs/libgst*.so $(ARCH)/
diff --git a/gst/NEWS b/gst/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gst/NEWS
diff --git a/gst/README b/gst/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gst/README
diff --git a/gst/autogen.sh b/gst/autogen.sh
new file mode 100755
index 0000000..aa82ce7
--- /dev/null
+++ b/gst/autogen.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+# you can either set the environment variables AUTOCONF and AUTOMAKE
+# to the right versions, or leave them unset and get the RedHat 7.3 defaults
+
+NOCONFIGURE=1
+DIE=0
+package=gst-plugin
+srcfile=src/main.c
+
+# autogen.sh helper functions (copied from GStreamer's common/ CVS module)
+if test ! -f ./gst-autogen.sh;
+then
+ echo There is something wrong with your source tree.
+ echo You are either missing ./gst-autogen.sh or not
+ echo running autogen.sh from the top-level source
+ echo directory.
+ exit 1
+fi
+. ./gst-autogen.sh
+
+CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-debug'
+
+autogen_options $@
+
+echo -n "+ check for build tools"
+if test ! -z "$NOCHECK"; then echo " skipped"; else echo; fi
+version_check "autoconf" "$AUTOCONF autoconf autoconf259 autoconf257 autoconf-2.54 autoconf-2.53 autoconf-2.52" \
+ "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 52 || DIE=1
+version_check "automake" "$AUTOMAKE automake automake-1.9 automake19 automake-1.7 automake-1.6 automake-1.5" \
+ "ftp://ftp.gnu.org/pub/gnu/automake/" 1 7 || DIE=1
+###version_check "autopoint" "autopoint" \
+### "ftp://ftp.gnu.org/pub/gnu/gettext/" 0 11 5 || DIE=1
+version_check "libtoolize" "$LIBTOOLIZE libtoolize glibtoolize" \
+ "ftp://ftp.gnu.org/pub/gnu/libtool/" 1 5 0 || DIE=1
+version_check "pkg-config" "" \
+ "http://www.freedesktop.org/software/pkgconfig" 0 8 0 || DIE=1
+
+die_check $DIE
+
+autoconf_2_52d_check || DIE=1
+aclocal_check || DIE=1
+autoheader_check || DIE=1
+
+die_check $DIE
+
+# if no arguments specified then this will be printed
+if test -z "$*"; then
+ echo "+ checking for autogen.sh options"
+ echo " This autogen script will automatically run ./configure as:"
+ echo " ./configure $CONFIGURE_DEF_OPT"
+ echo " To pass any additional options, please specify them on the $0"
+ echo " command line."
+fi
+
+tool_run "$aclocal" "-I m4/ $ACLOCAL_FLAGS"
+tool_run "$libtoolize" "--copy --force"
+tool_run "$autoheader"
+tool_run "$autoconf"
+tool_run "$automake" "-a -c"
+
+# if enable exists, add an -enable option for each of the lines in that file
+if test -f enable; then
+ for a in `cat enable`; do
+ CONFIGURE_FILE_OPT="--enable-$a"
+ done
+fi
+
+# if disable exists, add an -disable option for each of the lines in that file
+if test -f disable; then
+ for a in `cat disable`; do
+ CONFIGURE_FILE_OPT="$CONFIGURE_FILE_OPT --disable-$a"
+ done
+fi
+
+test -n "$NOCONFIGURE" && {
+ echo "+ skipping configure stage for package $package, as requested."
+ echo "+ autogen.sh done."
+ exit 0
+}
+
+echo "+ running configure ... "
+test ! -z "$CONFIGURE_DEF_OPT" && echo " ./configure default flags: $CONFIGURE_DEF_OPT"
+test ! -z "$CONFIGURE_EXT_OPT" && echo " ./configure external flags: $CONFIGURE_EXT_OPT"
+test ! -z "$CONFIGURE_FILE_OPT" && echo " ./configure enable/disable flags: $CONFIGURE_FILE_OPT"
+echo
+
+./configure $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT $CONFIGURE_FILE_OPT || {
+ echo " configure failed"
+ exit 1
+}
+
+echo "Now type 'make' to compile $package."
diff --git a/gst/configure.ac b/gst/configure.ac
new file mode 100644
index 0000000..cd84f56
--- /dev/null
+++ b/gst/configure.ac
@@ -0,0 +1,136 @@
+AC_INIT([gst-plugins-espeak], [0.3])
+
+dnl versions of gstreamer and plugins-base
+GST_MAJORMINOR=0.10
+GST_REQUIRED=0.10.0
+GSTPB_REQUIRED=0.10.0
+
+dnl fill in your package name and version here
+dnl the fourth (nano) number should be 0 for a release, 1 for CVS,
+dnl and 2... for a prerelease
+
+dnl when going to/from release please set the nano correctly !
+dnl releases only do Wall, cvs and prerelease does Werror too
+AS_VERSION(gst-plugin, GST_PLUGIN_VERSION, 0, 10, 0, 1,
+ GST_PLUGIN_CVS="no", GST_PLUGIN_CVS="yes")
+
+dnl AM_MAINTAINER_MODE provides the option to enable maintainer mode
+#AM_MAINTAINER_MODE
+
+AM_INIT_AUTOMAKE($PACKAGE, $VERSION)
+
+dnl make aclocal work in maintainer mode
+AC_SUBST(ACLOCAL_AMFLAGS, "-I m4")
+
+AM_CONFIG_HEADER(config.h)
+
+dnl check for tools
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+
+dnl decide on error flags
+AS_COMPILER_FLAG(-Wall, GST_WALL="yes", GST_WALL="no")
+
+if test "x$GST_WALL" = "xyes"; then
+ GST_ERROR="$GST_ERROR -Wall"
+
+ if test "x$GST_PLUGIN_CVS" = "xyes"; then
+ AS_COMPILER_FLAG(-Werror,GST_ERROR="$GST_ERROR -Werror",GST_ERROR="$GST_ERROR")
+ fi
+fi
+
+dnl Check for pkgconfig first
+AC_CHECK_PROG(HAVE_PKGCONFIG, pkg-config, yes, no)
+
+dnl Give error and exit if we don't have pkgconfig
+if test "x$HAVE_PKGCONFIG" = "xno"; then
+ AC_MSG_ERROR(you need to have pkgconfig installed !)
+fi
+
+dnl Now we're ready to ask for gstreamer libs and cflags
+dnl And we can also ask for the right version of gstreamer
+
+
+PKG_CHECK_MODULES(GST, \
+ gstreamer-$GST_MAJORMINOR >= $GST_REQUIRED,
+ HAVE_GST=yes,HAVE_GST=no)
+
+dnl Give error and exit if we don't have gstreamer
+if test "x$HAVE_GST" = "xno"; then
+ AC_MSG_ERROR(you need gstreamer development packages installed !)
+fi
+
+dnl append GST_ERROR cflags to GST_CFLAGS
+GST_CFLAGS="$GST_CFLAGS $GST_ERROR"
+
+dnl make GST_CFLAGS and GST_LIBS available
+AC_SUBST(GST_CFLAGS)
+AC_SUBST(GST_LIBS)
+
+dnl make GST_MAJORMINOR available in Makefile.am
+AC_SUBST(GST_MAJORMINOR)
+
+dnl If we need them, we can also use the base class libraries
+PKG_CHECK_MODULES(GST_BASE, gstreamer-base-$GST_MAJORMINOR >= $GST_REQUIRED,
+ HAVE_GST_BASE=yes, HAVE_GST_BASE=no)
+
+dnl Give a warning if we don't have gstreamer libs
+dnl you can turn this into an error if you need them
+if test "x$HAVE_GST_BASE" = "xno"; then
+ AC_MSG_NOTICE(no GStreamer base class libraries found (gstreamer-base-$GST_MAJORMINOR))
+fi
+
+dnl make _CFLAGS and _LIBS available
+AC_SUBST(GST_BASE_CFLAGS)
+AC_SUBST(GST_BASE_LIBS)
+
+dnl If we need them, we can also use the gstreamer-plugins-base libraries
+PKG_CHECK_MODULES(GSTPB_BASE,
+ gstreamer-plugins-base-$GST_MAJORMINOR >= $GSTPB_REQUIRED,
+ HAVE_GSTPB_BASE=yes, HAVE_GSTPB_BASE=no)
+
+dnl Give a warning if we don't have gstreamer libs
+dnl you can turn this into an error if you need them
+if test "x$HAVE_GSTPB_BASE" = "xno"; then
+ AC_MSG_NOTICE(no GStreamer Plugins Base libraries found (gstreamer-plugins-base-$GST_MAJORMINOR))
+fi
+
+dnl make _CFLAGS and _LIBS available
+AC_SUBST(GSTPB_BASE_CFLAGS)
+AC_SUBST(GSTPB_BASE_LIBS)
+
+dnl If we need them, we can also use the gstreamer-controller libraries
+PKG_CHECK_MODULES(GSTCTRL,
+ gstreamer-controller-$GST_MAJORMINOR >= $GSTPB_REQUIRED,
+ HAVE_GSTCTRL=yes, HAVE_GSTCTRL=no)
+
+dnl Give a warning if we don't have gstreamer-controller
+dnl you can turn this into an error if you need them
+if test "x$HAVE_GSTCTRL" = "xno"; then
+ AC_MSG_NOTICE(no GStreamer Controller libraries found (gstreamer-controller-$GST_MAJORMINOR))
+fi
+
+dnl make _CFLAGS and _LIBS available
+AC_SUBST(GSTCTRL_CFLAGS)
+AC_SUBST(GSTCTRL_LIBS)
+
+dnl set the plugindir where plugins should be installed
+if test "x${prefix}" = "x$HOME"; then
+ plugindir="$HOME/.gstreamer-$GST_MAJORMINOR/plugins"
+else
+ plugindir="\$(libdir)/gstreamer-$GST_MAJORMINOR"
+fi
+AC_SUBST(plugindir)
+
+dnl set proper LDFLAGS for plugins
+GST_PLUGIN_LDFLAGS='-module -avoid-version -export-symbols-regex [_]*\(gst_\|Gst\|GST_\).*'
+AC_SUBST(GST_PLUGIN_LDFLAGS)
+
+PKG_CHECK_MODULES(OGG, ogg)
+
+AC_DEFINE_UNQUOTED(GST_LICENSE, "LGPL", [ ])
+AC_DEFINE_UNQUOTED(GST_PACKAGE_NAME, "GStreamer Base Plug-ins CVS/prerelease", [ ])
+AC_DEFINE_UNQUOTED(GST_PACKAGE_ORIGIN, "Unknown package origin", [ ])
+
+AC_OUTPUT(Makefile)
diff --git a/gst/gst-autogen.sh b/gst/gst-autogen.sh
new file mode 100644
index 0000000..7b31212
--- /dev/null
+++ b/gst/gst-autogen.sh
@@ -0,0 +1,308 @@
+# a silly hack that generates autoregen.sh but it's handy
+# Remove the old autoregen.sh first to create a new file,
+# as the current one may be being read by the shell executing
+# this script.
+if [ -f "autoregen.sh" ]; then
+ rm autoregen.sh
+fi
+echo "#!/bin/sh" > autoregen.sh
+echo "./autogen.sh $@ \$@" >> autoregen.sh
+chmod +x autoregen.sh
+
+# helper functions for autogen.sh
+
+debug ()
+# print out a debug message if DEBUG is a defined variable
+{
+ if test ! -z "$DEBUG"
+ then
+ echo "DEBUG: $1"
+ fi
+}
+
+version_check ()
+# check the version of a package
+# first argument : package name (executable)
+# second argument : optional path where to look for it instead
+# third argument : source download url
+# rest of arguments : major, minor, micro version
+# all consecutive ones : suggestions for binaries to use
+# (if not specified in second argument)
+{
+ PACKAGE=$1
+ PKG_PATH=$2
+ URL=$3
+ MAJOR=$4
+ MINOR=$5
+ MICRO=$6
+
+ # for backwards compatibility, we let PKG_PATH=PACKAGE when PKG_PATH null
+ if test -z "$PKG_PATH"; then PKG_PATH=$PACKAGE; fi
+ debug "major $MAJOR minor $MINOR micro $MICRO"
+ VERSION=$MAJOR
+ if test ! -z "$MINOR"; then VERSION=$VERSION.$MINOR; else MINOR=0; fi
+ if test ! -z "$MICRO"; then VERSION=$VERSION.$MICRO; else MICRO=0; fi
+
+ debug "major $MAJOR minor $MINOR micro $MICRO"
+
+ for SUGGESTION in $PKG_PATH; do
+ COMMAND="$SUGGESTION"
+
+ # don't check if asked not to
+ test -z "$NOCHECK" && {
+ echo -n " checking for $COMMAND >= $VERSION ... "
+ } || {
+ # we set a var with the same name as the package, but stripped of
+ # unwanted chars
+ VAR=`echo $PACKAGE | sed 's/-//g'`
+ debug "setting $VAR"
+ eval $VAR="$COMMAND"
+ return 0
+ }
+
+ debug "checking version with $COMMAND"
+ ($COMMAND --version) < /dev/null > /dev/null 2>&1 ||
+ {
+ echo "not found."
+ continue
+ }
+ # strip everything that's not a digit, then use cut to get the first field
+ pkg_version=`$COMMAND --version|head -n 1|sed 's/^.*)[^0-9]*//'|cut -d' ' -f1`
+ debug "pkg_version $pkg_version"
+ # remove any non-digit characters from the version numbers to permit numeric
+ # comparison
+ pkg_major=`echo $pkg_version | cut -d. -f1 | sed s/[a-zA-Z\-].*//g`
+ pkg_minor=`echo $pkg_version | cut -d. -f2 | sed s/[a-zA-Z\-].*//g`
+ pkg_micro=`echo $pkg_version | cut -d. -f3 | sed s/[a-zA-Z\-].*//g`
+ test -z "$pkg_major" && pkg_major=0
+ test -z "$pkg_minor" && pkg_minor=0
+ test -z "$pkg_micro" && pkg_micro=0
+ debug "found major $pkg_major minor $pkg_minor micro $pkg_micro"
+
+ #start checking the version
+ debug "version check"
+
+ # reset check
+ WRONG=
+
+ if [ ! "$pkg_major" -gt "$MAJOR" ]; then
+ debug "major: $pkg_major <= $MAJOR"
+ if [ "$pkg_major" -lt "$MAJOR" ]; then
+ debug "major: $pkg_major < $MAJOR"
+ WRONG=1
+ elif [ ! "$pkg_minor" -gt "$MINOR" ]; then
+ debug "minor: $pkg_minor <= $MINOR"
+ if [ "$pkg_minor" -lt "$MINOR" ]; then
+ debug "minor: $pkg_minor < $MINOR"
+ WRONG=1
+ elif [ "$pkg_micro" -lt "$MICRO" ]; then
+ debug "micro: $pkg_micro < $MICRO"
+ WRONG=1
+ fi
+ fi
+ fi
+
+ if test ! -z "$WRONG"; then
+ echo "found $pkg_version, not ok !"
+ continue
+ else
+ echo "found $pkg_version, ok."
+ # we set a var with the same name as the package, but stripped of
+ # unwanted chars
+ VAR=`echo $PACKAGE | sed 's/-//g'`
+ debug "setting $VAR"
+ eval $VAR="$COMMAND"
+ return 0
+ fi
+ done
+
+ echo "not found !"
+ echo "You must have $PACKAGE installed to compile $package."
+ echo "Download the appropriate package for your distribution,"
+ echo "or get the source tarball at $URL"
+ return 1;
+}
+
+aclocal_check ()
+{
+ # normally aclocal is part of automake
+ # so we expect it to be in the same place as automake
+ # so if a different automake is supplied, we need to adapt as well
+ # so how's about replacing automake with aclocal in the set var,
+ # and saving that in $aclocal ?
+ # note, this will fail if the actual automake isn't called automake*
+ # or if part of the path before it contains it
+ if [ -z "$automake" ]; then
+ echo "Error: no automake variable set !"
+ return 1
+ else
+ aclocal=`echo $automake | sed s/automake/aclocal/`
+ debug "aclocal: $aclocal"
+ if [ "$aclocal" != "aclocal" ];
+ then
+ CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-aclocal=$aclocal"
+ fi
+ if [ ! -x `which $aclocal` ]; then
+ echo "Error: cannot execute $aclocal !"
+ return 1
+ fi
+ fi
+}
+
+autoheader_check ()
+{
+ # same here - autoheader is part of autoconf
+ # use the same voodoo
+ if [ -z "$autoconf" ]; then
+ echo "Error: no autoconf variable set !"
+ return 1
+ else
+ autoheader=`echo $autoconf | sed s/autoconf/autoheader/`
+ debug "autoheader: $autoheader"
+ if [ "$autoheader" != "autoheader" ];
+ then
+ CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-autoheader=$autoheader"
+ fi
+ if [ ! -x `which $autoheader` ]; then
+ echo "Error: cannot execute $autoheader !"
+ return 1
+ fi
+ fi
+
+}
+autoconf_2_52d_check ()
+{
+ # autoconf 2.52d has a weird issue involving a yes:no error
+ # so don't allow it's use
+ test -z "$NOCHECK" && {
+ ac_version=`$autoconf --version|head -n 1|sed 's/^[a-zA-Z\.\ ()]*//;s/ .*$//'`
+ if test "$ac_version" = "2.52d"; then
+ echo "autoconf 2.52d has an issue with our current build."
+ echo "We don't know who's to blame however. So until we do, get a"
+ echo "regular version. RPM's of a working version are on the gstreamer site."
+ exit 1
+ fi
+ }
+ return 0
+}
+
+die_check ()
+{
+ # call with $DIE
+ # if set to 1, we need to print something helpful then die
+ DIE=$1
+ if test "x$DIE" = "x1";
+ then
+ echo
+ echo "- Please get the right tools before proceeding."
+ echo "- Alternatively, if you're sure we're wrong, run with --nocheck."
+ exit 1
+ fi
+}
+
+autogen_options ()
+{
+ if test "x$1" = "x"; then
+ return 0
+ fi
+
+ while test "x$1" != "x" ; do
+ optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ case "$1" in
+ --noconfigure)
+ NOCONFIGURE=defined
+ AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --noconfigure"
+ echo "+ configure run disabled"
+ shift
+ ;;
+ --nocheck)
+ AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --nocheck"
+ NOCHECK=defined
+ echo "+ autotools version check disabled"
+ shift
+ ;;
+ --debug)
+ DEBUG=defined
+ AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --debug"
+ echo "+ debug output enabled"
+ shift
+ ;;
+ --prefix=*)
+ CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT --prefix=$optarg"
+ echo "+ passing --prefix=$optarg to configure"
+ shift
+ ;;
+ --prefix)
+ shift
+ echo "DEBUG: $1"
+ CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT --prefix=$1"
+ echo "+ passing --prefix=$1 to configure"
+ shift
+ ;;
+
+ -h|--help)
+ echo "autogen.sh (autogen options) -- (configure options)"
+ echo "autogen.sh help options: "
+ echo " --noconfigure don't run the configure script"
+ echo " --nocheck don't do version checks"
+ echo " --debug debug the autogen process"
+ echo " --prefix will be passed on to configure"
+ echo
+ echo " --with-autoconf PATH use autoconf in PATH"
+ echo " --with-automake PATH use automake in PATH"
+ echo
+ echo "to pass options to configure, put them as arguments after -- "
+ exit 1
+ ;;
+ --with-automake=*)
+ AUTOMAKE=$optarg
+ echo "+ using alternate automake in $optarg"
+ CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-automake=$AUTOMAKE"
+ shift
+ ;;
+ --with-autoconf=*)
+ AUTOCONF=$optarg
+ echo "+ using alternate autoconf in $optarg"
+ CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-autoconf=$AUTOCONF"
+ shift
+ ;;
+ --disable*|--enable*|--with*)
+ echo "+ passing option $1 to configure"
+ CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT $1"
+ shift
+ ;;
+ --) shift ; break ;;
+ *) echo "- ignoring unknown autogen.sh argument $1"; shift ;;
+ esac
+ done
+
+ for arg do CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT $arg"; done
+ if test ! -z "$CONFIGURE_EXT_OPT"
+ then
+ echo "+ options passed to configure: $CONFIGURE_EXT_OPT"
+ fi
+}
+
+toplevel_check ()
+{
+ srcfile=$1
+ test -f $srcfile || {
+ echo "You must run this script in the top-level $package directory"
+ exit 1
+ }
+}
+
+
+tool_run ()
+{
+ tool=$1
+ options=$2
+ run_if_fail=$3
+ echo "+ running $tool $options..."
+ $tool $options || {
+ echo
+ echo $tool failed
+ eval $run_if_fail
+ exit 1
+ }
+}
diff --git a/gst/gstvalve.c b/gst/gstvalve.c
new file mode 100644
index 0000000..702b3e5
--- /dev/null
+++ b/gst/gstvalve.c
@@ -0,0 +1,311 @@
+/*
+ * Farsight Voice+Video library
+ *
+ * Copyright 2007 Collabora Ltd,
+ * Copyright 2007 Nokia Corporation
+ * @author: Olivier Crete <olivier.crete@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+/**
+ * SECTION:element-valve
+ *
+ * The valve is a simple element that drops buffers when the #GstValve::drop
+ * property is set to %TRUE and lets then through otherwise.
+ *
+ * Any downstream error received while the #GstValve::drop property is %FALSE
+ * is ignored. So downstream element can be set to %GST_STATE_NULL and removed,
+ * without using pad blocking.
+ *
+ * Last reviewed on 2008-02-10 (0.10.11)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstvalve.h"
+
+#include <string.h>
+
+GST_DEBUG_CATEGORY (valve_debug);
+#define GST_CAT_DEFAULT (valve_debug)
+
+/* elementfactory information */
+static const GstElementDetails gst_valve_details =
+GST_ELEMENT_DETAILS ("Valve element",
+ "Filter",
+ "This element drops all packets when drop is TRUE",
+ "Olivier Crete <olivier.crete@collabora.co.uk>");
+
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+/* Valve signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+ ARG_DROP,
+};
+
+
+
+
+static void gst_valve_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_valve_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+static gboolean gst_valve_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_valve_buffer_alloc (GstPad * pad, guint64 offset,
+ guint size, GstCaps * caps, GstBuffer ** buf);
+static GstFlowReturn gst_valve_chain (GstPad * pad, GstBuffer * buffer);
+static GstCaps *gst_valve_getcaps (GstPad * pad);
+
+static void
+_do_init (GType type)
+{
+ GST_DEBUG_CATEGORY_INIT (valve_debug, "valve", 0, "Valve");
+}
+
+GST_BOILERPLATE_FULL (GstValve, gst_valve, GstElement,
+ GST_TYPE_ELEMENT, _do_init);
+
+static void
+gst_valve_base_init (gpointer klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&srctemplate));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&sinktemplate));
+
+ gst_element_class_set_details (element_class, &gst_valve_details);
+}
+
+static void
+gst_valve_class_init (GstValveClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_valve_set_property);
+ gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_valve_get_property);
+
+ g_object_class_install_property (gobject_class, ARG_DROP,
+ g_param_spec_boolean ("drop",
+ "Drops all buffers if TRUE",
+ "If this property if TRUE, the element will drop all buffers, if its FALSE, it will let them through",
+ FALSE, G_PARAM_READWRITE));
+
+ parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+gst_valve_init (GstValve * valve, GstValveClass * klass)
+{
+ valve->drop = FALSE;
+ valve->discont = FALSE;
+
+ valve->srcpad = gst_pad_new_from_static_template (&srctemplate, "src");
+ gst_pad_set_getcaps_function (valve->srcpad,
+ GST_DEBUG_FUNCPTR (gst_valve_getcaps));
+ gst_element_add_pad (GST_ELEMENT (valve), valve->srcpad);
+
+ valve->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
+ gst_pad_set_chain_function (valve->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_valve_chain));
+ gst_pad_set_event_function (valve->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_valve_event));
+ gst_pad_set_bufferalloc_function (valve->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_valve_buffer_alloc));
+ gst_pad_set_getcaps_function (valve->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_valve_getcaps));
+ gst_element_add_pad (GST_ELEMENT (valve), valve->sinkpad);
+}
+
+
+static void
+gst_valve_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstValve *valve = GST_VALVE (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ case ARG_DROP:
+ GST_OBJECT_LOCK (object);
+ valve->drop = g_value_get_boolean (value);
+ GST_OBJECT_UNLOCK (object);
+ break;
+ }
+}
+
+static void
+gst_valve_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstValve *valve = GST_VALVE (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ case ARG_DROP:
+ GST_OBJECT_LOCK (object);
+ g_value_set_boolean (value, valve->drop);
+ GST_OBJECT_UNLOCK (object);
+ break;
+ }
+}
+
+static GstFlowReturn
+gst_valve_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstValve *valve = GST_VALVE (gst_pad_get_parent_element (pad));
+ GstFlowReturn ret = GST_FLOW_OK;
+ gboolean drop;
+
+ GST_OBJECT_LOCK (GST_OBJECT (valve));
+ drop = valve->drop;
+
+ if (!drop && valve->discont) {
+ buffer = gst_buffer_make_metadata_writable (buffer);
+ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
+ valve->discont = FALSE;
+ }
+ GST_OBJECT_UNLOCK (GST_OBJECT (valve));
+
+ if (drop)
+ gst_buffer_unref (buffer);
+ else
+ ret = gst_pad_push (valve->srcpad, buffer);
+
+
+ GST_OBJECT_LOCK (GST_OBJECT (valve));
+ if (valve->drop)
+ ret = GST_FLOW_OK;
+ GST_OBJECT_UNLOCK (GST_OBJECT (valve));
+
+ gst_object_unref (valve);
+
+ return ret;
+}
+
+
+static gboolean
+gst_valve_event (GstPad * pad, GstEvent * event)
+{
+ GstValve *valve = GST_VALVE (gst_pad_get_parent_element (pad));
+ gboolean ret = TRUE;
+ gboolean drop;
+
+ GST_OBJECT_LOCK (GST_OBJECT (valve));
+ drop = valve->drop;
+ GST_OBJECT_UNLOCK (GST_OBJECT (valve));
+
+ if (drop)
+ gst_event_unref (event);
+ else
+ ret = gst_pad_push_event (valve->srcpad, event);
+
+ GST_OBJECT_LOCK (GST_OBJECT (valve));
+ if (valve->drop)
+ ret = TRUE;
+ GST_OBJECT_UNLOCK (GST_OBJECT (valve));
+
+ gst_object_unref (valve);
+ return ret;
+}
+
+static GstFlowReturn
+gst_valve_buffer_alloc (GstPad * pad, guint64 offset, guint size,
+ GstCaps * caps, GstBuffer ** buf)
+{
+ GstValve *valve = GST_VALVE (gst_pad_get_parent_element (pad));
+ GstFlowReturn ret = GST_FLOW_OK;
+ gboolean drop;
+
+ GST_OBJECT_LOCK (GST_OBJECT (valve));
+ drop = valve->drop;
+ GST_OBJECT_UNLOCK (GST_OBJECT (valve));
+
+ if (drop)
+ *buf = NULL;
+ else
+ ret = gst_pad_alloc_buffer (valve->srcpad, offset, size, caps, buf);
+
+ GST_OBJECT_LOCK (GST_OBJECT (valve));
+ if (valve->drop)
+ ret = GST_FLOW_OK;
+ GST_OBJECT_UNLOCK (GST_OBJECT (valve));
+
+ gst_object_unref (valve);
+
+ return ret;
+}
+
+static GstCaps *
+gst_valve_getcaps (GstPad * pad)
+{
+ GstValve *valve = GST_VALVE (gst_pad_get_parent (pad));
+ GstCaps *caps;
+
+ if (pad == valve->sinkpad)
+ caps = gst_pad_peer_get_caps (valve->srcpad);
+ else
+ caps = gst_pad_peer_get_caps (valve->sinkpad);
+
+ if (caps == NULL)
+ caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+
+ gst_object_unref (valve);
+
+ return caps;
+}
+
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "valve",
+ GST_RANK_MARGINAL, GST_TYPE_VALVE);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "valve",
+ "Valve",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/gstvalve.h b/gst/gstvalve.h
new file mode 100644
index 0000000..cc7cd38
--- /dev/null
+++ b/gst/gstvalve.h
@@ -0,0 +1,82 @@
+/*
+ * Farsight Voice+Video library
+ *
+ * Copyright 2007 Collabora Ltd,
+ * Copyright 2007 Nokia Corporation
+ * @author: Olivier Crete <olivier.crete@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __GST_VALVE_H__
+#define __GST_VALVE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+/* #define's don't like whitespacey bits */
+#define GST_TYPE_VALVE \
+ (gst_valve_get_type())
+#define GST_VALVE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ GST_TYPE_VALVE,GstValve))
+#define GST_VALVE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), \
+ GST_TYPE_VALVE,GstValveClass))
+#define GST_IS_VALVE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VALVE))
+#define GST_IS_VALVE_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VALVE))
+typedef struct _GstValve GstValve;
+typedef struct _GstValveClass GstValveClass;
+typedef struct _GstValvePrivate GstValvePrivate;
+
+/**
+ * GstValve:
+ *
+ * The private valve structure
+ */
+struct _GstValve
+{
+ /*< private >*/
+ GstElement parent;
+
+ /* Protected by the object lock */
+ gboolean drop;
+
+ /* Protected by the stream lock */
+ gboolean discont;
+
+ GstPad *srcpad;
+ GstPad *sinkpad;
+
+ /*< private > */
+ gpointer _gst_reserved[GST_PADDING];
+};
+
+struct _GstValveClass
+{
+ GstElementClass parent_class;
+
+ /*< private > */
+ gpointer _gst_reserved[GST_PADDING];
+};
+
+GType gst_valve_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_VALVE_H__ */
diff --git a/gst/gstvideorate.c b/gst/gstvideorate.c
new file mode 100644
index 0000000..b728357
--- /dev/null
+++ b/gst/gstvideorate.c
@@ -0,0 +1,877 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-videorate
+ *
+ * This element takes an incoming stream of timestamped video frames.
+ * It will produce a perfect stream that matches the source pad's framerate.
+ *
+ * The correction is performed by dropping and duplicating frames, no fancy
+ * algorithm is used to interpolate frames (yet).
+ *
+ * By default the element will simply negotiate the same framerate on its
+ * source and sink pad.
+ *
+ * This operation is useful to link to elements that require a perfect stream.
+ * Typical examples are formats that do not store timestamps for video frames,
+ * but only store a framerate, like Ogg and AVI.
+ *
+ * A conversion to a specific framerate can be forced by using filtered caps on
+ * the source pad.
+ *
+ * The properties #GstVideoRate:in, #GstVideoRate:out, #GstVideoRate:duplicate
+ * and #GstVideoRate:drop can be read to obtain information about number of
+ * input frames, output frames, dropped frames (i.e. the number of unused input
+ * frames) and duplicated frames (i.e. the number of times an input frame was
+ * duplicated, beside being used normally).
+ *
+ * An input stream that needs no adjustments will thus never have dropped or
+ * duplicated frames.
+ *
+ * When the #GstVideoRate:silent property is set to FALSE, a GObject property
+ * notification will be emitted whenever one of the #GstVideoRate:duplicate or
+ * #GstVideoRate:drop values changes.
+ * This can potentially cause performance degradation.
+ * Note that property notification will happen from the streaming thread, so
+ * applications should be prepared for this.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videorate ! video/x-raw-yuv,framerate=15/1 ! xvimagesink
+ * ]| Decode an Ogg/Theora file and adjust the framerate to 15 fps before playing.
+ * To create the test Ogg/Theora file refer to the documentation of theoraenc.
+ * |[
+ * gst-launch -v v4lsrc ! videorate ! video/x-raw-yuv,framerate=25/2 ! theoraenc ! oggmux ! filesink location=v4l.ogg
+ * ]| Capture video from a V4L device, and adjust the stream to 12.5 fps before
+ * encoding to Ogg/Theora.
+ * </refsect2>
+ *
+ * Last reviewed on 2006-09-02 (0.10.11)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstvideorate.h"
+
+GST_DEBUG_CATEGORY_STATIC (video_rate_debug);
+#define GST_CAT_DEFAULT video_rate_debug
+
+/* elementfactory information */
+static const GstElementDetails video_rate_details =
+GST_ELEMENT_DETAILS ("Video rate adjuster",
+ "Filter/Effect/Video",
+ "Drops/duplicates/adjusts timestamps on video frames to make a perfect stream",
+ "Wim Taymans <wim@fluendo.com>");
+
+/* GstVideoRate signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+#define DEFAULT_SILENT TRUE
+#define DEFAULT_NEW_PREF 1.0
+#define DEFAULT_SKIP_TO_FIRST FALSE
+
+enum
+{
+ ARG_0,
+ ARG_IN,
+ ARG_OUT,
+ ARG_DUP,
+ ARG_DROP,
+ ARG_SILENT,
+ ARG_NEW_PREF,
+ ARG_SKIP_TO_FIRST
+ /* FILL ME */
+};
+
+static GstStaticPadTemplate gst_video_rate_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw-yuv; video/x-raw-rgb; image/jpeg; image/png")
+ );
+
+static GstStaticPadTemplate gst_video_rate_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw-yuv; video/x-raw-rgb; image/jpeg; image/png")
+ );
+
+static void gst_video_rate_swap_prev (GstVideoRate * videorate,
+ GstBuffer * buffer, gint64 time);
+static gboolean gst_video_rate_event (GstPad * pad, GstEvent * event);
+static gboolean gst_video_rate_query (GstPad * pad, GstQuery * query);
+static GstFlowReturn gst_video_rate_chain (GstPad * pad, GstBuffer * buffer);
+
+static void gst_video_rate_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_video_rate_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn gst_video_rate_change_state (GstElement * element,
+ GstStateChange transition);
+
+/*static guint gst_video_rate_signals[LAST_SIGNAL] = { 0 }; */
+
+GST_BOILERPLATE (GstVideoRate, gst_video_rate, GstElement, GST_TYPE_ELEMENT);
+
+static void
+gst_video_rate_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details (element_class, &video_rate_details);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_video_rate_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_video_rate_src_template));
+}
+static void
+gst_video_rate_class_init (GstVideoRateClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->set_property = gst_video_rate_set_property;
+ object_class->get_property = gst_video_rate_get_property;
+
+ g_object_class_install_property (object_class, ARG_IN,
+ g_param_spec_uint64 ("in", "In",
+ "Number of input frames", 0, G_MAXUINT64, 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, ARG_OUT,
+ g_param_spec_uint64 ("out", "Out", "Number of output frames", 0,
+ G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, ARG_DUP,
+ g_param_spec_uint64 ("duplicate", "Duplicate",
+ "Number of duplicated frames", 0, G_MAXUINT64, 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, ARG_DROP,
+ g_param_spec_uint64 ("drop", "Drop", "Number of dropped frames", 0,
+ G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, ARG_SILENT,
+ g_param_spec_boolean ("silent", "silent",
+ "Don't emit notify for dropped and duplicated frames", DEFAULT_SILENT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, ARG_NEW_PREF,
+ g_param_spec_double ("new-pref", "New Pref",
+ "Value indicating how much to prefer new frames (unused)", 0.0, 1.0,
+ DEFAULT_NEW_PREF, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, ARG_SKIP_TO_FIRST,
+ g_param_spec_boolean ("skip-to-first", "Skip to first buffer",
+ "Don't produce buffers before the first one we receive",
+ DEFAULT_SKIP_TO_FIRST,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ element_class->change_state = gst_video_rate_change_state;
+}
+
+/* return the caps that can be used on out_pad given in_caps on in_pad */
+static gboolean
+gst_video_rate_transformcaps (GstPad * in_pad, GstCaps * in_caps,
+ GstPad * out_pad, GstCaps ** out_caps)
+{
+ GstCaps *intersect;
+ const GstCaps *in_templ;
+ gint i;
+
+ in_templ = gst_pad_get_pad_template_caps (in_pad);
+ intersect = gst_caps_intersect (in_caps, in_templ);
+
+ /* all possible framerates are allowed */
+ for (i = 0; i < gst_caps_get_size (intersect); i++) {
+ GstStructure *structure;
+
+ structure = gst_caps_get_structure (intersect, i);
+
+ gst_structure_set (structure,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
+ }
+ *out_caps = intersect;
+
+ return TRUE;
+}
+
+static GstCaps *
+gst_video_rate_getcaps (GstPad * pad)
+{
+ GstVideoRate *videorate;
+ GstPad *otherpad;
+ GstCaps *caps;
+
+ videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad));
+
+ otherpad = (pad == videorate->srcpad) ? videorate->sinkpad :
+ videorate->srcpad;
+
+ /* we can do what the peer can */
+ caps = gst_pad_peer_get_caps (otherpad);
+ if (caps) {
+ GstCaps *transform;
+
+ gst_video_rate_transformcaps (otherpad, caps, pad, &transform);
+ gst_caps_unref (caps);
+ caps = transform;
+ } else {
+ /* no peer, our padtemplate is enough then */
+ caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+ }
+
+ return caps;
+}
+
+static gboolean
+gst_video_rate_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstVideoRate *videorate;
+ GstStructure *structure;
+ gboolean ret = TRUE;
+ GstPad *otherpad, *opeer;
+ gint rate_numerator, rate_denominator;
+
+ videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad));
+
+ GST_DEBUG ("setcaps called %" GST_PTR_FORMAT, caps);
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_get_fraction (structure, "framerate",
+ &rate_numerator, &rate_denominator))
+ goto no_framerate;
+
+ if (pad == videorate->srcpad) {
+ videorate->to_rate_numerator = rate_numerator;
+ videorate->to_rate_denominator = rate_denominator;
+ otherpad = videorate->sinkpad;
+ } else {
+ videorate->from_rate_numerator = rate_numerator;
+ videorate->from_rate_denominator = rate_denominator;
+ otherpad = videorate->srcpad;
+ }
+ /* now try to find something for the peer */
+ opeer = gst_pad_get_peer (otherpad);
+ if (opeer) {
+ if (gst_pad_accept_caps (opeer, caps)) {
+ /* the peer accepts the caps as they are */
+ gst_pad_set_caps (otherpad, caps);
+
+ ret = TRUE;
+ } else {
+ GstCaps *peercaps;
+ GstCaps *intersect;
+ GstCaps *transform = NULL;
+
+ ret = FALSE;
+
+ /* see how we can transform the input caps */
+ if (!gst_video_rate_transformcaps (pad, caps, otherpad, &transform))
+ goto no_transform;
+
+ /* see what the peer can do */
+ peercaps = gst_pad_get_caps (opeer);
+
+ GST_DEBUG ("icaps %" GST_PTR_FORMAT, peercaps);
+ GST_DEBUG ("transform %" GST_PTR_FORMAT, transform);
+
+ /* filter against our possibilities */
+ intersect = gst_caps_intersect (peercaps, transform);
+ gst_caps_unref (peercaps);
+ gst_caps_unref (transform);
+
+ GST_DEBUG ("intersect %" GST_PTR_FORMAT, intersect);
+
+ /* take first possibility */
+ caps = gst_caps_copy_nth (intersect, 0);
+ gst_caps_unref (intersect);
+ structure = gst_caps_get_structure (caps, 0);
+
+ /* and fixate */
+ gst_structure_fixate_field_nearest_fraction (structure, "framerate",
+ rate_numerator, rate_denominator);
+
+ gst_structure_get_fraction (structure, "framerate",
+ &rate_numerator, &rate_denominator);
+
+ if (otherpad == videorate->srcpad) {
+ videorate->to_rate_numerator = rate_numerator;
+ videorate->to_rate_denominator = rate_denominator;
+ } else {
+ videorate->from_rate_numerator = rate_numerator;
+ videorate->from_rate_denominator = rate_denominator;
+ }
+ gst_pad_set_caps (otherpad, caps);
+ gst_caps_unref (caps);
+ ret = TRUE;
+ }
+ gst_object_unref (opeer);
+ }
+done:
+ /* After a setcaps, our caps may have changed. In that case, we can't use
+ * the old buffer, if there was one (it might have different dimensions) */
+ GST_DEBUG ("swapping old buffers");
+ gst_video_rate_swap_prev (videorate, NULL, GST_CLOCK_TIME_NONE);
+
+ gst_object_unref (videorate);
+ return ret;
+
+no_framerate:
+ {
+ GST_DEBUG_OBJECT (videorate, "no framerate specified");
+ goto done;
+ }
+no_transform:
+ {
+ GST_DEBUG_OBJECT (videorate, "no framerate transform possible");
+ ret = FALSE;
+ goto done;
+ }
+}
+
+static void
+gst_video_rate_reset (GstVideoRate * videorate)
+{
+ GST_DEBUG ("resetting internal variables");
+
+ videorate->in = 0;
+ videorate->out = 0;
+ videorate->segment_out = 0;
+ videorate->drop = 0;
+ videorate->dup = 0;
+ videorate->next_ts = GST_CLOCK_TIME_NONE;
+ gst_video_rate_swap_prev (videorate, NULL, 0);
+
+ gst_segment_init (&videorate->segment, GST_FORMAT_TIME);
+}
+
+static void
+gst_video_rate_init (GstVideoRate * videorate, GstVideoRateClass * klass)
+{
+ GST_DEBUG ("gst_video_rate_init");
+ videorate->sinkpad =
+ gst_pad_new_from_static_template (&gst_video_rate_sink_template, "sink");
+ gst_pad_set_event_function (videorate->sinkpad, gst_video_rate_event);
+ gst_pad_set_chain_function (videorate->sinkpad, gst_video_rate_chain);
+ gst_pad_set_getcaps_function (videorate->sinkpad, gst_video_rate_getcaps);
+ gst_pad_set_setcaps_function (videorate->sinkpad, gst_video_rate_setcaps);
+ gst_element_add_pad (GST_ELEMENT (videorate), videorate->sinkpad);
+
+ videorate->srcpad =
+ gst_pad_new_from_static_template (&gst_video_rate_src_template, "src");
+ gst_pad_set_query_function (videorate->srcpad, gst_video_rate_query);
+ gst_pad_set_getcaps_function (videorate->srcpad, gst_video_rate_getcaps);
+ gst_pad_set_setcaps_function (videorate->srcpad, gst_video_rate_setcaps);
+ gst_element_add_pad (GST_ELEMENT (videorate), videorate->srcpad);
+
+ gst_video_rate_reset (videorate);
+ videorate->silent = DEFAULT_SILENT;
+ videorate->new_pref = DEFAULT_NEW_PREF;
+
+ videorate->from_rate_numerator = 0;
+ videorate->from_rate_denominator = 0;
+ videorate->to_rate_numerator = 0;
+ videorate->to_rate_denominator = 0;
+
+ videorate->first_pass_buffer = TRUE;
+}
+
+/* flush the oldest buffer */
+static GstFlowReturn
+gst_video_rate_flush_prev (GstVideoRate * videorate)
+{
+ GstFlowReturn res;
+ GstBuffer *outbuf;
+ GstClockTime push_ts;
+
+ if (!videorate->prevbuf)
+ goto eos_before_buffers;
+
+ /* make sure we can write to the metadata */
+ outbuf = gst_buffer_make_metadata_writable
+ (gst_buffer_ref (videorate->prevbuf));
+
+ GST_BUFFER_OFFSET (outbuf) = videorate->out;
+ GST_BUFFER_OFFSET_END (outbuf) = videorate->out + 1;
+
+ /* this is the timestamp we put on the buffer */
+ push_ts = videorate->next_ts;
+
+ videorate->out++;
+ videorate->segment_out++;
+ if (videorate->to_rate_numerator) {
+ /* interpolate next expected timestamp in the segment */
+ videorate->next_ts = videorate->segment.accum + videorate->segment.start +
+ gst_util_uint64_scale (videorate->segment_out,
+ videorate->to_rate_denominator * GST_SECOND,
+ videorate->to_rate_numerator);
+ GST_BUFFER_DURATION (outbuf) = videorate->next_ts - push_ts;
+ }
+
+ /* adapt for looping, bring back to time in current segment. */
+ GST_BUFFER_TIMESTAMP (outbuf) = push_ts - videorate->segment.accum;
+
+ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (videorate->srcpad));
+
+ GST_LOG_OBJECT (videorate,
+ "old is best, dup, pushing buffer outgoing ts %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (push_ts));
+
+ res = gst_pad_push (videorate->srcpad, outbuf);
+
+ return res;
+
+ /* WARNINGS */
+eos_before_buffers:
+ {
+ GST_INFO_OBJECT (videorate, "got EOS before any buffer was received");
+ return GST_FLOW_OK;
+ }
+}
+
+static void
+gst_video_rate_swap_prev (GstVideoRate * videorate, GstBuffer * buffer,
+ gint64 time)
+{
+ GST_LOG_OBJECT (videorate, "swap_prev: storing buffer %p in prev", buffer);
+ if (videorate->prevbuf)
+ gst_buffer_unref (videorate->prevbuf);
+ videorate->prevbuf = buffer;
+ videorate->prev_ts = time;
+}
+
+#define MAGIC_LIMIT 25
+static gboolean
+gst_video_rate_event (GstPad * pad, GstEvent * event)
+{
+ GstVideoRate *videorate;
+ gboolean ret;
+
+ videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_NEWSEGMENT:
+ {
+ gint64 start, stop, time;
+ gdouble rate, arate;
+ gboolean update;
+ GstFormat format;
+
+ gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
+ &start, &stop, &time);
+
+ if (format != GST_FORMAT_TIME)
+ goto format_error;
+
+ GST_DEBUG_OBJECT (videorate, "handle NEWSEGMENT");
+
+ /* close up the previous segment, if appropriate */
+ if (!update && videorate->prevbuf) {
+ gint count = 0;
+ GstFlowReturn res;
+
+ res = GST_FLOW_OK;
+ /* fill up to the end of current segment,
+ * or only send out the stored buffer if there is no specific stop.
+ * regardless, prevent going loopy in strange cases */
+ while (res == GST_FLOW_OK && count <= MAGIC_LIMIT &&
+ ((GST_CLOCK_TIME_IS_VALID (videorate->segment.stop) &&
+ videorate->next_ts - videorate->segment.accum
+ < videorate->segment.stop)
+ || count < 1)) {
+ gst_video_rate_flush_prev (videorate);
+ count++;
+ }
+ if (count > 1) {
+ videorate->dup += count - 1;
+ if (!videorate->silent)
+ g_object_notify (G_OBJECT (videorate), "duplicate");
+ } else if (count == 0) {
+ videorate->drop++;
+ if (!videorate->silent)
+ g_object_notify (G_OBJECT (videorate), "drop");
+ }
+ /* clean up for the new one; _chain will resume from the new start */
+ videorate->segment_out = 0;
+ gst_video_rate_swap_prev (videorate, NULL, 0);
+ videorate->next_ts = GST_CLOCK_TIME_NONE;
+ }
+
+ /* We just want to update the accumulated stream_time */
+ gst_segment_set_newsegment_full (&videorate->segment, update, rate, arate,
+ format, start, stop, time);
+
+ GST_DEBUG_OBJECT (videorate, "updated segment: %" GST_SEGMENT_FORMAT,
+ &videorate->segment);
+ break;
+ }
+ case GST_EVENT_EOS:
+ /* flush last queued frame */
+ GST_DEBUG_OBJECT (videorate, "Got EOS");
+ gst_video_rate_flush_prev (videorate);
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ /* also resets the segment */
+ GST_DEBUG_OBJECT (videorate, "Got FLUSH_STOP");
+ gst_video_rate_reset (videorate);
+ break;
+ default:
+ break;
+ }
+
+ ret = gst_pad_push_event (videorate->srcpad, event);
+
+done:
+ gst_object_unref (videorate);
+
+ return ret;
+
+ /* ERRORS */
+format_error:
+ {
+ GST_WARNING_OBJECT (videorate,
+ "Got segment but doesn't have GST_FORMAT_TIME value");
+ gst_event_unref (event);
+ ret = FALSE;
+ goto done;
+ }
+}
+
+static gboolean
+gst_video_rate_query (GstPad * pad, GstQuery * query)
+{
+ GstVideoRate *videorate;
+ gboolean res = FALSE;
+
+ videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad));
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_LATENCY:
+ {
+ GstClockTime min, max;
+ gboolean live;
+ guint64 latency;
+ GstPad *peer;
+
+ if ((peer = gst_pad_get_peer (videorate->sinkpad))) {
+ if ((res = gst_pad_query (peer, query))) {
+ gst_query_parse_latency (query, &live, &min, &max);
+
+ GST_DEBUG_OBJECT (videorate, "Peer latency: min %"
+ GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (min), GST_TIME_ARGS (max));
+
+ /* add latency. We don't really know since we hold on to the frames
+ * until we get a next frame, which can be anything. We assume
+ * however that this will take from_rate time. */
+ latency = gst_util_uint64_scale (GST_SECOND,
+ videorate->from_rate_denominator, videorate->from_rate_numerator);
+
+ GST_DEBUG_OBJECT (videorate, "Our latency: %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (latency));
+
+ min += latency;
+ if (max != -1)
+ max += latency;
+
+ GST_DEBUG_OBJECT (videorate, "Calculated total latency : min %"
+ GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (min), GST_TIME_ARGS (max));
+
+ gst_query_set_latency (query, live, min, max);
+ }
+ gst_object_unref (peer);
+ }
+ break;
+ }
+ default:
+ res = gst_pad_query_default (pad, query);
+ break;
+ }
+ gst_object_unref (videorate);
+
+ return res;
+}
+
+static GstFlowReturn
+gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstVideoRate *videorate;
+ GstFlowReturn res = GST_FLOW_OK;
+ GstClockTime intime, in_ts;
+
+ videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad));
+
+ /* make sure the denominators are not 0 */
+ if (videorate->from_rate_denominator == 0 ||
+ videorate->to_rate_denominator == 0)
+ goto not_negotiated;
+
+ in_ts = GST_BUFFER_TIMESTAMP (buffer);
+
+ if (G_UNLIKELY (in_ts == GST_CLOCK_TIME_NONE))
+ goto invalid_buffer;
+
+ GST_DEBUG_OBJECT (videorate, "got buffer with timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (in_ts));
+
+ /* the input time is the time in the segment + all previously accumulated
+ * segments */
+ intime = in_ts + videorate->segment.accum;
+
+ /* we need to have two buffers to compare */
+ if (videorate->prevbuf == NULL) {
+ gst_video_rate_swap_prev (videorate, buffer, intime);
+ videorate->in++;
+ if (!GST_CLOCK_TIME_IS_VALID (videorate->next_ts)) {
+ /* new buffer, we expect to output a buffer that matches the first
+ * timestamp in the segment */
+ if (videorate->skip_to_first) {
+ videorate->next_ts = in_ts;
+ videorate->segment_out = gst_util_uint64_scale (in_ts,
+ videorate->to_rate_numerator,
+ videorate->to_rate_denominator * GST_SECOND) -
+ (videorate->segment.accum + videorate->segment.start);
+ }
+ else {
+ videorate->next_ts = videorate->segment.start + videorate->segment.accum;
+ }
+ }
+ } else {
+ GstClockTime prevtime;
+ gint count = 0;
+ gint64 diff1, diff2;
+
+ prevtime = videorate->prev_ts;
+
+ GST_LOG_OBJECT (videorate,
+ "BEGINNING prev buf %" GST_TIME_FORMAT " new buf %" GST_TIME_FORMAT
+ " outgoing ts %" GST_TIME_FORMAT, GST_TIME_ARGS (prevtime),
+ GST_TIME_ARGS (intime), GST_TIME_ARGS (videorate->next_ts));
+
+ videorate->in++;
+
+ /* drop new buffer if it's before previous one */
+ if (intime < prevtime) {
+ GST_DEBUG_OBJECT (videorate,
+ "The new buffer (%" GST_TIME_FORMAT
+ ") is before the previous buffer (%"
+ GST_TIME_FORMAT "). Dropping new buffer.",
+ GST_TIME_ARGS (intime), GST_TIME_ARGS (prevtime));
+ videorate->drop++;
+ if (!videorate->silent)
+ g_object_notify (G_OBJECT (videorate), "drop");
+ gst_buffer_unref (buffer);
+ goto done;
+ }
+
+ /* got 2 buffers, see which one is the best */
+ do {
+
+ diff1 = prevtime - videorate->next_ts;
+ diff2 = intime - videorate->next_ts;
+
+ /* take absolute values, beware: abs and ABS don't work for gint64 */
+ if (diff1 < 0)
+ diff1 = -diff1;
+ if (diff2 < 0)
+ diff2 = -diff2;
+
+ GST_LOG_OBJECT (videorate,
+ "diff with prev %" GST_TIME_FORMAT " diff with new %"
+ GST_TIME_FORMAT " outgoing ts %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (diff1), GST_TIME_ARGS (diff2),
+ GST_TIME_ARGS (videorate->next_ts));
+
+ /* output first one when its the best */
+ if (diff1 < diff2) {
+ count++;
+
+ /* on error the _flush function posted a warning already */
+ if ((res = gst_video_rate_flush_prev (videorate)) != GST_FLOW_OK) {
+ gst_buffer_unref (buffer);
+ goto done;
+ }
+
+ // XXX let downstream theoraenc treat first buffer
+ // as a buffer with keyframe
+ if (videorate->first_pass_buffer == TRUE) {
+ videorate->first_pass_buffer = FALSE;
+ break;
+ }
+ }
+ /* continue while the first one was the best */
+ }
+ while (diff1 < diff2);
+
+ /* if we outputed the first buffer more then once, we have dups */
+ if (count > 1) {
+ videorate->dup += count - 1;
+ if (!videorate->silent)
+ g_object_notify (G_OBJECT (videorate), "duplicate");
+ }
+ /* if we didn't output the first buffer, we have a drop */
+ else if (count == 0) {
+ videorate->drop++;
+
+ if (!videorate->silent)
+ g_object_notify (G_OBJECT (videorate), "drop");
+
+ GST_LOG_OBJECT (videorate,
+ "new is best, old never used, drop, outgoing ts %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (videorate->next_ts));
+ }
+ GST_LOG_OBJECT (videorate,
+ "END, putting new in old, diff1 %" GST_TIME_FORMAT
+ ", diff2 %" GST_TIME_FORMAT ", next_ts %" GST_TIME_FORMAT
+ ", in %lld, out %lld, drop %lld, dup %lld", GST_TIME_ARGS (diff1),
+ GST_TIME_ARGS (diff2), GST_TIME_ARGS (videorate->next_ts),
+ videorate->in, videorate->out, videorate->drop, videorate->dup);
+
+ /* swap in new one when it's the best */
+ gst_video_rate_swap_prev (videorate, buffer, intime);
+ }
+done:
+ return res;
+
+ /* ERRORS */
+not_negotiated:
+ {
+ GST_WARNING_OBJECT (videorate, "no framerate negotiated");
+ gst_buffer_unref (buffer);
+ res = GST_FLOW_NOT_NEGOTIATED;
+ goto done;
+ }
+
+invalid_buffer:
+ {
+ GST_WARNING_OBJECT (videorate,
+ "Got buffer with GST_CLOCK_TIME_NONE timestamp, discarding it");
+ gst_buffer_unref (buffer);
+ goto done;
+ }
+}
+
+static void
+gst_video_rate_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstVideoRate *videorate = GST_VIDEO_RATE (object);
+
+ switch (prop_id) {
+ case ARG_SILENT:
+ videorate->silent = g_value_get_boolean (value);
+ break;
+ case ARG_NEW_PREF:
+ videorate->new_pref = g_value_get_double (value);
+ break;
+ case ARG_SKIP_TO_FIRST:
+ videorate->skip_to_first = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_video_rate_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstVideoRate *videorate = GST_VIDEO_RATE (object);
+
+ switch (prop_id) {
+ case ARG_IN:
+ g_value_set_uint64 (value, videorate->in);
+ break;
+ case ARG_OUT:
+ g_value_set_uint64 (value, videorate->out);
+ break;
+ case ARG_DUP:
+ g_value_set_uint64 (value, videorate->dup);
+ break;
+ case ARG_DROP:
+ g_value_set_uint64 (value, videorate->drop);
+ break;
+ case ARG_SILENT:
+ g_value_set_boolean (value, videorate->silent);
+ break;
+ case ARG_NEW_PREF:
+ g_value_set_double (value, videorate->new_pref);
+ break;
+ case ARG_SKIP_TO_FIRST:
+ g_value_set_boolean (value, videorate->skip_to_first);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstStateChangeReturn
+gst_video_rate_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstVideoRate *videorate;
+
+ videorate = GST_VIDEO_RATE (element);
+
+ switch (transition) {
+ default:
+ break;
+ }
+
+ ret = parent_class->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_video_rate_reset (videorate);
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ videorate->first_pass_buffer = TRUE;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (video_rate_debug, "videorate", 0,
+ "VideoRate stream fixer");
+
+ return gst_element_register (plugin, "videorate", GST_RANK_NONE,
+ GST_TYPE_VIDEO_RATE);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "videorate",
+ "Adjusts video frames",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/gstvideorate.h b/gst/gstvideorate.h
new file mode 100644
index 0000000..01abcae
--- /dev/null
+++ b/gst/gstvideorate.h
@@ -0,0 +1,81 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_VIDEO_RATE_H__
+#define __GST_VIDEO_RATE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VIDEO_RATE \
+ (gst_video_rate_get_type())
+#define GST_VIDEO_RATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_RATE,GstVideoRate))
+#define GST_VIDEO_RATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_RATE,GstVideoRateClass))
+#define GST_IS_VIDEO_RATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_RATE))
+#define GST_IS_VIDEO_RATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_RATE))
+
+typedef struct _GstVideoRate GstVideoRate;
+typedef struct _GstVideoRateClass GstVideoRateClass;
+
+/**
+ * GstVideoRate:
+ *
+ * Opaque data structure.
+ */
+struct _GstVideoRate
+{
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+
+ /* video state */
+ gint from_rate_numerator, from_rate_denominator;
+ gint to_rate_numerator, to_rate_denominator;
+ guint64 next_ts; /* Timestamp of next buffer to output */
+ GstBuffer *prevbuf;
+ guint64 prev_ts; /* Previous buffer timestamp */
+ guint64 segment_out; /* in-segment counting */
+
+ /* segment handling */
+ GstSegment segment;
+
+ /* properties */
+ guint64 in, out, dup, drop;
+ gboolean silent;
+ gdouble new_pref;
+ gboolean skip_to_first;
+
+ // XXX let downstream theoraenc treat first buffer
+ // as a buffer with keyframe
+ gboolean first_pass_buffer;
+};
+
+struct _GstVideoRateClass
+{
+ GstElementClass parent_class;
+};
+
+G_END_DECLS
+
+#endif /* __GST_VIDEO_RATE_H__ */
diff --git a/gst/m4/Makefile.am b/gst/m4/Makefile.am
new file mode 100644
index 0000000..4a44032
--- /dev/null
+++ b/gst/m4/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = as-version.m4 as-compiler-flag.m4
diff --git a/gst/m4/as-compiler-flag.m4 b/gst/m4/as-compiler-flag.m4
new file mode 100644
index 0000000..2f0ba19
--- /dev/null
+++ b/gst/m4/as-compiler-flag.m4
@@ -0,0 +1,25 @@
+dnl as-compiler-flag.m4 0.0.1
+dnl autostars m4 macro for detection of compiler flags
+dnl
+dnl ds@schleef.org
+
+AC_DEFUN([AS_COMPILER_FLAG],
+[
+ AC_MSG_CHECKING([to see if compiler understands $1])
+
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $1"
+
+ AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
+ CFLAGS="$save_CFLAGS"
+
+ if test "X$flag_ok" = Xyes ; then
+ $2
+ true
+ else
+ $3
+ true
+ fi
+ AC_MSG_RESULT([$flag_ok])
+])
+
diff --git a/gst/m4/as-version.m4 b/gst/m4/as-version.m4
new file mode 100644
index 0000000..0bee437
--- /dev/null
+++ b/gst/m4/as-version.m4
@@ -0,0 +1,66 @@
+dnl as-version.m4 0.1.0
+
+dnl autostars m4 macro for versioning
+
+dnl Thomas Vander Stichele <thomas at apestaart dot org>
+
+dnl $Id: as-version.m4,v 1.2 2004-09-17 22:18:03 leroutier Exp $
+
+dnl AS_VERSION(PACKAGE, PREFIX, MAJOR, MINOR, MICRO, NANO,
+dnl ACTION-IF-NO-NANO, [ACTION-IF-NANO])
+
+dnl example
+dnl AS_VERSION(gstreamer, GST_VERSION, 0, 3, 2,)
+dnl for a 0.3.2 release version
+
+dnl this macro
+dnl - defines [$PREFIX]_MAJOR, MINOR and MICRO
+dnl - if NANO is empty, then we're in release mode, else in cvs/dev mode
+dnl - defines [$PREFIX], VERSION, and [$PREFIX]_RELEASE
+dnl - executes the relevant action
+dnl - AC_SUBST's PACKAGE, VERSION, [$PREFIX] and [$PREFIX]_RELEASE
+dnl as well as the little ones
+dnl - doesn't call AM_INIT_AUTOMAKE anymore because it prevents
+dnl maintainer mode from running ok
+dnl
+dnl don't forget to put #undef [$2] and [$2]_RELEASE in acconfig.h
+dnl if you use acconfig.h
+
+AC_DEFUN([AS_VERSION],
+[
+ PACKAGE=[$1]
+ [$2]_MAJOR=[$3]
+ [$2]_MINOR=[$4]
+ [$2]_MICRO=[$5]
+ NANO=[$6]
+ [$2]_NANO=$NANO
+ if test "x$NANO" = "x" || test "x$NANO" = "x0";
+ then
+ AC_MSG_NOTICE(configuring [$1] for release)
+ VERSION=[$3].[$4].[$5]
+ [$2]_RELEASE=1
+ dnl execute action
+ ifelse([$7], , :, [$7])
+ else
+ AC_MSG_NOTICE(configuring [$1] for development with nano $NANO)
+ VERSION=[$3].[$4].[$5].$NANO
+ [$2]_RELEASE=0.`date +%Y%m%d.%H%M%S`
+ dnl execute action
+ ifelse([$8], , :, [$8])
+ fi
+
+ [$2]=$VERSION
+ AC_DEFINE_UNQUOTED([$2], "$[$2]", [Define the version])
+ AC_SUBST([$2])
+ AC_DEFINE_UNQUOTED([$2]_RELEASE, "$[$2]_RELEASE", [Define the release version])
+ AC_SUBST([$2]_RELEASE)
+
+ AC_SUBST([$2]_MAJOR)
+ AC_SUBST([$2]_MINOR)
+ AC_SUBST([$2]_MICRO)
+ AC_SUBST([$2]_NANO)
+ AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Define the package name])
+ AC_SUBST(PACKAGE)
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Define the version])
+ AC_SUBST(VERSION)
+])
diff --git a/instance.py b/instance.py
index 1ab5407..d0178df 100644
--- a/instance.py
+++ b/instance.py
@@ -9,41 +9,41 @@ from color import Color
import record
class Instance:
- key = profile.get_pubkey()
- if hasattr(util, '_sha_data'):
- # sugar-0.82 and previous
- keyHash = util._sha_data(key)
- else:
- keyHash = util.sha_data(key)
+ key = profile.get_pubkey()
+ if hasattr(util, '_sha_data'):
+ # sugar-0.82 and previous
+ keyHash = util._sha_data(key)
+ else:
+ keyHash = util.sha_data(key)
- keyHashPrintable = util.printable_hash(keyHash)
- nickName = profile.get_nick_name()
+ keyHashPrintable = util.printable_hash(keyHash)
+ nickName = profile.get_nick_name()
- colorFill = Color()
- colorFill.init_hex( profile.get_color().get_fill_color() )
- colorStroke = Color()
- colorStroke.init_hex( profile.get_color().get_stroke_color() )
+ colorFill = Color()
+ colorFill.init_hex( profile.get_color().get_fill_color() )
+ colorStroke = Color()
+ colorStroke.init_hex( profile.get_color().get_stroke_color() )
- instanceId = None
- instancePath = None
- dataPath = None
+ instanceId = None
+ instancePath = None
+ dataPath = None
- def __init__(self, ca):
- self.__class__.instanceId = ca._activity_id
+ def __init__(self, ca):
+ self.__class__.instanceId = ca._activity_id
- self.__class__.instancePath = os.path.join(ca.get_activity_root(), "instance")
- recreateTmp()
+ self.__class__.instancePath = os.path.join(ca.get_activity_root(), "instance")
+ recreateTmp()
- self.__class__.dataPath = os.path.join(ca.get_activity_root(), "data")
- recreateData()
+ self.__class__.dataPath = os.path.join(ca.get_activity_root(), "data")
+ recreateData()
def recreateTmp():
- if (not os.path.exists(Instance.instancePath)):
- os.makedirs(Instance.instancePath)
+ if (not os.path.exists(Instance.instancePath)):
+ os.makedirs(Instance.instancePath)
def recreateData():
- if (not os.path.exists(Instance.dataPath)):
- os.makedirs(Instance.dataPath)
+ if (not os.path.exists(Instance.dataPath)):
+ os.makedirs(Instance.dataPath)
diff --git a/model.py b/model.py
index 15c4553..2126dc4 100644
--- a/model.py
+++ b/model.py
@@ -20,6 +20,7 @@
#THE SOFTWARE.
+import uuid
import urllib
import string
import fnmatch
@@ -37,6 +38,9 @@ from time import strftime
import gobject
import operator
+import logging
+logger = logging.getLogger('record:model.py')
+
import sugar.env
from constants import Constants
@@ -50,410 +54,405 @@ import serialize
class Model:
- def __init__( self, pca ):
- self.ca = pca
- self.MODE = Constants.MODE_PHOTO
- self.UPDATING = True
- self.RECORDING = False
- self.FULL = self._isXoFull()
+ def __init__( self, pca ):
+ self.ca = pca
+ self.MODE = Constants.MODE_PHOTO
+ self.UPDATING = True
+ self.RECORDING = False
+ self.FULL = self._isXoFull()
+
+ self.mediaHashs = {}
+ for key,value in Constants.mediaTypes.items():
+ self.mediaHashs[key] = []
+
+
+ def updateXoFullStatus( self ):
+ self.FULL = self._isXoFull()
+
+
+ def _isXoFull( self ):
+ full = False
+ if (utils.getFreespaceKb() <= Constants.keepFreeKbOnXo):
+ full = True
+
+ return full
+
+
+ def getRecdByMd5( self, md5 ):
+ for mh in range (0, len(self.mediaHashs)):
+ for r in range (0, len(self.mediaHashs[mh])):
+ recd = self.mediaHashs[mh][r]
+ if (recd.thumbMd5 == md5):
+ return recd
+ elif (recd.mediaMd5 == md5):
+ return recd
+
+ return None
+
+
+ def isVideoMode( self ):
+ return self.MODE == Constants.MODE_VIDEO
+
+
+ def isPhotoMode( self ):
+ return self.MODE == Constants.MODE_PHOTO
+
+
+ def displayThumb( self, recd, forceUpdating ):
+ #to avoid Xlib: unexpected async reply error when taking a picture on a gst callback, always call with idle_add
+ #this happens b/c this might get called from a gstreamer callback
+ if (not recd.type == self.MODE):
+ return
+
+ if (forceUpdating):
+ self.setUpdating( True )
+ hash = self.mediaHashs[recd.type]
+ if (len(hash) > 0):
+ self.ca.ui.addThumb(recd, forceUpdating)
+ if (forceUpdating):
+ self.setUpdating( False )
+
+
+ def setupMode( self, type, update ):
+ if (not type == self.MODE):
+ return
+
+ self.setUpdating( True )
+ self.ca.ui.removeThumbs()
+ hash = self.mediaHashs[type]
+ for i in range (0, len(hash)):
+ self.ca.ui.addThumb( hash[i], True )
+ if (update):
+ self.ca.ui.updateModeChange()
+ self.setUpdating(False)
+
+
+ def showNextThumb( self, shownRecd ):
+ if (shownRecd == None):
+ self.showLastThumb()
+ else:
+ hash = self.mediaHashs[self.MODE]
+ if (len(hash) > 0):
+ hash = self.mediaHashs[self.MODE]
+ i = operator.indexOf( hash, shownRecd )
+ i = i+1
+ if (i>=len(hash)):
+ i = 0
+ self.ca.ui.showThumbSelection( hash[i] )
+
+
+ def showPrevThumb( self, shownRecd ):
+ if (shownRecd == None):
+ self.showLastThumb()
+ else:
+ hash = self.mediaHashs[self.MODE]
+ if (len(hash) > 0):
+ hash = self.mediaHashs[self.MODE]
+ i = operator.indexOf( hash, shownRecd )
+ i = i-1
+ if (i<0):
+ i = len(hash)-1
+ self.ca.ui.showThumbSelection( hash[i] )
- self.mediaHashs = {}
- for key,value in Constants.mediaTypes.items():
- self.mediaHashs[key] = []
+ def showLastThumb( self ):
+ hash = self.mediaHashs[self.MODE]
+ if (len(hash) > 0):
+ self.ca.ui.showThumbSelection( hash[len(hash)-1] )
- def updateXoFullStatus( self ):
- self.FULL = self._isXoFull()
+ def doShutter( self ):
+ if (self.UPDATING):
+ return
+
+ if (self.MODE == Constants.MODE_PHOTO):
+ self.startTakingPhoto()
+ elif (self.MODE == Constants.MODE_VIDEO):
+ if (not self.RECORDING):
+ self.startRecordingVideo()
+ else:
+ #post-processing begins now, so queue up this gfx
+ self.ca.ui.showPostProcessGfx(True)
+ self.stopRecordingVideo()
+ elif (self.MODE == Constants.MODE_AUDIO):
+ if (not self.RECORDING):
+ self.startRecordingAudio()
+ else:
+ #post-processing begins now, so queue up this gfx
+ self.ca.ui.showPostProcessGfx(True)
+ self.stopRecordingAudio()
- def _isXoFull( self ):
- full = False
- if (utils.getFreespaceKb() <= Constants.keepFreeKbOnXo):
- full = True
-
- return full
-
-
- def getRecdByMd5( self, md5 ):
- for mh in range (0, len(self.mediaHashs)):
- for r in range (0, len(self.mediaHashs[mh])):
- recd = self.mediaHashs[mh][r]
- if (recd.thumbMd5 == md5):
- return recd
- elif (recd.mediaMd5 == md5):
- return recd
-
- return None
-
-
- def isVideoMode( self ):
- return self.MODE == Constants.MODE_VIDEO
-
-
- def isPhotoMode( self ):
- return self.MODE == Constants.MODE_PHOTO
-
-
- def displayThumb( self, recd, forceUpdating ):
- #to avoid Xlib: unexpected async reply error when taking a picture on a gst callback, always call with idle_add
- #this happens b/c this might get called from a gstreamer callback
- if (not recd.type == self.MODE):
- return
-
- if (forceUpdating):
- self.setUpdating( True )
- hash = self.mediaHashs[recd.type]
- if (len(hash) > 0):
- self.ca.ui.addThumb(recd, forceUpdating)
- if (forceUpdating):
- self.setUpdating( False )
-
-
- def setupMode( self, type, update ):
- if (not type == self.MODE):
- return
-
- self.setUpdating( True )
- self.ca.ui.removeThumbs()
- hash = self.mediaHashs[type]
- for i in range (0, len(hash)):
- self.ca.ui.addThumb( hash[i], True )
- if (update):
- self.ca.ui.updateModeChange()
- self.setUpdating(False)
-
-
- def showNextThumb( self, shownRecd ):
- if (shownRecd == None):
- self.showLastThumb()
- else:
- hash = self.mediaHashs[self.MODE]
- if (len(hash) > 0):
- hash = self.mediaHashs[self.MODE]
- i = operator.indexOf( hash, shownRecd )
- i = i+1
- if (i>=len(hash)):
- i = 0
- self.ca.ui.showThumbSelection( hash[i] )
-
- def showPrevThumb( self, shownRecd ):
- if (shownRecd == None):
- self.showLastThumb()
- else:
- hash = self.mediaHashs[self.MODE]
- if (len(hash) > 0):
- hash = self.mediaHashs[self.MODE]
- i = operator.indexOf( hash, shownRecd )
- i = i-1
- if (i<0):
- i = len(hash)-1
- self.ca.ui.showThumbSelection( hash[i] )
+ def stopRecordingAudio( self ):
+ gobject.source_remove( self.ca.ui.UPDATE_DURATION_ID )
+ self.ca.ui.progressWindow.updateProgress( 0, "" )
+ self.setUpdating( True )
+ self.setRecording( False )
+ self.ca.ui.FULLSCREEN = False
+ self.ca.ui.updateVideoComponents()
+ self.ca.glive.stopRecordingAudio( )
- def showLastThumb( self ):
- hash = self.mediaHashs[self.MODE]
- if (len(hash) > 0):
- self.ca.ui.showThumbSelection( hash[len(hash)-1] )
+ def saveAudio( self, tmpPath, pixbuf ):
+ self.setUpdating( True )
- def doShutter( self ):
- if (self.UPDATING):
- return
+ recd = self.createNewRecorded( Constants.TYPE_AUDIO )
+ os.rename( tmpPath, os.path.join(Instance.instancePath,recd.mediaFilename))
+
+ thumbPath = os.path.join(Instance.instancePath, recd.thumbFilename)
+ scale = float((UI.dim_THUMB_WIDTH+0.0)/(pixbuf.get_width()+0.0))
+ thumbImg = utils.generateThumbnail(pixbuf, scale, UI.dim_THUMB_WIDTH, UI.dim_THUMB_HEIGHT)
+ thumbImg.write_to_png(thumbPath)
- if (self.MODE == Constants.MODE_PHOTO):
- self.startTakingPhoto()
- elif (self.MODE == Constants.MODE_VIDEO):
- if (not self.RECORDING):
- self.startRecordingVideo()
- else:
- #post-processing begins now, so queue up this gfx
- self.ca.ui.showPostProcessGfx(True)
- self.stopRecordingVideo()
- elif (self.MODE == Constants.MODE_AUDIO):
- if (not self.RECORDING):
- self.startRecordingAudio()
- else:
- #post-processing begins now, so queue up this gfx
- self.ca.ui.showPostProcessGfx(True)
- self.stopRecordingAudio()
-
-
- def stopRecordingAudio( self ):
- gobject.source_remove( self.ca.ui.UPDATE_DURATION_ID )
- self.ca.ui.progressWindow.updateProgress( 0, "" )
- self.setUpdating( True )
- self.setRecording( False )
- self.ca.ui.TRANSCODING = True
- self.ca.ui.FULLSCREEN = False
- self.ca.ui.updateVideoComponents()
+ imagePath = os.path.join(Instance.instancePath, "audioPicture.png")
+ imagePath = utils.getUniqueFilepath( imagePath, 0 )
+ pixbuf.save( imagePath, "png", {} )
+ recd.audioImageFilename = os.path.basename(imagePath)
- self.ca.glive.stopRecordingAudio( )
+ #at this point, we have both audio and thumb sapath, so we can save the recd
+ self.createNewRecordedMd5Sums( recd )
+ audioHash = self.mediaHashs[Constants.TYPE_AUDIO]
+ audioHash.append( recd )
+ gobject.idle_add(self.displayThumb, recd, True)
+ self.doPostSaveVideo()
+ self.meshShareRecd( recd )
- def saveAudio( self, tmpPath, pixbuf ):
- self.setUpdating( True )
-
- recd = self.createNewRecorded( Constants.TYPE_AUDIO )
- os.rename( tmpPath, os.path.join(Instance.instancePath,recd.mediaFilename))
-
- thumbPath = os.path.join(Instance.instancePath, recd.thumbFilename)
- scale = float((UI.dim_THUMB_WIDTH+0.0)/(pixbuf.get_width()+0.0))
- thumbImg = utils.generateThumbnail(pixbuf, scale, UI.dim_THUMB_WIDTH, UI.dim_THUMB_HEIGHT)
- thumbImg.write_to_png(thumbPath)
-
- imagePath = os.path.join(Instance.instancePath, "audioPicture.png")
- imagePath = utils.getUniqueFilepath( imagePath, 0 )
- pixbuf.save( imagePath, "png", {} )
- recd.audioImageFilename = os.path.basename(imagePath)
-
- #at this point, we have both audio and thumb sapath, so we can save the recd
- self.createNewRecordedMd5Sums( recd )
-
- audioHash = self.mediaHashs[Constants.TYPE_AUDIO]
- audioHash.append( recd )
- gobject.idle_add(self.displayThumb, recd, True)
- self.doPostSaveVideo()
- self.meshShareRecd( recd )
+ def startRecordingVideo( self ):
+ self.setUpdating( True )
+ self.setRecording( True )
+ #let the red eye kick in before we start the video underway
+ gobject.idle_add( self.beginRecordingVideo )
- def startRecordingVideo( self ):
- self.setUpdating( True )
- self.setRecording( True )
- #let the red eye kick in before we start the video underway
- gobject.idle_add( self.beginRecordingVideo )
+ def beginRecordingVideo( self ):
+ self.ca.ui.recordVideo()
+ self.setUpdating( False )
- def beginRecordingVideo( self ):
- self.ca.ui.recordVideo()
- self.setUpdating( False )
+ def startRecordingAudio( self ):
+ self.setUpdating( True )
+ self.setRecording( True )
+ self.ca.ui.recordAudio()
+ self.setUpdating( False )
- def startRecordingAudio( self ):
- self.setUpdating( True )
- self.setRecording( True )
- self.ca.ui.recordAudio()
- self.setUpdating( False )
+ def setUpdating( self, upd ):
+ self.UPDATING = upd
+ self.ca.ui.updateButtonSensitivities()
- def setUpdating( self, upd ):
- self.UPDATING = upd
- self.ca.ui.updateButtonSensitivities()
+ def setRecording( self, rec ):
+ self.RECORDING = rec
+ self.ca.ui.updateButtonSensitivities()
- def setRecording( self, rec ):
- self.RECORDING = rec
- self.ca.ui.updateButtonSensitivities()
+ def stopRecordingVideo( self ):
+ self.ca.glive.stopRecordingVideo()
+ gobject.source_remove( self.ca.ui.UPDATE_DURATION_ID )
+ self.setUpdating( True )
+ self.setRecording( False )
+ self.ca.ui.FULLSCREEN = False
+ self.ca.ui.updateVideoComponents()
- def stopRecordingVideo( self ):
- self.ca.glive.stopRecordingVideo()
- gobject.source_remove( self.ca.ui.UPDATE_DURATION_ID )
- self.ca.ui.progressWindow.updateProgress( 0, "" )
- self.setUpdating( True )
- self.setRecording( False )
- self.ca.ui.TRANSCODING = True
- self.ca.ui.FULLSCREEN = False
- self.ca.ui.updateVideoComponents()
+ def saveVideo( self, pixbuf, tmpPath, wid, hit ):
+ recd = self.createNewRecorded( Constants.TYPE_VIDEO )
+ os.rename( tmpPath, os.path.join(Instance.instancePath,recd.mediaFilename))
- def saveVideo( self, pixbuf, tmpPath, wid, hit ):
- recd = self.createNewRecorded( Constants.TYPE_VIDEO )
- os.rename( tmpPath, os.path.join(Instance.instancePath,recd.mediaFilename))
+ thumbPath = os.path.join(Instance.instancePath, recd.thumbFilename)
+ scale = float((UI.dim_THUMB_WIDTH+0.0)/(wid+0.0))
+ thumbImg = utils.generateThumbnail(pixbuf, scale, UI.dim_THUMB_WIDTH, UI.dim_THUMB_HEIGHT)
+ thumbImg.write_to_png(thumbPath)
- thumbPath = os.path.join(Instance.instancePath, recd.thumbFilename)
- scale = float((UI.dim_THUMB_WIDTH+0.0)/(wid+0.0))
- thumbImg = utils.generateThumbnail(pixbuf, scale, UI.dim_THUMB_WIDTH, UI.dim_THUMB_HEIGHT)
- thumbImg.write_to_png(thumbPath)
+ self.createNewRecordedMd5Sums( recd )
- self.createNewRecordedMd5Sums( recd )
+ videoHash = self.mediaHashs[Constants.TYPE_VIDEO]
+ videoHash.append( recd )
+ self.doPostSaveVideo()
+ gobject.idle_add(self.displayThumb, recd, True)
+ self.meshShareRecd( recd )
- videoHash = self.mediaHashs[Constants.TYPE_VIDEO]
- videoHash.append( recd )
- self.doPostSaveVideo()
- gobject.idle_add(self.displayThumb, recd, True)
- self.meshShareRecd( recd )
+ def meshShareRecd( self, recd ):
+ #hey, i just took a cool video.audio.photo! let me show you!
+ if (self.ca.recTube != None):
+ logger.debug('meshShareRecd')
+ recdXml = serialize.getRecdXmlMeshString(recd)
+ self.ca.recTube.notifyBudsOfNewRecd( Instance.keyHashPrintable, recdXml )
- def meshShareRecd( self, recd ):
- record.Record.log.debug('meshShareRecd')
- #hey, i just took a cool video.audio.photo! let me show you!
- if (self.ca.recTube != None):
- recdXml = serialize.getRecdXmlMeshString(recd)
- self.ca.recTube.notifyBudsOfNewRecd( Instance.keyHashPrintable, recdXml )
+ def cannotSaveVideo( self ):
+ self.doPostSaveVideo()
- def cannotSaveVideo( self ):
- self.doPostSaveVideo()
+ def doPostSaveVideo( self ):
+ self.ca.ui.showPostProcessGfx(False)
- def doPostSaveVideo( self ):
- self.ca.ui.showPostProcessGfx(False)
+ #prep the ui for your return
+ self.ca.ui.LAST_MODE = -1
+ self.ca.ui.TRANSCODING = False
- #prep the ui for your return
- self.ca.ui.LAST_MODE = -1
- self.ca.ui.TRANSCODING = False
+ #resume live video from the camera (if the activity is active)
+ if (self.ca.ui.ACTIVE):
+ self.ca.ui.updateVideoComponents()
- #resume live video from the camera (if the activity is active)
- if (self.ca.ui.ACTIVE):
- self.ca.ui.updateVideoComponents()
+ self.ca.ui.progressWindow.updateProgress( 0, "" )
+ self.setRecording( False )
+ self.setUpdating( False )
- self.ca.ui.progressWindow.updateProgress( 0, "" )
- self.setRecording( False )
- self.setUpdating( False )
+ def abandonRecording( self ):
- def abandonRecording( self ):
+ self.ca.ui.LAST_MODE = -1
+ self.ca.ui.TRANSCODING = False
+ self.ca.ui.completeTimer()
+ self.ca.ui.completeCountdown()
+ self.setRecording(False)
- self.ca.ui.LAST_MODE = -1
- self.ca.ui.TRANSCODING = False
- self.ca.ui.completeTimer()
- self.ca.ui.completeCountdown()
- self.setRecording(False)
+ self.ca.ui.progressWindow.updateProgress( 0, "" )
- self.ca.ui.progressWindow.updateProgress( 0, "" )
+ self.ca.glive.abandonMedia()
- self.ca.glive.abandonMedia()
+ def stoppedRecordingVideo( self ):
+ self.setUpdating( False )
- def stoppedRecordingVideo( self ):
- self.setUpdating( False )
+ def startTakingPhoto( self ):
+ self.setUpdating( True )
+ self.ca.glive.takePhoto()
- def startTakingPhoto( self ):
- self.setUpdating( True )
- self.ca.glive.takePhoto()
+ def savePhoto( self, pixbuf ):
+ recd = self.createNewRecorded( Constants.TYPE_PHOTO )
- def savePhoto( self, pixbuf ):
- recd = self.createNewRecorded( Constants.TYPE_PHOTO )
+ imgpath = os.path.join(Instance.instancePath, recd.mediaFilename)
+ pixbuf.save( imgpath, "jpeg" )
- imgpath = os.path.join(Instance.instancePath, recd.mediaFilename)
- pixbuf.save( imgpath, "jpeg" )
+ thumbpath = os.path.join(Instance.instancePath, recd.thumbFilename)
+ scale = float((UI.dim_THUMB_WIDTH+0.0)/(pixbuf.get_width()+0.0))
+ thumbImg = utils.generateThumbnail(pixbuf, scale, UI.dim_THUMB_WIDTH, UI.dim_THUMB_HEIGHT)
+ thumbImg.write_to_png(thumbpath)
+ gc.collect()
+ #now that we've saved both the image and its pixbuf, we get their md5s
+ self.createNewRecordedMd5Sums( recd )
- thumbpath = os.path.join(Instance.instancePath, recd.thumbFilename)
- scale = float((UI.dim_THUMB_WIDTH+0.0)/(pixbuf.get_width()+0.0))
- thumbImg = utils.generateThumbnail(pixbuf, scale, UI.dim_THUMB_WIDTH, UI.dim_THUMB_HEIGHT)
- thumbImg.write_to_png(thumbpath)
- gc.collect()
- #now that we've saved both the image and its pixbuf, we get their md5s
- self.createNewRecordedMd5Sums( recd )
+ photoHash = self.mediaHashs[Constants.TYPE_PHOTO]
+ photoHash.append( recd )
+ gobject.idle_add(self.displayThumb, recd, True)
- photoHash = self.mediaHashs[Constants.TYPE_PHOTO]
- photoHash.append( recd )
- gobject.idle_add(self.displayThumb, recd, True)
+ self.meshShareRecd( recd )
- self.meshShareRecd( recd )
+ def addMeshRecd( self, recd ):
+ #todo: sort on time-taken, not on their arrival time over the mesh (?)
+ self.mediaHashs[recd.type].append( recd )
- def addMeshRecd( self, recd ):
- #todo: sort on time-taken, not on their arrival time over the mesh (?)
- self.mediaHashs[recd.type].append( recd )
+ #updateUi, but don't lock up the buttons if they're recording or whatever
+ gobject.idle_add(self.displayThumb, recd, False)
- #updateUi, but don't lock up the buttons if they're recording or whatever
- gobject.idle_add(self.displayThumb, recd, False)
+ def createNewRecorded( self, type ):
+ recd = Recorded( )
- def createNewRecorded( self, type ):
- recd = Recorded( )
+ recd.recorderName = Instance.nickName
+ recd.recorderHash = Instance.keyHashPrintable
- recd.recorderName = Instance.nickName
- recd.recorderHash = Instance.keyHashPrintable
+ #to create a file, use the hardware_id+time *and* check if available or not
+ nowtime = int(time.time())
+ recd.time = nowtime
+ recd.type = type
- #to create a file, use the hardware_id+time *and* check if available or not
- nowtime = int(time.time())
- recd.time = nowtime
- recd.type = type
+ mediaThumbFilename = str(recd.recorderHash) + "_" + str(recd.time)
+ mediaFilename = mediaThumbFilename
+ mediaFilename = mediaFilename + "." + Constants.mediaTypes[type][Constants.keyExt]
+ mediaFilepath = os.path.join( Instance.instancePath, mediaFilename )
+ mediaFilepath = utils.getUniqueFilepath( mediaFilepath, 0 )
+ recd.mediaFilename = os.path.basename( mediaFilepath )
- mediaThumbFilename = str(recd.recorderHash) + "_" + str(recd.time)
- mediaFilename = mediaThumbFilename
- mediaFilename = mediaFilename + "." + Constants.mediaTypes[type][Constants.keyExt]
- mediaFilepath = os.path.join( Instance.instancePath, mediaFilename )
- mediaFilepath = utils.getUniqueFilepath( mediaFilepath, 0 )
- recd.mediaFilename = os.path.basename( mediaFilepath )
+ thumbFilename = mediaThumbFilename + "_thumb.jpg"
+ thumbFilepath = os.path.join( Instance.instancePath, thumbFilename )
+ thumbFilepath = utils.getUniqueFilepath( thumbFilepath, 0 )
+ recd.thumbFilename = os.path.basename( thumbFilepath )
- thumbFilename = mediaThumbFilename + "_thumb.jpg"
- thumbFilepath = os.path.join( Instance.instancePath, thumbFilename )
- thumbFilepath = utils.getUniqueFilepath( thumbFilepath, 0 )
- recd.thumbFilename = os.path.basename( thumbFilepath )
+ stringType = Constants.mediaTypes[type][Constants.keyIstr]
+ recd.title = Constants.istrBy % {"1":stringType, "2":str(recd.recorderName)}
- stringType = Constants.mediaTypes[type][Constants.keyIstr]
- recd.title = Constants.istrBy % {"1":stringType, "2":str(recd.recorderName)}
+ recd.colorStroke = Instance.colorStroke
+ recd.colorFill = Instance.colorFill
- recd.colorStroke = Instance.colorStroke
- recd.colorFill = Instance.colorFill
+ logger.debug('createNewRecorded: ' + str(recd) + ", thumbFilename:" + str(recd.thumbFilename))
+ return recd
- record.Record.log.debug('createNewRecorded: ' + str(recd) + ", thumbFilename:" + str(recd.thumbFilename))
- return recd
+ def createNewRecordedMd5Sums( self, recd ):
+ recd.thumbMd5 = recd.mediaMd5 = uuid.uuid4()
- def createNewRecordedMd5Sums( self, recd ):
- #load the thumbfile
- thumbFile = os.path.join(Instance.instancePath, recd.thumbFilename)
- thumbMd5 = utils.md5File( thumbFile )
- recd.thumbMd5 = thumbMd5
- tBytes = os.stat(thumbFile)[6]
- recd.thumbBytes = tBytes
+ #load the thumbfile
+ thumbFile = os.path.join(Instance.instancePath, recd.thumbFilename)
+ tBytes = os.stat(thumbFile)[6]
+ recd.thumbBytes = tBytes
- recd.tags = ""
+ recd.tags = ""
- #load the mediafile
- mediaFile = os.path.join(Instance.instancePath, recd.mediaFilename)
- mediaMd5 = utils.md5File( mediaFile )
- recd.mediaMd5 = mediaMd5
- mBytes = os.stat(mediaFile)[6]
- recd.mediaBytes = mBytes
+ #load the mediafile
+ mediaFile = os.path.join(Instance.instancePath, recd.mediaFilename)
+ mBytes = os.stat(mediaFile)[6]
+ recd.mediaBytes = mBytes
- def deleteRecorded( self, recd ):
- recd.deleted = True
+ def deleteRecorded( self, recd ):
+ recd.deleted = True
- #clear the index
- hash = self.mediaHashs[recd.type]
- index = hash.index(recd)
- hash.remove( recd )
+ #clear the index
+ hash = self.mediaHashs[recd.type]
+ index = hash.index(recd)
+ hash.remove( recd )
- if (not recd.meshUploading):
- self.doDeleteRecorded( recd )
+ if (not recd.meshUploading):
+ self.doDeleteRecorded( recd )
- def doDeleteRecorded( self, recd ):
- #remove files from the filesystem if not on the datastore
- if (recd.datastoreId == None):
- mediaFile = recd.getMediaFilepath()
- if (os.path.exists(mediaFile)):
- os.remove(mediaFile)
+ def doDeleteRecorded( self, recd ):
+ #remove files from the filesystem if not on the datastore
+ if (recd.datastoreId == None):
+ mediaFile = recd.getMediaFilepath()
+ if (os.path.exists(mediaFile)):
+ os.remove(mediaFile)
- thumbFile = recd.getThumbFilepath( )
- if (os.path.exists(thumbFile)):
- os.remove(thumbFile)
- else:
- #remove from the datastore here, since once gone, it is gone...
- serialize.removeMediaFromDatastore( recd )
+ thumbFile = recd.getThumbFilepath( )
+ if (os.path.exists(thumbFile)):
+ os.remove(thumbFile)
+ else:
+ #remove from the datastore here, since once gone, it is gone...
+ serialize.removeMediaFromDatastore( recd )
- def doVideoMode( self ):
- if (self.MODE == Constants.MODE_VIDEO):
- return
+ def doVideoMode( self ):
+ if (self.MODE == Constants.MODE_VIDEO):
+ return
- self.MODE = Constants.MODE_VIDEO
- self.setUpdating(True)
- gobject.idle_add( self.setupMode, self.MODE, True )
+ self.MODE = Constants.MODE_VIDEO
+ self.setUpdating(True)
+ gobject.idle_add( self.setupMode, self.MODE, True )
- def doPhotoMode( self ):
- if (self.MODE == Constants.MODE_PHOTO):
- return
+ def doPhotoMode( self ):
+ if (self.MODE == Constants.MODE_PHOTO):
+ return
- self.MODE = Constants.MODE_PHOTO
- self.setUpdating(True)
- gobject.idle_add( self.setupMode, self.MODE, True )
+ self.MODE = Constants.MODE_PHOTO
+ self.setUpdating(True)
+ gobject.idle_add( self.setupMode, self.MODE, True )
- def doAudioMode( self ):
- if (self.MODE == Constants.MODE_AUDIO):
- return
+ def doAudioMode( self ):
+ if (self.MODE == Constants.MODE_AUDIO):
+ return
- self.MODE = Constants.MODE_AUDIO
- self.setUpdating(True)
- gobject.idle_add( self.setupMode, self.MODE, True )
+ self.MODE = Constants.MODE_AUDIO
+ self.setUpdating(True)
+ gobject.idle_add( self.setupMode, self.MODE, True )
diff --git a/p5.py b/p5.py
index ebcb08e..e785f94 100644
--- a/p5.py
+++ b/p5.py
@@ -27,164 +27,164 @@ import math
#Sometimes a gtk.Image is a useful alternative to a drawing area. You can put a gtk.gdk.Pixmap in the gtk.Image and draw to the gtk.gdk.Pixmap, calling the gtk.Widget.queue_draw() method on the gtk.Image when you want to refresh to the screen.
class P5(gtk.DrawingArea):
- def __init__(self):
- super(P5, self).__init__()
+ def __init__(self):
+ super(P5, self).__init__()
- # gtk.Widget signals
- self.connect("expose_event", self.expose)
- self.connect("button_press_event", self.button_press)
- self.connect("button_release_event", self.button_release)
- self.connect("motion_notify_event", self.motion_notify)
+ # gtk.Widget signals
+ self.connect("expose_event", self.expose)
+ self.connect("button_press_event", self.button_press)
+ self.connect("button_release_event", self.button_release)
+ self.connect("motion_notify_event", self.motion_notify)
- # ok, we have to listen to mouse events here too
- self.add_events(gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.POINTER_MOTION_MASK)
- self._dragging = False
- self._mouseX = 0
- self._mouseY = 0
+ # ok, we have to listen to mouse events here too
+ self.add_events(gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.POINTER_MOTION_MASK)
+ self._dragging = False
+ self._mouseX = 0
+ self._mouseY = 0
- self._w = -1
- self._h = -1
+ self._w = -1
+ self._h = -1
- #ok, this calls an initial painting & setting of painterly variables
- #e.g. time for the clock widget
- #(but not through to redraw_canvas when called here first time)
- self._msecUpdate = 100
- self._looping = False
- self.noloop()
+ #ok, this calls an initial painting & setting of painterly variables
+ #e.g. time for the clock widget
+ #(but not through to redraw_canvas when called here first time)
+ self._msecUpdate = 100
+ self._looping = False
+ self.noloop()
- def loop(self):
- if (self._looping):
- return
- else:
- self._looping = True
- # this is our maybe-threaded refresh (in millisecs)
- gobject.timeout_add( self._msecUpdate, self.update )
+ def loop(self):
+ if (self._looping):
+ return
+ else:
+ self._looping = True
+ # this is our maybe-threaded refresh (in millisecs)
+ gobject.timeout_add( self._msecUpdate, self.update )
- def noloop(self):
- self._looping = False
- self.redraw()
+ def noloop(self):
+ self._looping = False
+ self.redraw()
- def redraw(self):
- self.update()
+ def redraw(self):
+ self.update()
- def expose(self, widget, event):
- ctx = widget.window.cairo_create()
+ def expose(self, widget, event):
+ ctx = widget.window.cairo_create()
- # set a clip region for the expose event
- ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
- ctx.clip()
+ # set a clip region for the expose event
+ ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
+ ctx.clip()
- rect = widget.allocation
- #self.draw(ctx, event.area.width, event.area.height)
- self.draw( ctx, rect.width, rect.height )
+ rect = widget.allocation
+ #self.draw(ctx, event.area.width, event.area.height)
+ self.draw( ctx, rect.width, rect.height )
- def button_press(self, widget, event):
- self._mouseX = event.x
- self._mouseY = event.y
- self._dragging = True
+ def button_press(self, widget, event):
+ self._mouseX = event.x
+ self._mouseY = event.y
+ self._dragging = True
- def button_release(self, widget, event):
- if self._dragging:
- self._dragging = False
+ def button_release(self, widget, event):
+ if self._dragging:
+ self._dragging = False
- def motion_notify(self, widget, event):
- self._mouseX = event.x
- self._mouseY = event.y
+ def motion_notify(self, widget, event):
+ self._mouseX = event.x
+ self._mouseY = event.y
- def draw(self, ctx, w, h):
- ctx.set_antialias( cairo.ANTIALIAS_NONE )
- ctx.set_line_width( 1 )
- ctx.identity_matrix( )
- if ((w != self._w) or (h != self._h)):
- self._w = w
- self._h = h
- self.doResize( )
+ def draw(self, ctx, w, h):
+ ctx.set_antialias( cairo.ANTIALIAS_NONE )
+ ctx.set_line_width( 1 )
+ ctx.identity_matrix( )
+ if ((w != self._w) or (h != self._h)):
+ self._w = w
+ self._h = h
+ self.doResize( )
- def doResize(self):
- pass
+ def doResize(self):
+ pass
- #called from update
- def redraw_canvas(self):
- if self.window:
- alloc = self.get_allocation()
- #this is odd behavior, but once we add this widget to a parent (vbox)
- #it requires setting the q_d_a x,y to 0, 0
- #self.queue_draw_area(alloc.x, alloc.y, alloc.width, alloc.height)
- self.queue_draw_area(0, 0, alloc.width, alloc.height)
- self.window.process_updates(True)
+ #called from update
+ def redraw_canvas(self):
+ if self.window:
+ alloc = self.get_allocation()
+ #this is odd behavior, but once we add this widget to a parent (vbox)
+ #it requires setting the q_d_a x,y to 0, 0
+ #self.queue_draw_area(alloc.x, alloc.y, alloc.width, alloc.height)
+ self.queue_draw_area(0, 0, alloc.width, alloc.height)
+ self.window.process_updates(True)
- def update(self):
- #paint thread -- call redraw_canvas, which calls expose
- self.redraw_canvas()
- if (self._looping):
- return True # keep running this event
- else:
- return False
+ def update(self):
+ #paint thread -- call redraw_canvas, which calls expose
+ self.redraw_canvas()
+ if (self._looping):
+ return True # keep running this event
+ else:
+ return False
- def drawShape( self, ctx, poly, col ):
- self.setColor( ctx, col )
+ def drawShape( self, ctx, poly, col ):
+ self.setColor( ctx, col )
- for i in range ( 0, len(poly._xs) ):
- ctx.line_to ( poly._xs[i], poly._ys[i] )
- ctx.close_path()
- ctx.set_line_width(1)
- ctx.stroke()
+ for i in range ( 0, len(poly._xs) ):
+ ctx.line_to ( poly._xs[i], poly._ys[i] )
+ ctx.close_path()
+ ctx.set_line_width(1)
+ ctx.stroke()
- def fillShape( self, ctx, poly, col ):
- self.setColor( ctx, col )
- for i in range ( 0, len(poly._xs) ):
- ctx.line_to (poly._xs[i], poly._ys[i])
- ctx.close_path()
+ def fillShape( self, ctx, poly, col ):
+ self.setColor( ctx, col )
+ for i in range ( 0, len(poly._xs) ):
+ ctx.line_to (poly._xs[i], poly._ys[i])
+ ctx.close_path()
- ctx.fill()
+ ctx.fill()
- def background( self, ctx, col, w, h ):
- self.setColor( ctx, col )
+ def background( self, ctx, col, w, h ):
+ self.setColor( ctx, col )
- ctx.line_to(0, 0)
- ctx.line_to(w, 0)
- ctx.line_to(w, h)
- ctx.line_to(0, h)
- ctx.close_path()
+ ctx.line_to(0, 0)
+ ctx.line_to(w, 0)
+ ctx.line_to(w, h)
+ ctx.line_to(0, h)
+ ctx.close_path()
- ctx.fill()
+ ctx.fill()
- def rect( self, ctx, x, y, w, h ):
- ctx.line_to(x, y)
- ctx.line_to(x+w, y)
- ctx.line_to(x+w, y+h)
- ctx.line_to(x, y+h)
- ctx.close_path()
+ def rect( self, ctx, x, y, w, h ):
+ ctx.line_to(x, y)
+ ctx.line_to(x+w, y)
+ ctx.line_to(x+w, y+h)
+ ctx.line_to(x, y+h)
+ ctx.close_path()
- def setColor( self, ctx, col ):
- if (not col._opaque):
- ctx.set_source_rgba( col._r, col._g, col._b, col._a )
- else:
- ctx.set_source_rgb( col._r, col._g, col._b )
+ def setColor( self, ctx, col ):
+ if (not col._opaque):
+ ctx.set_source_rgba( col._r, col._g, col._b, col._a )
+ else:
+ ctx.set_source_rgb( col._r, col._g, col._b )
- def line( self, ctx, x1, y1, x2, y2 ):
- ctx.move_to (x1, y1)
- ctx.line_to (x2, y2)
- ctx.stroke()
+ def line( self, ctx, x1, y1, x2, y2 ):
+ ctx.move_to (x1, y1)
+ ctx.line_to (x2, y2)
+ ctx.stroke()
- def point( self, ctx, x1, y1 ):
- self.line( ctx, x1, y1, x1+1, y1 ) \ No newline at end of file
+ def point( self, ctx, x1, y1 ):
+ self.line( ctx, x1, y1, x1+1, y1 ) \ No newline at end of file
diff --git a/p5_button.py b/p5_button.py
index 0461b3c..cf76a34 100644
--- a/p5_button.py
+++ b/p5_button.py
@@ -22,152 +22,152 @@ from p5 import P5
class P5Button(P5):
- def __init__(self):
- P5.__init__(self)
- self.noloop()
- self._butts = []
- self._buttonPressed = False
+ def __init__(self):
+ P5.__init__(self)
+ self.noloop()
+ self._butts = []
+ self._buttonPressed = False
- def button_press(self, widget, event):
- P5.button_press(self, widget, event)
+ def button_press(self, widget, event):
+ P5.button_press(self, widget, event)
- #iterate through the buttons to see if you've pressed any down
- bp = False
- for i in range ( 0, len(self._butts) ):
- if (self._butts[i]._enabled):
- contains = self._butts[i].contains(event.x, event.y)
- self._butts[i]._pressed = contains
- if (contains):
- bp = True
+ #iterate through the buttons to see if you've pressed any down
+ bp = False
+ for i in range ( 0, len(self._butts) ):
+ if (self._butts[i]._enabled):
+ contains = self._butts[i].contains(event.x, event.y)
+ self._butts[i]._pressed = contains
+ if (contains):
+ bp = True
- self._buttonPressed = bp
- self.redraw()
+ self._buttonPressed = bp
+ self.redraw()
- def button_release(self, widget, event):
- P5.button_release(self, widget, event)
- self._buttonPressed = False
+ def button_release(self, widget, event):
+ P5.button_release(self, widget, event)
+ self._buttonPressed = False
- pressed = []
- #iterate through the buttons to see if you've released on any
- for i in range ( 0, len(self._butts) ):
- if (self._butts[i]._enabled):
- if (self._butts[i]._pressed):
- if (self._butts[i].contains(event.x, event.y)):
- pressed.append( self._butts[i] )
+ pressed = []
+ #iterate through the buttons to see if you've released on any
+ for i in range ( 0, len(self._butts) ):
+ if (self._butts[i]._enabled):
+ if (self._butts[i]._pressed):
+ if (self._butts[i].contains(event.x, event.y)):
+ pressed.append( self._butts[i] )
- if (self._butts[i]._toggle):
- self._butts[i]._pressed = not self._butts[i]._pressed
- else:
- self._butts[i]._pressed = False
+ if (self._butts[i]._toggle):
+ self._butts[i]._pressed = not self._butts[i]._pressed
+ else:
+ self._butts[i]._pressed = False
- for i in range( 0, len(pressed) ):
- pressed[i].doPressed()
+ for i in range( 0, len(pressed) ):
+ pressed[i].doPressed()
- self.redraw()
+ self.redraw()
class Polygon:
- def __init__( self, xs, ys ):
- self.setPoints( xs, ys )
+ def __init__( self, xs, ys ):
+ self.setPoints( xs, ys )
- def setPoints( self, xs, ys ):
- self._xs = xs
- self._ys = ys
+ def setPoints( self, xs, ys ):
+ self._xs = xs
+ self._ys = ys
- self._boundingX = self._xs[0]
- self._boundingY = self._ys[0]
- self._boundingW = self._xs[0]
- self._boundingH = self._ys[0]
+ self._boundingX = self._xs[0]
+ self._boundingY = self._ys[0]
+ self._boundingW = self._xs[0]
+ self._boundingH = self._ys[0]
- for i in range ( 1, len(self._xs) ):
- if (self._xs[i] > self._boundingW):
- self._boundingW = self._xs[i]
- if (self._ys[i] > self._boundingH):
- self._boundingH = self._ys[i]
- if (self._xs[i] < self._boundingX):
- self._boundingX = self._xs[i]
- if (self._ys[i] < self._boundingY):
- self._boundingY = self._ys[i]
+ for i in range ( 1, len(self._xs) ):
+ if (self._xs[i] > self._boundingW):
+ self._boundingW = self._xs[i]
+ if (self._ys[i] > self._boundingH):
+ self._boundingH = self._ys[i]
+ if (self._xs[i] < self._boundingX):
+ self._boundingX = self._xs[i]
+ if (self._ys[i] < self._boundingY):
+ self._boundingY = self._ys[i]
- def contains( self, mx, my ):
- if (not self.bbox_contains(mx, my)):
- return False
+ def contains( self, mx, my ):
+ if (not self.bbox_contains(mx, my)):
+ return False
- #insert simple path tracing check on the polygon here
+ #insert simple path tracing check on the polygon here
- return True
+ return True
- def bbox_contains( self, mx, my ):
- if ( not((mx>=self._boundingX) and (my>=self._boundingY) and (mx<self._boundingW) and (my<self._boundingH)) ):
- return False
- else:
- return True
+ def bbox_contains( self, mx, my ):
+ if ( not((mx>=self._boundingX) and (my>=self._boundingY) and (mx<self._boundingW) and (my<self._boundingH)) ):
+ return False
+ else:
+ return True
class Button:
- def __init__(self, poly, offX, offY):
- self._poly = poly
- self._offX = offX
- self._offY = offY
+ def __init__(self, poly, offX, offY):
+ self._poly = poly
+ self._offX = offX
+ self._offY = offY
- self._enabled = True
- self._pressed = False
- self._toggle = False
+ self._enabled = True
+ self._pressed = False
+ self._toggle = False
- self._listeners = []
+ self._listeners = []
- self._actionCommand = None
+ self._actionCommand = None
- self._img = None
+ self._img = None
- def setOffsets(self, offs):
- self._offX = offs[0]
- self._offY = offs[1]
+ def setOffsets(self, offs):
+ self._offX = offs[0]
+ self._offY = offs[1]
- def addActionListener(self, listen):
- self._listeners.append(listen)
+ def addActionListener(self, listen):
+ self._listeners.append(listen)
- def removeActionListener(self, listen):
- try:
- self._listeners.remove(listen)
- except ValueError:
- pass
+ def removeActionListener(self, listen):
+ try:
+ self._listeners.remove(listen)
+ except ValueError:
+ pass
- def setActionCommand(self, command):
- self._actionCommand = command
+ def setActionCommand(self, command):
+ self._actionCommand = command
- def getActionCommand(self):
- return self._actionCommand
+ def getActionCommand(self):
+ return self._actionCommand
- def setImage(self, img):
- self._img = img
+ def setImage(self, img):
+ self._img = img
- def contains( self, mx, my ):
- x = mx - self._offX
- y = my - self._offY
+ def contains( self, mx, my ):
+ x = mx - self._offX
+ y = my - self._offY
- contains = self._poly.contains( x, y )
- return contains
+ contains = self._poly.contains( x, y )
+ return contains
- def doPressed( self ):
- for i in range ( 0, len(self._listeners) ):
- self._listeners[i].fireButton( self._actionCommand )
+ def doPressed( self ):
+ for i in range ( 0, len(self._listeners) ):
+ self._listeners[i].fireButton( self._actionCommand )
- def isImg( self ):
- return self._img != None \ No newline at end of file
+ def isImg( self ):
+ return self._img != None \ No newline at end of file
diff --git a/po/zh_TW.po b/po/zh_TW.po
index 57aa2d0..54b45fe 100644
--- a/po/zh_TW.po
+++ b/po/zh_TW.po
@@ -343,4 +343,4 @@ msgstr "容量"
#~ msgstr "低品質"
#~ msgid "Your disk is full"
-#~ msgstr "
+#~ msgstr ""
diff --git a/port/AUTHORS b/port/AUTHORS
new file mode 100644
index 0000000..47ead6c
--- /dev/null
+++ b/port/AUTHORS
@@ -0,0 +1 @@
+Aleksey Lim <alsroot@member.fsf.org>
diff --git a/port/COPYING b/port/COPYING
new file mode 100644
index 0000000..623b625
--- /dev/null
+++ b/port/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/port/NEWS b/port/NEWS
new file mode 100644
index 0000000..0dcfeb5
--- /dev/null
+++ b/port/NEWS
@@ -0,0 +1,8 @@
+1
+
+* Add tarball.py
+* Add json import wrapper
+* Add object chooser
+* Add activity classes
+* Add pixbuf methods
+* Add TempoSlider and ScrolledBox widgets
diff --git a/port/README b/port/README
new file mode 100644
index 0000000..bd0dade
--- /dev/null
+++ b/port/README
@@ -0,0 +1,13 @@
+About
+-----
+
+A set of sugar components/libraries/etc to simplify writing activities.
+
+Cornerstone purposes for this project:
+* Total backwards compatibility for sugar-port API
+* Run on all sugar platforms beginning from 0.82
+
+Get it
+------
+
+http://wiki.sugarlabs.org/go/Development_Team/sugar-port
diff --git a/port/TODO b/port/TODO
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/port/TODO
diff --git a/port/__init__.py b/port/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/port/__init__.py
diff --git a/port/json.py b/port/json.py
new file mode 100644
index 0000000..d464abb
--- /dev/null
+++ b/port/json.py
@@ -0,0 +1,33 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""
+Unify usage of simplejson in Python 2.5/2.6
+
+In Python 2.5 it imports simplejson module, in 2.6 native json module.
+
+Usage:
+
+ import port.json as json
+
+ # and using regular simplejson interface with module json
+ json.dumps([])
+
+"""
+
+try:
+ from json import *
+ dumps
+except (ImportError, NameError):
+ from simplejson import *
diff --git a/record.py b/record.py
index 74df6e2..d5f5e19 100644
--- a/record.py
+++ b/record.py
@@ -27,17 +27,21 @@ import telepathy.client
import logging
import xml.dom.minidom
import time
+from xml.dom.minidom import parse
+
+import logging
+logger = logging.getLogger('record:record.py')
from sugar.activity import activity
from sugar.presence import presenceservice
from sugar.presence.tubeconn import TubeConnection
from sugar import util
+import port.json
from model import Model
from ui import UI
from recordtube import RecordTube
from glive import Glive
-from glivex import GliveX
from gplay import Gplay
from greplay import Greplay
from recorded import Recorded
@@ -49,472 +53,486 @@ import utils
class Record(activity.Activity):
- log = logging.getLogger('record-activity')
+ log = logging.getLogger('record-activity')
+
+ def __init__(self, handle):
+ activity.Activity.__init__(self, handle)
+ #flags for controlling the writing to the datastore
+ self.I_AM_CLOSING = False
+ self.I_AM_SAVED = False
+
+ self.props.enable_fullscreen_mode = False
+ Instance(self)
+ Constants(self)
+ self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+
+ #wait a moment so that our debug console capture mistakes
+ gobject.idle_add( self._initme, None )
+
+
+ def _initme( self, userdata=None ):
+ #totally tubular
+ self.meshTimeoutTime = 10000
+ self.recTube = None
+ self.connect( "shared", self._sharedCb )
+
+ #the main classes
+ self.m = Model(self)
+ self.glive = Glive(self)
+ self.gplay = Gplay(self)
+ self.ui = UI(self)
+
+ #CSCL
+ if self._shared_activity:
+ #have you joined or shared this activity yourself?
+ if self.get_shared():
+ self._meshJoinedCb( self )
+ else:
+ self.connect("joined", self._meshJoinedCb)
+
+ return False
+
+
+ def read_file(self, file):
+ try:
+ dom = parse(file)
+ except Exception, e:
+ logger.error('read_file: %s' % e)
+ return
+
+ serialize.fillMediaHash(dom, self.m.mediaHashs)
+
+ for i in dom.documentElement.getElementsByTagName('ui'):
+ for ui_el in i.childNodes:
+ self.ui.deserialize(port.json.loads(ui_el.data))
+
+
+ def write_file(self, file):
+ self.I_AM_SAVED = False
+
+ self.m.mediaHashs['ui'] = self.ui.serialize()
- def __init__(self, handle):
- activity.Activity.__init__(self, handle)
- #flags for controlling the writing to the datastore
- self.I_AM_CLOSING = False
- self.I_AM_SAVED = False
+ dom = serialize.saveMediaHash(self.m.mediaHashs)
- self.props.enable_fullscreen_mode = False
- Instance(self)
- Constants(self)
- self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ ui_data = port.json.dumps(self.ui.serialize())
+ ui_el = dom.createElement('ui')
+ ui_el.appendChild(dom.createTextNode(ui_data))
+ dom.documentElement.appendChild(ui_el)
- #wait a moment so that our debug console capture mistakes
- gobject.idle_add( self._initme, None )
+ xmlFile = open( file, "w" )
+ dom.writexml(xmlFile)
+ xmlFile.close()
+ allDone = True
+ for h in range (0, len(self.m.mediaHashs)-1):
+ mhash = self.m.mediaHashs[h]
+ for i in range (0, len(mhash)):
+ recd = mhash[i]
- def _initme( self, userdata=None ):
- #totally tubular
- self.meshTimeoutTime = 10000
- self.recTube = None
- self.connect( "shared", self._sharedCb )
+ if ( (not recd.savedMedia) or (not recd.savedXml) ):
+ allDone = False
- #the main classes
- self.m = Model(self)
- self.glive = Glive(self)
- self.glivex = GliveX(self)
- self.gplay = Gplay()
- self.ui = UI(self)
+ if (self.I_AM_CLOSING):
+ mediaObject = recd.datastoreOb
+ if (mediaObject != None):
+ recd.datastoreOb = None
+ mediaObject.destroy()
+ del mediaObject
- #CSCL
- if self._shared_activity:
- #have you joined or shared this activity yourself?
- if self.get_shared():
- self._meshJoinedCb( self )
- else:
- self.connect("joined", self._meshJoinedCb)
+ self.I_AM_SAVED = True
+ if (self.I_AM_SAVED and self.I_AM_CLOSING):
+ self.destroy()
- return False
+ def stopPipes(self):
+ self.ui.doMouseListener( False )
+ self.m.setUpdating( False )
- def read_file(self, file):
- serialize.fillMediaHash(file, self.m.mediaHashs)
+ if (self.ui.COUNTINGDOWN):
+ self.m.abandonRecording()
+ elif (self.m.RECORDING):
+ self.m.doShutter()
+ else:
+ self.glive.stop()
- def write_file(self, file):
- self.I_AM_SAVED = False
+ def restartPipes(self):
+ if (not self.ui.TRANSCODING):
+ self.ui.updateModeChange( )
+ self.ui.doMouseListener( True )
- dom = serialize.saveMediaHash(self.m.mediaHashs)
- xmlFile = open( file, "w" )
- dom.writexml(xmlFile)
- xmlFile.close()
- allDone = True
- for h in range (0, len(self.m.mediaHashs)):
- mhash = self.m.mediaHashs[h]
- for i in range (0, len(mhash)):
- recd = mhash[i]
+ def close( self ):
+ self.I_AM_CLOSING = True
- if ( (not recd.savedMedia) or (not recd.savedXml) ):
- allDone = False
+ self.m.UPDATING = False
+ if (self.ui != None):
+ self.ui.updateButtonSensitivities( )
+ self.ui.doMouseListener( False )
+ self.ui.hideAllWindows()
+ if (self.gplay != None):
+ self.gplay.stop( )
+ if (self.glive != None):
+ self.glive.stop( )
- if (self.I_AM_CLOSING):
- mediaObject = recd.datastoreOb
- if (mediaObject != None):
- recd.datastoreOb = None
- mediaObject.destroy()
- del mediaObject
+ #this calls write_file
+ activity.Activity.close( self )
- self.I_AM_SAVED = True
- if (self.I_AM_SAVED and self.I_AM_CLOSING):
- self.destroy()
+ def destroy( self ):
+ if self.I_AM_SAVED:
+ activity.Activity.destroy( self )
- def stopPipes(self):
- self.ui.doMouseListener( False )
- self.m.setUpdating( False )
- if (self.ui.COUNTINGDOWN):
- self.m.abandonRecording()
- elif (self.m.RECORDING):
- self.m.doShutter()
- else:
- self.glive.stop()
- self.glivex.stop()
+ def _sharedCb( self, activity ):
+ self._setup()
+ id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube( Constants.SERVICE, {})
- def restartPipes(self):
- if (not self.ui.TRANSCODING):
- self.ui.updateModeChange( )
- self.ui.doMouseListener( True )
+ def _meshJoinedCb( self, activity ):
+ if not self._shared_activity:
+ return
+
+ self._setup()
- def close( self ):
- self.I_AM_CLOSING = True
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb)
- self.m.UPDATING = False
- if (self.ui != None):
- self.ui.updateButtonSensitivities( )
- self.ui.doMouseListener( False )
- self.ui.hideAllWindows()
- if (self.gplay != None):
- self.gplay.stop( )
- if (self.glive != None):
- self.glive.stop( )
- if (self.glivex != None):
- self.glivex.stop( )
- #this calls write_file
- activity.Activity.close( self )
-
-
- def destroy( self ):
- if self.I_AM_SAVED:
- activity.Activity.destroy( self )
-
-
- def _sharedCb( self, activity ):
- self._setup()
-
- id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube( Constants.SERVICE, {})
-
-
- def _meshJoinedCb( self, activity ):
- if not self._shared_activity:
- return
-
- self._setup()
-
- self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb)
-
-
- def _list_tubes_reply_cb(self, tubes):
- for tube_info in tubes:
- self._newTubeCb(*tube_info)
-
-
- def _list_tubes_error_cb(self, e):
- self.__class__.log.error('ListTubes() failed: %s', e)
-
-
- def _setup(self):
- #sets up the tubes...
- if self._shared_activity is None:
- self.__class__.log.error('_setup: Failed to share or join activity')
- return
-
- pservice = presenceservice.get_instance()
- try:
- name, path = pservice.get_preferred_connection()
- self.conn = telepathy.client.Connection(name, path)
- except:
- self.__class__.log.error('_setup: Failed to get_preferred_connection')
-
- # Work out what our room is called and whether we have Tubes already
- bus_name, conn_path, channel_paths = self._shared_activity.get_channels()
- room = None
- tubes_chan = None
- text_chan = None
- for channel_path in channel_paths:
- channel = telepathy.client.Channel(bus_name, channel_path)
- htype, handle = channel.GetHandle()
- if htype == telepathy.HANDLE_TYPE_ROOM:
- self.__class__.log.debug('Found our room: it has handle#%d "%s"', handle, self.conn.InspectHandles(htype, [handle])[0])
- room = handle
- ctype = channel.GetChannelType()
- if ctype == telepathy.CHANNEL_TYPE_TUBES:
- self.__class__.log.debug('Found our Tubes channel at %s', channel_path)
- tubes_chan = channel
- elif ctype == telepathy.CHANNEL_TYPE_TEXT:
- self.__class__.log.debug('Found our Text channel at %s', channel_path)
- text_chan = channel
-
- if room is None:
- self.__class__.log.error("Presence service didn't create a room")
- return
- if text_chan is None:
- self.__class__.log.error("Presence service didn't create a text channel")
- return
-
- # Make sure we have a Tubes channel - PS doesn't yet provide one
- if tubes_chan is None:
- self.__class__.log.debug("Didn't find our Tubes channel, requesting one...")
- tubes_chan = self.conn.request_channel(telepathy.CHANNEL_TYPE_TUBES, telepathy.HANDLE_TYPE_ROOM, room, True)
-
- self.tubes_chan = tubes_chan
- self.text_chan = text_chan
-
- tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal('NewTube', self._newTubeCb)
-
-
- def _newTubeCb(self, id, initiator, type, service, params, state):
- self.__class__.log.debug('New tube: ID=%d initator=%d type=%d service=%s params=%r state=%d', id, initiator, type, service, params, state)
- if (type == telepathy.TUBE_TYPE_DBUS and service == Constants.SERVICE):
- if state == telepathy.TUBE_STATE_LOCAL_PENDING:
- self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id)
- tube_conn = TubeConnection(self.conn, self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id, group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
- self.recTube = RecordTube(tube_conn)
- self.recTube.connect("new-recd", self._newRecdCb)
- self.recTube.connect("recd-request", self._recdRequestCb)
- self.recTube.connect("recd-bits-arrived", self._recdBitsArrivedCb)
- self.recTube.connect("recd-unavailable", self._recdUnavailableCb)
-
-
- def _newRecdCb( self, objectThatSentTheSignal, recorder, xmlString ):
- self.__class__.log.debug('_newRecdCb')
- dom = None
- try:
- dom = xml.dom.minidom.parseString(xmlString)
- except:
- self.__class__.log.error('Unable to parse mesh xml')
- if (dom == None):
- return
-
- recd = Recorded()
- recd = serialize.fillRecdFromNode(recd, dom.documentElement)
- if (recd != None):
- self.__class__.log.debug('_newRecdCb: adding new recd thumb')
- recd.buddy = True
- recd.downloadedFromBuddy = False
- self.m.addMeshRecd( recd )
- else:
- self.__class__.log.debug('_newRecdCb: recd is None. Unable to parse XML')
-
-
- def requestMeshDownload( self, recd ):
- if (recd.meshDownloading):
- return True
-
- self.m.updateXoFullStatus()
- if (self.m.FULL):
- return True
-
- #this call will get the bits or request the bits if they're not available
- if (recd.buddy and (not recd.downloadedFromBuddy)):
- self.meshInitRoundRobin(recd)
- return True
-
- else:
- return False
-
-
- def meshInitRoundRobin( self, recd ):
- if (recd.meshDownloading):
- self.__class__.log.debug("meshInitRoundRobin: we are in midst of downloading this file...")
- return
-
- if (self.recTube == None):
- gobject.idle_add(self.ui.updateMeshProgress, False, recd)
- return
-
- #start with who took the photo
- recd.triedMeshBuddies = []
- recd.triedMeshBuddies.append(Instance.keyHashPrintable)
- self.meshReqRecFromBuddy( recd, recd.recorderHash, recd.recorderName )
-
-
- def meshNextRoundRobinBuddy( self, recd ):
- self.__class__.log.debug('meshNextRoundRobinBuddy')
- if (recd.meshReqCallbackId != 0):
- gobject.source_remove(recd.meshReqCallbackId)
- recd.meshReqCallbackId = 0
-
- #delete any stub of a partially downloaded file
- filepath = recd.getMediaFilepath()
- if (filepath != None):
- if (os.path.exists(filepath)):
- os.remove( filepath )
-
- goodBudObj = None
- buds = self._shared_activity.get_joined_buddies()
- for i in range (0, len(buds)):
- nextBudObj = buds[i]
- nextBud = util._sha_data(nextBudObj.props.key)
- nextBud = util.printable_hash(nextBud)
- if (recd.triedMeshBuddies.count(nextBud) > 0):
- self.__class__.log.debug('mnrrb: weve already tried bud ' + str(nextBudObj.props.nick))
- else:
- self.__class__.log.debug('mnrrb: ask next buddy: ' + str(nextBudObj.props.nick))
- goodBudObj = nextBudObj
- break
-
- if (goodBudObj != None):
- goodNick = goodBudObj.props.nick
- goodBud = util._sha_data(goodBudObj.props.key)
- goodBud = util.printable_hash(goodBud)
- self.meshReqRecFromBuddy(recd, goodBud, goodNick)
- else:
- self.__class__.log.debug('weve tried all buddies here, and no one has this recd')
- recd.meshDownloading = False
- recd.triedMeshBuddies = []
- recd.triedMeshBuddies.append(Instance.keyHashPrintable)
- self.ui.updateMeshProgress(False, recd)
-
-
- def meshReqRecFromBuddy( self, recd, fromWho, fromWhosNick ):
- recd.triedMeshBuddies.append( fromWho )
- recd.meshDownloadingFrom = fromWho
- recd.meshDownloadingFromNick = fromWhosNick
- recd.meshDownloadingProgress = False
- recd.meshDownloading = True
- recd.meshDownlodingPercent = 0.0
- self.ui.updateMeshProgress(True, recd)
- recd.meshReqCallbackId = gobject.timeout_add(self.meshTimeoutTime, self._meshCheckOnRecdRequest, recd)
- self.recTube.requestRecdBits( Instance.keyHashPrintable, fromWho, recd.mediaMd5 )
-
-
- def _meshCheckOnRecdRequest( self, recdRequesting ):
- #todo: add category for "not active activity, so go ahead and delete"
-
- if (recdRequesting.downloadedFromBuddy):
- self.__class__.log.debug('_meshCheckOnRecdRequest: recdRequesting.downloadedFromBuddy')
- if (recdRequesting.meshReqCallbackId != 0):
- gobject.source_remove(recdRequesting.meshReqCallbackId)
- recdRequesting.meshReqCallbackId = 0
- return False
- if (recdRequesting.deleted):
- self.__class__.log.debug('_meshCheckOnRecdRequest: recdRequesting.deleted')
- if (recdRequesting.meshReqCallbackId != 0):
- gobject.source_remove(recdRequesting.meshReqCallbackId)
- recdRequesting.meshReqCallbackId = 0
- return False
- if (recdRequesting.meshDownloadingProgress):
- self.__class__.log.debug('_meshCheckOnRecdRequest: recdRequesting.meshDownloadingProgress')
- #we've received some bits since last we checked, so keep waiting... they'll all get here eventually!
- recdRequesting.meshDownloadingProgress = False
- return True
- else:
- self.__class__.log.debug('_meshCheckOnRecdRequest: ! recdRequesting.meshDownloadingProgress')
- #that buddy we asked info from isn't responding; next buddy!
- #self.meshNextRoundRobinBuddy( recdRequesting )
- gobject.idle_add(self.meshNextRoundRobinBuddy, recdRequesting)
- return False
-
-
- def _recdRequestCb( self, objectThatSentTheSignal, whoWantsIt, md5sumOfIt ):
- #if we are here, it is because someone has been told we have what they want.
- #we need to send them that thing, whatever that thing is
- recd = self.m.getRecdByMd5( md5sumOfIt )
- if (recd == None):
- self.__class__.log.debug('_recdRequestCb: we dont have the recd they asked for')
- self.recTube.unavailableRecd(md5sumOfIt, Instance.keyHashPrintable, whoWantsIt)
- return
- if (recd.deleted):
- self.__class__.log.debug('_recdRequestCb: we have the recd, but it has been deleted, so we wont share')
- self.recTube.unavailableRecd(md5sumOfIt, Instance.keyHashPrintable, whoWantsIt)
- return
- if (recd.buddy and not recd.downloadedFromBuddy):
- self.__class__.log.debug('_recdRequestCb: we have an incomplete recd, so we wont share')
- self.recTube.unavailableRecd(md5sumOfIt, Instance.keyHashPrintable, whoWantsIt)
- return
-
- recd.meshUploading = True
- filepath = recd.getMediaFilepath()
-
- if (recd.type == Constants.TYPE_AUDIO):
- audioImgFilepath = recd.getAudioImageFilepath()
-
- destPath = os.path.join(Instance.instancePath, "audioBundle")
- destPath = utils.getUniqueFilepath(destPath, 0)
- cmd = "cat " + str(filepath) + " " + str(audioImgFilepath) + " > " + str(destPath)
- self.__class__.log.debug(cmd)
- os.system(cmd)
- filepath = destPath
-
- sent = self.recTube.broadcastRecd(recd.mediaMd5, filepath, whoWantsIt)
- recd.meshUploading = False
- #if you were deleted while uploading, now throw away those bits now
- if (recd.deleted):
- recd.doDeleteRecorded(recd)
-
-
- def _recdBitsArrivedCb( self, objectThatSentTheSignal, md5sumOfIt, part, numparts, bytes, fromWho ):
- #self.__class__.log.debug('_recdBitsArrivedCb: ' + str(part) + "/" + str(numparts))
- recd = self.m.getRecdByMd5( md5sumOfIt )
- if (recd == None):
- self.__class__.log.debug('_recdBitsArrivedCb: thx 4 yr bits, but we dont even have that photo')
- return
- if (recd.deleted):
- self.__class__.log.debug('_recdBitsArrivedCb: thx 4 yr bits, but we deleted that photo')
- return
- if (recd.downloadedFromBuddy):
- self.__class__.log.debug('_recdBitsArrivedCb: weve already downloadedFromBuddy')
- return
- if (not recd.buddy):
- self.__class__.log.debug('_recdBitsArrivedCb: uh, we took this photo, so dont need your bits')
- return
- if (recd.meshDownloadingFrom != fromWho):
- self.__class__.log.debug('_recdBitsArrivedCb: wrong bits ' + str(fromWho) + ", exp:" + str(recd.meshDownloadingFrom))
- return
-
- #update that we've heard back about this, reset the timeout
- gobject.source_remove(recd.meshReqCallbackId)
- recd.meshReqCallbackId = gobject.timeout_add(self.meshTimeoutTime, self._meshCheckOnRecdRequest, recd)
-
- #update the progress bar
- recd.meshDownlodingPercent = (part+0.0)/(numparts+0.0)
- recd.meshDownloadingProgress = True
- self.ui.updateMeshProgress(True, recd)
- f = open(recd.getMediaFilepath(), 'a+')
- f.write(bytes)
- f.close()
-
- if part == numparts:
- self.__class__.log.debug('Finished receiving %s' % recd.title)
- gobject.source_remove( recd.meshReqCallbackId )
- recd.meshReqCallbackId = 0
- recd.meshDownloading = False
- recd.meshDownlodingPercent = 1.0
- recd.downloadedFromBuddy = True
- if (recd.type == Constants.TYPE_AUDIO):
- filepath = recd.getMediaFilepath()
- bundlePath = os.path.join(Instance.instancePath, "audioBundle")
- bundlePath = utils.getUniqueFilepath(bundlePath, 0)
-
- cmd = "split -a 1 -b " + str(recd.mediaBytes) + " " + str(filepath) + " " + str(bundlePath)
- self.__class__.log.debug( cmd )
- os.system( cmd )
-
- bundleName = os.path.basename(bundlePath)
- mediaFilename = str(bundleName) + "a"
- mediaFilepath = os.path.join(Instance.instancePath, mediaFilename)
- mediaFilepathExt = os.path.join(Instance.instancePath, mediaFilename+".ogg")
- os.rename(mediaFilepath, mediaFilepathExt)
- audioImageFilename = str(bundleName) + "b"
- audioImageFilepath = os.path.join(Instance.instancePath, audioImageFilename)
- audioImageFilepathExt = os.path.join(Instance.instancePath, audioImageFilename+".png")
- os.rename(audioImageFilepath, audioImageFilepathExt)
-
- recd.mediaFilename = os.path.basename(mediaFilepathExt)
- recd.audioImageFilename = os.path.basename(audioImageFilepathExt)
-
- self.ui.showMeshRecd( recd )
- elif part > numparts:
- self.__class__.log.error('More parts than required have arrived')
-
-
- def _getAlbumArtCb( self, objectThatSentTheSignal, pixbuf, recd ):
-
- if (pixbuf != None):
- imagePath = os.path.join(Instance.instancePath, "audioPicture.png")
- imagePath = utils.getUniqueFilepath( imagePath, 0 )
- pixbuf.save( imagePath, "png", {} )
- recd.audioImageFilename = os.path.basename(imagePath)
-
- self.ui.showMeshRecd( recd )
- return False
-
-
- def _recdUnavailableCb( self, objectThatSentTheSignal, md5sumOfIt, whoDoesntHaveIt ):
- self.__class__.log.debug('_recdUnavailableCb: sux, we want to see that photo')
- recd = self.m.getRecdByMd5( md5sumOfIt )
- if (recd == None):
- self.__class__.log.debug('_recdUnavailableCb: actually, we dont even know about that one..')
- return
- if (recd.deleted):
- self.__class__.log.debug('_recdUnavailableCb: actually, since we asked, we deleted.')
- return
- if (not recd.buddy):
- self.__class__.log.debug('_recdUnavailableCb: uh, odd, we took that photo and have it already.')
- return
- if (recd.downloadedFromBuddy):
- self.__class__.log.debug('_recdUnavailableCb: we already downloaded it... you might have been slow responding.')
- return
- if (recd.meshDownloadingFrom != whoDoesntHaveIt):
- self.__class__.log.debug('_recdUnavailableCb: we arent asking you for a copy now. slow response, pbly.')
- return
-
- #self.meshNextRoundRobinBuddy( recd )
+ def _list_tubes_reply_cb(self, tubes):
+ for tube_info in tubes:
+ self._newTubeCb(*tube_info)
+
+
+ def _list_tubes_error_cb(self, e):
+ self.__class__.log.error('ListTubes() failed: %s', e)
+
+
+ def _setup(self):
+ #sets up the tubes...
+ if self._shared_activity is None:
+ self.__class__.log.error('_setup: Failed to share or join activity')
+ return
+
+ pservice = presenceservice.get_instance()
+ try:
+ name, path = pservice.get_preferred_connection()
+ self.conn = telepathy.client.Connection(name, path)
+ except:
+ self.__class__.log.error('_setup: Failed to get_preferred_connection')
+
+ # Work out what our room is called and whether we have Tubes already
+ bus_name, conn_path, channel_paths = self._shared_activity.get_channels()
+ room = None
+ tubes_chan = None
+ text_chan = None
+ for channel_path in channel_paths:
+ channel = telepathy.client.Channel(bus_name, channel_path)
+ htype, handle = channel.GetHandle()
+ if htype == telepathy.HANDLE_TYPE_ROOM:
+ self.__class__.log.debug('Found our room: it has handle#%d "%s"', handle, self.conn.InspectHandles(htype, [handle])[0])
+ room = handle
+ ctype = channel.GetChannelType()
+ if ctype == telepathy.CHANNEL_TYPE_TUBES:
+ self.__class__.log.debug('Found our Tubes channel at %s', channel_path)
+ tubes_chan = channel
+ elif ctype == telepathy.CHANNEL_TYPE_TEXT:
+ self.__class__.log.debug('Found our Text channel at %s', channel_path)
+ text_chan = channel
+
+ if room is None:
+ self.__class__.log.error("Presence service didn't create a room")
+ return
+ if text_chan is None:
+ self.__class__.log.error("Presence service didn't create a text channel")
+ return
+
+ # Make sure we have a Tubes channel - PS doesn't yet provide one
+ if tubes_chan is None:
+ self.__class__.log.debug("Didn't find our Tubes channel, requesting one...")
+ tubes_chan = self.conn.request_channel(telepathy.CHANNEL_TYPE_TUBES, telepathy.HANDLE_TYPE_ROOM, room, True)
+
+ self.tubes_chan = tubes_chan
+ self.text_chan = text_chan
+
+ tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal('NewTube', self._newTubeCb)
+
+
+ def _newTubeCb(self, id, initiator, type, service, params, state):
+ self.__class__.log.debug('New tube: ID=%d initator=%d type=%d service=%s params=%r state=%d', id, initiator, type, service, params, state)
+ if (type == telepathy.TUBE_TYPE_DBUS and service == Constants.SERVICE):
+ if state == telepathy.TUBE_STATE_LOCAL_PENDING:
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id)
+ tube_conn = TubeConnection(self.conn, self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id, group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
+ self.recTube = RecordTube(tube_conn)
+ self.recTube.connect("new-recd", self._newRecdCb)
+ self.recTube.connect("recd-request", self._recdRequestCb)
+ self.recTube.connect("recd-bits-arrived", self._recdBitsArrivedCb)
+ self.recTube.connect("recd-unavailable", self._recdUnavailableCb)
+
+
+ def _newRecdCb( self, objectThatSentTheSignal, recorder, xmlString ):
+ self.__class__.log.debug('_newRecdCb')
+ dom = None
+ try:
+ dom = xml.dom.minidom.parseString(xmlString)
+ except:
+ self.__class__.log.error('Unable to parse mesh xml')
+ if (dom == None):
+ return
+
+ recd = Recorded()
+ recd = serialize.fillRecdFromNode(recd, dom.documentElement)
+ if (recd != None):
+ self.__class__.log.debug('_newRecdCb: adding new recd thumb')
+ recd.buddy = True
+ recd.downloadedFromBuddy = False
+ self.m.addMeshRecd( recd )
+ else:
+ self.__class__.log.debug('_newRecdCb: recd is None. Unable to parse XML')
+
+
+ def requestMeshDownload( self, recd ):
+ if (recd.meshDownloading):
+ return True
+
+ self.m.updateXoFullStatus()
+ if (self.m.FULL):
+ return True
+
+ #this call will get the bits or request the bits if they're not available
+ if (recd.buddy and (not recd.downloadedFromBuddy)):
+ self.meshInitRoundRobin(recd)
+ return True
+
+ else:
+ return False
+
+
+ def meshInitRoundRobin( self, recd ):
+ if (recd.meshDownloading):
+ self.__class__.log.debug("meshInitRoundRobin: we are in midst of downloading this file...")
+ return
+
+ if (self.recTube == None):
+ gobject.idle_add(self.ui.updateMeshProgress, False, recd)
+ return
+
+ #start with who took the photo
+ recd.triedMeshBuddies = []
+ recd.triedMeshBuddies.append(Instance.keyHashPrintable)
+ self.meshReqRecFromBuddy( recd, recd.recorderHash, recd.recorderName )
+
+
+ def meshNextRoundRobinBuddy( self, recd ):
+ self.__class__.log.debug('meshNextRoundRobinBuddy')
+ if (recd.meshReqCallbackId != 0):
+ gobject.source_remove(recd.meshReqCallbackId)
+ recd.meshReqCallbackId = 0
+
+ #delete any stub of a partially downloaded file
+ filepath = recd.getMediaFilepath()
+ if (filepath != None):
+ if (os.path.exists(filepath)):
+ os.remove( filepath )
+
+ goodBudObj = None
+ buds = self._shared_activity.get_joined_buddies()
+ for i in range (0, len(buds)):
+ nextBudObj = buds[i]
+ nextBud = util._sha_data(nextBudObj.props.key)
+ nextBud = util.printable_hash(nextBud)
+ if (recd.triedMeshBuddies.count(nextBud) > 0):
+ self.__class__.log.debug('mnrrb: weve already tried bud ' + str(nextBudObj.props.nick))
+ else:
+ self.__class__.log.debug('mnrrb: ask next buddy: ' + str(nextBudObj.props.nick))
+ goodBudObj = nextBudObj
+ break
+
+ if (goodBudObj != None):
+ goodNick = goodBudObj.props.nick
+ goodBud = util._sha_data(goodBudObj.props.key)
+ goodBud = util.printable_hash(goodBud)
+ self.meshReqRecFromBuddy(recd, goodBud, goodNick)
+ else:
+ self.__class__.log.debug('weve tried all buddies here, and no one has this recd')
+ recd.meshDownloading = False
+ recd.triedMeshBuddies = []
+ recd.triedMeshBuddies.append(Instance.keyHashPrintable)
+ self.ui.updateMeshProgress(False, recd)
+
+
+ def meshReqRecFromBuddy( self, recd, fromWho, fromWhosNick ):
+ recd.triedMeshBuddies.append( fromWho )
+ recd.meshDownloadingFrom = fromWho
+ recd.meshDownloadingFromNick = fromWhosNick
+ recd.meshDownloadingProgress = False
+ recd.meshDownloading = True
+ recd.meshDownlodingPercent = 0.0
+ self.ui.updateMeshProgress(True, recd)
+ recd.meshReqCallbackId = gobject.timeout_add(self.meshTimeoutTime, self._meshCheckOnRecdRequest, recd)
+ self.recTube.requestRecdBits( Instance.keyHashPrintable, fromWho, recd.mediaMd5 )
+
+
+ def _meshCheckOnRecdRequest( self, recdRequesting ):
+ #todo: add category for "not active activity, so go ahead and delete"
+
+ if (recdRequesting.downloadedFromBuddy):
+ self.__class__.log.debug('_meshCheckOnRecdRequest: recdRequesting.downloadedFromBuddy')
+ if (recdRequesting.meshReqCallbackId != 0):
+ gobject.source_remove(recdRequesting.meshReqCallbackId)
+ recdRequesting.meshReqCallbackId = 0
+ return False
+ if (recdRequesting.deleted):
+ self.__class__.log.debug('_meshCheckOnRecdRequest: recdRequesting.deleted')
+ if (recdRequesting.meshReqCallbackId != 0):
+ gobject.source_remove(recdRequesting.meshReqCallbackId)
+ recdRequesting.meshReqCallbackId = 0
+ return False
+ if (recdRequesting.meshDownloadingProgress):
+ self.__class__.log.debug('_meshCheckOnRecdRequest: recdRequesting.meshDownloadingProgress')
+ #we've received some bits since last we checked, so keep waiting... they'll all get here eventually!
+ recdRequesting.meshDownloadingProgress = False
+ return True
+ else:
+ self.__class__.log.debug('_meshCheckOnRecdRequest: ! recdRequesting.meshDownloadingProgress')
+ #that buddy we asked info from isn't responding; next buddy!
+ #self.meshNextRoundRobinBuddy( recdRequesting )
+ gobject.idle_add(self.meshNextRoundRobinBuddy, recdRequesting)
+ return False
+
+
+ def _recdRequestCb( self, objectThatSentTheSignal, whoWantsIt, md5sumOfIt ):
+ #if we are here, it is because someone has been told we have what they want.
+ #we need to send them that thing, whatever that thing is
+ recd = self.m.getRecdByMd5( md5sumOfIt )
+ if (recd == None):
+ self.__class__.log.debug('_recdRequestCb: we dont have the recd they asked for')
+ self.recTube.unavailableRecd(md5sumOfIt, Instance.keyHashPrintable, whoWantsIt)
+ return
+ if (recd.deleted):
+ self.__class__.log.debug('_recdRequestCb: we have the recd, but it has been deleted, so we wont share')
+ self.recTube.unavailableRecd(md5sumOfIt, Instance.keyHashPrintable, whoWantsIt)
+ return
+ if (recd.buddy and not recd.downloadedFromBuddy):
+ self.__class__.log.debug('_recdRequestCb: we have an incomplete recd, so we wont share')
+ self.recTube.unavailableRecd(md5sumOfIt, Instance.keyHashPrintable, whoWantsIt)
+ return
+
+ recd.meshUploading = True
+ filepath = recd.getMediaFilepath()
+
+ if (recd.type == Constants.TYPE_AUDIO):
+ audioImgFilepath = recd.getAudioImageFilepath()
+
+ destPath = os.path.join(Instance.instancePath, "audioBundle")
+ destPath = utils.getUniqueFilepath(destPath, 0)
+ cmd = "cat " + str(filepath) + " " + str(audioImgFilepath) + " > " + str(destPath)
+ self.__class__.log.debug(cmd)
+ os.system(cmd)
+ filepath = destPath
+
+ sent = self.recTube.broadcastRecd(recd.mediaMd5, filepath, whoWantsIt)
+ recd.meshUploading = False
+ #if you were deleted while uploading, now throw away those bits now
+ if (recd.deleted):
+ recd.doDeleteRecorded(recd)
+
+
+ def _recdBitsArrivedCb( self, objectThatSentTheSignal, md5sumOfIt, part, numparts, bytes, fromWho ):
+ #self.__class__.log.debug('_recdBitsArrivedCb: ' + str(part) + "/" + str(numparts))
+ recd = self.m.getRecdByMd5( md5sumOfIt )
+ if (recd == None):
+ self.__class__.log.debug('_recdBitsArrivedCb: thx 4 yr bits, but we dont even have that photo')
+ return
+ if (recd.deleted):
+ self.__class__.log.debug('_recdBitsArrivedCb: thx 4 yr bits, but we deleted that photo')
+ return
+ if (recd.downloadedFromBuddy):
+ self.__class__.log.debug('_recdBitsArrivedCb: weve already downloadedFromBuddy')
+ return
+ if (not recd.buddy):
+ self.__class__.log.debug('_recdBitsArrivedCb: uh, we took this photo, so dont need your bits')
+ return
+ if (recd.meshDownloadingFrom != fromWho):
+ self.__class__.log.debug('_recdBitsArrivedCb: wrong bits ' + str(fromWho) + ", exp:" + str(recd.meshDownloadingFrom))
+ return
+
+ #update that we've heard back about this, reset the timeout
+ gobject.source_remove(recd.meshReqCallbackId)
+ recd.meshReqCallbackId = gobject.timeout_add(self.meshTimeoutTime, self._meshCheckOnRecdRequest, recd)
+
+ #update the progress bar
+ recd.meshDownlodingPercent = (part+0.0)/(numparts+0.0)
+ recd.meshDownloadingProgress = True
+ self.ui.updateMeshProgress(True, recd)
+ f = open(recd.getMediaFilepath(), 'a+')
+ f.write(bytes)
+ f.close()
+
+ if part == numparts:
+ self.__class__.log.debug('Finished receiving %s' % recd.title)
+ gobject.source_remove( recd.meshReqCallbackId )
+ recd.meshReqCallbackId = 0
+ recd.meshDownloading = False
+ recd.meshDownlodingPercent = 1.0
+ recd.downloadedFromBuddy = True
+ if (recd.type == Constants.TYPE_AUDIO):
+ filepath = recd.getMediaFilepath()
+ bundlePath = os.path.join(Instance.instancePath, "audioBundle")
+ bundlePath = utils.getUniqueFilepath(bundlePath, 0)
+
+ cmd = "split -a 1 -b " + str(recd.mediaBytes) + " " + str(filepath) + " " + str(bundlePath)
+ self.__class__.log.debug( cmd )
+ os.system( cmd )
+
+ bundleName = os.path.basename(bundlePath)
+ mediaFilename = str(bundleName) + "a"
+ mediaFilepath = os.path.join(Instance.instancePath, mediaFilename)
+ mediaFilepathExt = os.path.join(Instance.instancePath, mediaFilename+".ogg")
+ os.rename(mediaFilepath, mediaFilepathExt)
+ audioImageFilename = str(bundleName) + "b"
+ audioImageFilepath = os.path.join(Instance.instancePath, audioImageFilename)
+ audioImageFilepathExt = os.path.join(Instance.instancePath, audioImageFilename+".png")
+ os.rename(audioImageFilepath, audioImageFilepathExt)
+
+ recd.mediaFilename = os.path.basename(mediaFilepathExt)
+ recd.audioImageFilename = os.path.basename(audioImageFilepathExt)
+
+ self.ui.showMeshRecd( recd )
+ elif part > numparts:
+ self.__class__.log.error('More parts than required have arrived')
+
+
+ def _getAlbumArtCb( self, objectThatSentTheSignal, pixbuf, recd ):
+
+ if (pixbuf != None):
+ imagePath = os.path.join(Instance.instancePath, "audioPicture.png")
+ imagePath = utils.getUniqueFilepath( imagePath, 0 )
+ pixbuf.save( imagePath, "png", {} )
+ recd.audioImageFilename = os.path.basename(imagePath)
+
+ self.ui.showMeshRecd( recd )
+ return False
+
+
+ def _recdUnavailableCb( self, objectThatSentTheSignal, md5sumOfIt, whoDoesntHaveIt ):
+ self.__class__.log.debug('_recdUnavailableCb: sux, we want to see that photo')
+ recd = self.m.getRecdByMd5( md5sumOfIt )
+ if (recd == None):
+ self.__class__.log.debug('_recdUnavailableCb: actually, we dont even know about that one..')
+ return
+ if (recd.deleted):
+ self.__class__.log.debug('_recdUnavailableCb: actually, since we asked, we deleted.')
+ return
+ if (not recd.buddy):
+ self.__class__.log.debug('_recdUnavailableCb: uh, odd, we took that photo and have it already.')
+ return
+ if (recd.downloadedFromBuddy):
+ self.__class__.log.debug('_recdUnavailableCb: we already downloaded it... you might have been slow responding.')
+ return
+ if (recd.meshDownloadingFrom != whoDoesntHaveIt):
+ self.__class__.log.debug('_recdUnavailableCb: we arent asking you for a copy now. slow response, pbly.')
+ return
+
+ #self.meshNextRoundRobinBuddy( recd )
diff --git a/recorded.py b/recorded.py
index 488a01c..8639a70 100644
--- a/recorded.py
+++ b/recorded.py
@@ -30,144 +30,144 @@ import record
class Recorded:
- def __init__( self ):
- self.type = -1
- self.time = None
- self.recorderName = None
- self.recorderHash = None
- self.title = None
- self.colorStroke = None
- self.colorFill = None
- self.mediaMd5 = None
- self.thumbMd5 = None
- self.mediaBytes = None
- self.thumbBytes = None
- self.tags = None
-
- #flag to alert need to re-datastore the title
- self.metaChange = False
-
- #when you are datastore-serialized, you get one of these ids...
- self.datastoreId = None
- self.datastoreOb = None
-
- #if not from the datastore, then your media is here...
- self.mediaFilename = None
- self.thumbFilename = None
- self.audioImageFilename = None
-
- #for flagging when you are being saved to the datastore for the first time...
- #and just because you have a datastore id, doesn't mean you're saved
- self.savedMedia = False
- self.savedXml = False
-
- #assume you took the picture
- self.buddy = False
- self.downloadedFromBuddy = False
- self.triedMeshBuddies = []
- self.meshDownloading = False
- self.meshDownloadingFrom = ""
- self.meshDownloadingFromNick = ""
- self.meshDownlodingPercent = 0.0
- self.meshDownloadingProgress = False
- #if someone is downloading this, then hold onto it
- self.meshUploading = False
- self.meshReqCallbackId = 0
-
- self.deleted = False
-
-
- def setTitle( self, newTitle ):
- self.title = newTitle
- self.metaChange = True
-
-
- def setTags( self, newTags ):
- self.tags = newTags
- self.metaChange = True
-
-
- def isClipboardCopyable( self ):
- copyme = True
- if (self.buddy):
- if (not self.downloadedFromBuddy):
- return False
- return copyme
-
-
- #scenarios:
- #launch, your new thumb -- Journal/session
- #launch, your new media -- Journal/session
- #launch, their new thumb -- Journal/session/buddy
- #launch, their new media -- ([request->]) Journal/session/buddy
- #relaunch, your old thumb -- metadataPixbuf on request (or save to Journal/session..?)
- #relaunch, your old media -- datastoreObject->file (hold onto the datastore object, delete if deleted)
- #relaunch, their old thumb -- metadataPixbuf on request (or save to Journal/session..?)
- #relaunch, their old media -- datastoreObject->file (hold onto the datastore object, delete if deleted) | ([request->]) Journal/session/buddy
-
- def getThumbPixbuf( self ):
- thumbPixbuf = None
- thumbFilepath = self.getThumbFilepath()
- if ( os.path.isfile(thumbFilepath) ):
- thumbPixbuf = gtk.gdk.pixbuf_new_from_file(thumbFilepath)
- return thumbPixbuf
-
-
- def getThumbFilepath( self ):
- return os.path.join(Instance.instancePath, self.thumbFilename)
-
-
- def getAudioImagePixbuf( self ):
- audioPixbuf = None
-
- if (self.audioImageFilename == None):
- audioPixbuf = self.getThumbPixbuf()
- else:
- audioFilepath = self.getAudioImageFilepath()
- if (audioFilepath != None):
- audioPixbuf = gtk.gdk.pixbuf_new_from_file(audioFilepath)
-
- return audioPixbuf
-
-
- def getAudioImageFilepath( self ):
- if (self.audioImageFilename != None):
- audioFilepath = os.path.join(Instance.instancePath, self.audioImageFilename)
- return os.path.abspath(audioFilepath)
- else:
- return self.getThumbFilepath()
-
-
- def getMediaFilepath(self):
- if (self.datastoreId == None):
- if (not self.buddy):
- #just taken by you, so it is in the tempSessionDir
- mediaFilepath = os.path.join(Instance.instancePath, self.mediaFilename)
- return os.path.abspath(mediaFilepath)
- else:
- if (self.downloadedFromBuddy):
- #the user has requested the high-res version, and it has downloaded
- mediaFilepath = os.path.join(Instance.instancePath, self.mediaFilename)
- return os.path.abspath(mediaFilepath)
- else:
- if self.mediaFilename == None:
- #creating a new filepath, probably just got here from the mesh
- ext = Constants.mediaTypes[self.type][Constants.keyExt]
- recdPath = os.path.join(Instance.instancePath, "recdFile_"+self.mediaMd5+"."+ext)
- recdPath = utils.getUniqueFilepath(recdPath, 0)
- self.mediaFilename = os.path.basename(recdPath)
- mediaFilepath = os.path.join(Instance.instancePath, self.mediaFilename)
- return os.path.abspath(mediaFilepath)
- else:
- mediaFilepath = os.path.join(Instance.instancePath, self.mediaFilename)
- return os.path.abspath(mediaFilepath)
-
- else: #pulling from the datastore, regardless of who took it, cause we got it
- #first, get the datastoreObject and hold the reference in this Recorded instance
- if (self.datastoreOb == None):
- self.datastoreOb = serialize.getMediaFromDatastore( self )
- if (self.datastoreOb == None):
- print("RecordActivity error -- unable to get datastore object in getMediaFilepath")
- return None
-
- return self.datastoreOb.file_path \ No newline at end of file
+ def __init__( self ):
+ self.type = -1
+ self.time = None
+ self.recorderName = None
+ self.recorderHash = None
+ self.title = None
+ self.colorStroke = None
+ self.colorFill = None
+ self.mediaMd5 = None
+ self.thumbMd5 = None
+ self.mediaBytes = None
+ self.thumbBytes = None
+ self.tags = None
+
+ #flag to alert need to re-datastore the title
+ self.metaChange = False
+
+ #when you are datastore-serialized, you get one of these ids...
+ self.datastoreId = None
+ self.datastoreOb = None
+
+ #if not from the datastore, then your media is here...
+ self.mediaFilename = None
+ self.thumbFilename = None
+ self.audioImageFilename = None
+
+ #for flagging when you are being saved to the datastore for the first time...
+ #and just because you have a datastore id, doesn't mean you're saved
+ self.savedMedia = False
+ self.savedXml = False
+
+ #assume you took the picture
+ self.buddy = False
+ self.downloadedFromBuddy = False
+ self.triedMeshBuddies = []
+ self.meshDownloading = False
+ self.meshDownloadingFrom = ""
+ self.meshDownloadingFromNick = ""
+ self.meshDownlodingPercent = 0.0
+ self.meshDownloadingProgress = False
+ #if someone is downloading this, then hold onto it
+ self.meshUploading = False
+ self.meshReqCallbackId = 0
+
+ self.deleted = False
+
+
+ def setTitle( self, newTitle ):
+ self.title = newTitle
+ self.metaChange = True
+
+
+ def setTags( self, newTags ):
+ self.tags = newTags
+ self.metaChange = True
+
+
+ def isClipboardCopyable( self ):
+ copyme = True
+ if (self.buddy):
+ if (not self.downloadedFromBuddy):
+ return False
+ return copyme
+
+
+ #scenarios:
+ #launch, your new thumb -- Journal/session
+ #launch, your new media -- Journal/session
+ #launch, their new thumb -- Journal/session/buddy
+ #launch, their new media -- ([request->]) Journal/session/buddy
+ #relaunch, your old thumb -- metadataPixbuf on request (or save to Journal/session..?)
+ #relaunch, your old media -- datastoreObject->file (hold onto the datastore object, delete if deleted)
+ #relaunch, their old thumb -- metadataPixbuf on request (or save to Journal/session..?)
+ #relaunch, their old media -- datastoreObject->file (hold onto the datastore object, delete if deleted) | ([request->]) Journal/session/buddy
+
+ def getThumbPixbuf( self ):
+ thumbPixbuf = None
+ thumbFilepath = self.getThumbFilepath()
+ if ( os.path.isfile(thumbFilepath) ):
+ thumbPixbuf = gtk.gdk.pixbuf_new_from_file(thumbFilepath)
+ return thumbPixbuf
+
+
+ def getThumbFilepath( self ):
+ return os.path.join(Instance.instancePath, self.thumbFilename)
+
+
+ def getAudioImagePixbuf( self ):
+ audioPixbuf = None
+
+ if (self.audioImageFilename == None):
+ audioPixbuf = self.getThumbPixbuf()
+ else:
+ audioFilepath = self.getAudioImageFilepath()
+ if (audioFilepath != None):
+ audioPixbuf = gtk.gdk.pixbuf_new_from_file(audioFilepath)
+
+ return audioPixbuf
+
+
+ def getAudioImageFilepath( self ):
+ if (self.audioImageFilename != None):
+ audioFilepath = os.path.join(Instance.instancePath, self.audioImageFilename)
+ return os.path.abspath(audioFilepath)
+ else:
+ return self.getThumbFilepath()
+
+
+ def getMediaFilepath(self):
+ if (self.datastoreId == None):
+ if (not self.buddy):
+ #just taken by you, so it is in the tempSessionDir
+ mediaFilepath = os.path.join(Instance.instancePath, self.mediaFilename)
+ return os.path.abspath(mediaFilepath)
+ else:
+ if (self.downloadedFromBuddy):
+ #the user has requested the high-res version, and it has downloaded
+ mediaFilepath = os.path.join(Instance.instancePath, self.mediaFilename)
+ return os.path.abspath(mediaFilepath)
+ else:
+ if self.mediaFilename == None:
+ #creating a new filepath, probably just got here from the mesh
+ ext = Constants.mediaTypes[self.type][Constants.keyExt]
+ recdPath = os.path.join(Instance.instancePath, "recdFile_"+self.mediaMd5+"."+ext)
+ recdPath = utils.getUniqueFilepath(recdPath, 0)
+ self.mediaFilename = os.path.basename(recdPath)
+ mediaFilepath = os.path.join(Instance.instancePath, self.mediaFilename)
+ return os.path.abspath(mediaFilepath)
+ else:
+ mediaFilepath = os.path.join(Instance.instancePath, self.mediaFilename)
+ return os.path.abspath(mediaFilepath)
+
+ else: #pulling from the datastore, regardless of who took it, cause we got it
+ #first, get the datastoreObject and hold the reference in this Recorded instance
+ if (self.datastoreOb == None):
+ self.datastoreOb = serialize.getMediaFromDatastore( self )
+ if (self.datastoreOb == None):
+ print("RecordActivity error -- unable to get datastore object in getMediaFilepath")
+ return None
+
+ return self.datastoreOb.file_path \ No newline at end of file
diff --git a/recordtube.py b/recordtube.py
index 5332823..7f63922 100644
--- a/recordtube.py
+++ b/recordtube.py
@@ -10,117 +10,117 @@ import record
class RecordTube(ExportedGObject):
- __gsignals__ = {
- 'recd-bits-arrived':
- (gobject.SIGNAL_RUN_FIRST, None, [object,object,object,object,object]),
- 'recd-request':
- (gobject.SIGNAL_RUN_FIRST, None, [object,object]),
- 'new-recd':
- (gobject.SIGNAL_RUN_FIRST, None, [object,object]),
- 'recd-unavailable':
- (gobject.SIGNAL_RUN_FIRST, None, [object,object])
- }
-
-
- def __init__(self, tube):
- super(RecordTube, self).__init__(tube, Constants.PATH)
- self.tube = tube
-
- self.idNotify = self.tube.add_signal_receiver(self._newRecdTubeCb, 'notifyBudsOfNewRecd', Constants.IFACE, path=Constants.PATH, sender_keyword='sender')
- self.idRequest = self.tube.add_signal_receiver(self._reqRecdTubeCb, 'requestRecdBits', Constants.IFACE, path=Constants.PATH, sender_keyword='sender')
- self.idBroadcast = self.tube.add_signal_receiver(self._getRecdTubeCb, 'broadcastRecdBits', Constants.IFACE, path=Constants.PATH, sender_keyword='sender', byte_arrays=True)
- self.idUnavailable = self.tube.add_signal_receiver(self._unavailableRecdTubeCb, 'unavailableRecd', Constants.IFACE, path=Constants.PATH, sender_keyword='sender')
-
-
- @signal(dbus_interface=Constants.IFACE, signature='ss') #dual s for 2x strings
- def notifyBudsOfNewRecd(self, recorder, recdXml):
- record.Record.log.debug('Ive taken a new pho-ideo-audio! I hereby send you an xml thumb of said media via this interface.')
-
-
- def _newRecdTubeCb(self, recorder, recdXml, sender=None):
- record.Record.log.debug("_newRecdTubeCb from " + recorder )
- if sender == self.tube.get_unique_name():
- record.Record.log.debug("_newRecdTubeCb: sender is my bus name, so ignore my own signal")
- return
- elif (recorder == Instance.keyHashPrintable):
- record.Record.log.debug('_newRecdTubeCb: excuse me? you are asking me to share a photo with myself?')
- return
-
- self.emit( "new-recd", str(recorder), str(recdXml) )
-
-
- @signal(dbus_interface=Constants.IFACE, signature='sss') #triple s for 3x strings
- def requestRecdBits(self, whoWantsIt, whoTheyWantItFrom, recdMd5sumOfIt ):
- record.Record.log.debug('I am requesting a high-res version of someones media.')
-
-
- def _reqRecdTubeCb(self, whoWantsIt, whoTheyWantItFrom, recdMd5sumOfIt, sender=None):
- if sender == self.tube.get_unique_name():
- record.Record.log.debug("_reqRecdTubeCb: sender is my bus name, so ignore my own signal")
- return
- elif (whoWantsIt == Instance.keyHashPrintable):
- record.Record.log.debug('_reqRecdTubeCb: excuse me? you are asking me to share a photo with myself?')
- return
- elif (whoTheyWantItFrom != Instance.keyHashPrintable):
- record.Record.log.debug('_reqRecdTubeCb: ive overhead someone wants a photo, but not from me')
- return
-
- self.emit( "recd-request", str(whoWantsIt), str(recdMd5sumOfIt) )
-
-
- def broadcastRecd(self, md5, filepath, sendThisTo ):
- size = os.path.getsize(filepath)
- f = open(filepath)
- chunk_size = 1000
- chunks = size / chunk_size
- if (size%chunk_size != 0):
- chunks += 1
-
- for chunk in range(chunks):
- bytes = f.read(chunk_size)
- if (chunk == 0):
- record.Record.log.debug("sending " + str(chunk+1) + " of " + str(chunks) + " to " + sendThisTo )
- if (chunk == chunks-1):
- record.Record.log.debug("sending " + str(chunk+1) + " of " + str(chunks) + " to " + sendThisTo )
- self.broadcastRecdBits(md5, chunk+1, chunks, bytes, sendThisTo, Instance.keyHashPrintable)
-
- f.close()
- return True
-
-
- @signal(dbus_interface=Constants.IFACE, signature='suuayss')
- def broadcastRecdBits(self, md5, part, numparts, bytes, sendTo, fromWho ):
- pass
-
-
- def _getRecdTubeCb(self, md5, part, numparts, bytes, sentTo, fromWho, sender=None):
- if sender == self.tube.get_unique_name():
- #record.Record.log.debug("_reqRecdTubeCb: sender is my bus name, so ignore my own signal")
- return
- if (fromWho == Instance.keyHashPrintable):
- #record.Record.log.debug('_getRecdTubeCb: i dont want bits from meself, thx anyway. schizophrenic?')
- return
- if (sentTo != Instance.keyHashPrintable):
- #record.Record.log.debug('_getRecdTubeCb: ive overhead someone sending bits, but not to me!')
- return
-
- self.emit( "recd-bits-arrived", md5, part, numparts, bytes, fromWho )
-
-
- @signal(dbus_interface=Constants.IFACE, signature='sss') #triple s for 3x strings
- def unavailableRecd(self, md5sumOfIt, whoDoesntHaveIt, whoAskedForIt):
- record.Record.log.debug('unavailableRecd: id love to share this photo, but i am without a copy meself chum')
-
-
- def _unavailableRecdTubeCb( self, md5sumOfIt, whoDoesntHaveIt, whoAskedForIt, sender=None):
- if sender == self.tube.get_unique_name():
- record.Record.log.debug("_unavailableRecdTubeCb: sender is my bus name, so ignore my own signal")
- return
- if (whoDoesntHaveIt == Instance.keyHashPrintable):
- record.Record.log.debug('_unavailableRecdTubeCb: yes, i know i dont have it, i just told you/me/us.')
- return
- if (whoAskedForIt != Instance.keyHashPrintable):
- record.Record.log.debug('_unavailableRecdTubeCb: ive overheard someone doesnt have a photo, but i didnt ask for that one anyways')
- return
+ __gsignals__ = {
+ 'recd-bits-arrived':
+ (gobject.SIGNAL_RUN_FIRST, None, [object,object,object,object,object]),
+ 'recd-request':
+ (gobject.SIGNAL_RUN_FIRST, None, [object,object]),
+ 'new-recd':
+ (gobject.SIGNAL_RUN_FIRST, None, [object,object]),
+ 'recd-unavailable':
+ (gobject.SIGNAL_RUN_FIRST, None, [object,object])
+ }
+
+
+ def __init__(self, tube):
+ super(RecordTube, self).__init__(tube, Constants.PATH)
+ self.tube = tube
+
+ self.idNotify = self.tube.add_signal_receiver(self._newRecdTubeCb, 'notifyBudsOfNewRecd', Constants.IFACE, path=Constants.PATH, sender_keyword='sender')
+ self.idRequest = self.tube.add_signal_receiver(self._reqRecdTubeCb, 'requestRecdBits', Constants.IFACE, path=Constants.PATH, sender_keyword='sender')
+ self.idBroadcast = self.tube.add_signal_receiver(self._getRecdTubeCb, 'broadcastRecdBits', Constants.IFACE, path=Constants.PATH, sender_keyword='sender', byte_arrays=True)
+ self.idUnavailable = self.tube.add_signal_receiver(self._unavailableRecdTubeCb, 'unavailableRecd', Constants.IFACE, path=Constants.PATH, sender_keyword='sender')
+
+
+ @signal(dbus_interface=Constants.IFACE, signature='ss') #dual s for 2x strings
+ def notifyBudsOfNewRecd(self, recorder, recdXml):
+ record.Record.log.debug('Ive taken a new pho-ideo-audio! I hereby send you an xml thumb of said media via this interface.')
+
+
+ def _newRecdTubeCb(self, recorder, recdXml, sender=None):
+ record.Record.log.debug("_newRecdTubeCb from " + recorder )
+ if sender == self.tube.get_unique_name():
+ record.Record.log.debug("_newRecdTubeCb: sender is my bus name, so ignore my own signal")
+ return
+ elif (recorder == Instance.keyHashPrintable):
+ record.Record.log.debug('_newRecdTubeCb: excuse me? you are asking me to share a photo with myself?')
+ return
+
+ self.emit( "new-recd", str(recorder), str(recdXml) )
+
+
+ @signal(dbus_interface=Constants.IFACE, signature='sss') #triple s for 3x strings
+ def requestRecdBits(self, whoWantsIt, whoTheyWantItFrom, recdMd5sumOfIt ):
+ record.Record.log.debug('I am requesting a high-res version of someones media.')
+
+
+ def _reqRecdTubeCb(self, whoWantsIt, whoTheyWantItFrom, recdMd5sumOfIt, sender=None):
+ if sender == self.tube.get_unique_name():
+ record.Record.log.debug("_reqRecdTubeCb: sender is my bus name, so ignore my own signal")
+ return
+ elif (whoWantsIt == Instance.keyHashPrintable):
+ record.Record.log.debug('_reqRecdTubeCb: excuse me? you are asking me to share a photo with myself?')
+ return
+ elif (whoTheyWantItFrom != Instance.keyHashPrintable):
+ record.Record.log.debug('_reqRecdTubeCb: ive overhead someone wants a photo, but not from me')
+ return
+
+ self.emit( "recd-request", str(whoWantsIt), str(recdMd5sumOfIt) )
+
+
+ def broadcastRecd(self, md5, filepath, sendThisTo ):
+ size = os.path.getsize(filepath)
+ f = open(filepath)
+ chunk_size = 1000
+ chunks = size / chunk_size
+ if (size%chunk_size != 0):
+ chunks += 1
+
+ for chunk in range(chunks):
+ bytes = f.read(chunk_size)
+ if (chunk == 0):
+ record.Record.log.debug("sending " + str(chunk+1) + " of " + str(chunks) + " to " + sendThisTo )
+ if (chunk == chunks-1):
+ record.Record.log.debug("sending " + str(chunk+1) + " of " + str(chunks) + " to " + sendThisTo )
+ self.broadcastRecdBits(md5, chunk+1, chunks, bytes, sendThisTo, Instance.keyHashPrintable)
+
+ f.close()
+ return True
+
+
+ @signal(dbus_interface=Constants.IFACE, signature='suuayss')
+ def broadcastRecdBits(self, md5, part, numparts, bytes, sendTo, fromWho ):
+ pass
+
+
+ def _getRecdTubeCb(self, md5, part, numparts, bytes, sentTo, fromWho, sender=None):
+ if sender == self.tube.get_unique_name():
+ #record.Record.log.debug("_reqRecdTubeCb: sender is my bus name, so ignore my own signal")
+ return
+ if (fromWho == Instance.keyHashPrintable):
+ #record.Record.log.debug('_getRecdTubeCb: i dont want bits from meself, thx anyway. schizophrenic?')
+ return
+ if (sentTo != Instance.keyHashPrintable):
+ #record.Record.log.debug('_getRecdTubeCb: ive overhead someone sending bits, but not to me!')
+ return
+
+ self.emit( "recd-bits-arrived", md5, part, numparts, bytes, fromWho )
+
+
+ @signal(dbus_interface=Constants.IFACE, signature='sss') #triple s for 3x strings
+ def unavailableRecd(self, md5sumOfIt, whoDoesntHaveIt, whoAskedForIt):
+ record.Record.log.debug('unavailableRecd: id love to share this photo, but i am without a copy meself chum')
+
+
+ def _unavailableRecdTubeCb( self, md5sumOfIt, whoDoesntHaveIt, whoAskedForIt, sender=None):
+ if sender == self.tube.get_unique_name():
+ record.Record.log.debug("_unavailableRecdTubeCb: sender is my bus name, so ignore my own signal")
+ return
+ if (whoDoesntHaveIt == Instance.keyHashPrintable):
+ record.Record.log.debug('_unavailableRecdTubeCb: yes, i know i dont have it, i just told you/me/us.')
+ return
+ if (whoAskedForIt != Instance.keyHashPrintable):
+ record.Record.log.debug('_unavailableRecdTubeCb: ive overheard someone doesnt have a photo, but i didnt ask for that one anyways')
+ return
- self.emit("recd-unavailable", md5sumOfIt, whoDoesntHaveIt) \ No newline at end of file
+ self.emit("recd-unavailable", md5sumOfIt, whoDoesntHaveIt) \ No newline at end of file
diff --git a/serialize.py b/serialize.py
index f86c373..8e56d5f 100644
--- a/serialize.py
+++ b/serialize.py
@@ -14,329 +14,320 @@ import record
import utils
import recorded
-def fillMediaHash( index, mediaHashs ):
- doc = None
- if (os.path.exists(index)):
- try:
- doc = parse( os.path.abspath(index) )
- except:
- doc = None
- if (doc == None):
- return
-
- for key,value in Constants.mediaTypes.items():
- recdElements = doc.documentElement.getElementsByTagName(value[Constants.keyName])
- for el in recdElements:
- _loadMediaIntoHash( el, mediaHashs[key] )
+def fillMediaHash( doc, mediaHashs ):
+ for key,value in Constants.mediaTypes.items():
+ recdElements = doc.documentElement.getElementsByTagName(value[Constants.keyName])
+ for el in recdElements:
+ _loadMediaIntoHash( el, mediaHashs[key] )
def _loadMediaIntoHash( el, hash ):
- addToHash = True
- recd = record.Recorded()
- recd = fillRecdFromNode(recd, el)
- if (recd != None):
- if (recd.datastoreId != None):
- #quickly check: if you have a datastoreId that the file hasn't been deleted,
- #cause if you do, we need to flag your removal
- #2904 trac
- recd.datastoreOb = getMediaFromDatastore( recd )
- if (recd.datastoreOb == None):
- addToHash = False
- else:
- #name might have been changed in the journal, so reflect that here
- if (recd.title != recd.datastoreOb.metadata['title']):
- recd.setTitle(recd.datastoreOb.metadata['title'])
- if (recd.tags != recd.datastoreOb.metadata['tags']):
- recd.setTags(recd.datastoreOb.metadata['tags'])
- if (recd.buddy):
- recd.downloadedFromBuddy = True
-
- recd.datastoreOb == None
-
- if (addToHash):
- hash.append( recd )
+ addToHash = True
+ recd = record.Recorded()
+ recd = fillRecdFromNode(recd, el)
+ if (recd != None):
+ if (recd.datastoreId != None):
+ #quickly check: if you have a datastoreId that the file hasn't been deleted,
+ #cause if you do, we need to flag your removal
+ #2904 trac
+ recd.datastoreOb = getMediaFromDatastore( recd )
+ if (recd.datastoreOb == None):
+ addToHash = False
+ else:
+ #name might have been changed in the journal, so reflect that here
+ if (recd.title != recd.datastoreOb.metadata['title']):
+ recd.setTitle(recd.datastoreOb.metadata['title'])
+ if (recd.tags != recd.datastoreOb.metadata['tags']):
+ recd.setTags(recd.datastoreOb.metadata['tags'])
+ if (recd.buddy):
+ recd.downloadedFromBuddy = True
+
+ recd.datastoreOb == None
+
+ if (addToHash):
+ hash.append( recd )
def getMediaFromDatastore( recd ):
- if (recd.datastoreId == None):
- return None
+ if (recd.datastoreId == None):
+ return None
- if (recd.datastoreOb != None):
- #already have the object
- return recd.datastoreOb
+ if (recd.datastoreOb != None):
+ #already have the object
+ return recd.datastoreOb
- mediaObject = None
- try:
- mediaObject = datastore.get( recd.datastoreId )
- finally:
- if (mediaObject == None):
- return None
+ mediaObject = None
+ try:
+ mediaObject = datastore.get( recd.datastoreId )
+ finally:
+ if (mediaObject == None):
+ return None
- return mediaObject
+ return mediaObject
def removeMediaFromDatastore( recd ):
- #before this method is called, the media are removed from the file
- if (recd.datastoreId == None):
- return
- if (recd.datastoreOb == None):
- return
+ #before this method is called, the media are removed from the file
+ if (recd.datastoreId == None):
+ return
+ if (recd.datastoreOb == None):
+ return
- try:
- recd.datastoreOb.destroy()
- datastore.delete( recd.datastoreId )
+ try:
+ recd.datastoreOb.destroy()
+ datastore.delete( recd.datastoreId )
- del recd.datastoreId
- recd.datastoreId = None
+ del recd.datastoreId
+ recd.datastoreId = None
- del recd.datastoreOb
- recd.datastoreOb = None
+ del recd.datastoreOb
+ recd.datastoreOb = None
- finally:
- #todo: add error message here
- pass
+ finally:
+ #todo: add error message here
+ pass
def fillRecdFromNode( recd, el ):
- if (el.getAttributeNode(Constants.recdType) != None):
- typeInt = int(el.getAttribute(Constants.recdType))
- recd.type = typeInt
-
- if (el.getAttributeNode(Constants.recdTitle) != None):
- recd.title = el.getAttribute(Constants.recdTitle)
-
- if (el.getAttributeNode(Constants.recdTime) != None):
- timeInt = int(el.getAttribute(Constants.recdTime))
- recd.time = timeInt
-
- if (el.getAttributeNode(Constants.recdRecorderName) != None):
- recd.recorderName = el.getAttribute(Constants.recdRecorderName)
-
- if (el.getAttributeNode(Constants.recdTags) != None):
- recd.tags = el.getAttribute(Constants.recdTags)
- else:
- recd.tags = ""
-
- if (el.getAttributeNode(Constants.recdRecorderHash) != None):
- recd.recorderHash = el.getAttribute(Constants.recdRecorderHash)
-
- if (el.getAttributeNode(Constants.recdColorStroke) != None):
- try:
- colorStrokeHex = el.getAttribute(Constants.recdColorStroke)
- colorStroke = Color()
- colorStroke.init_hex(colorStrokeHex)
- recd.colorStroke = colorStroke
- except:
- record.Record.log.error("unable to load recd colorStroke")
-
- if (el.getAttributeNode(Constants.recdColorFill) != None):
- try:
- colorFillHex = el.getAttribute(Constants.recdColorFill)
- colorFill = Color()
- colorFill.init_hex( colorFillHex )
- recd.colorFill = colorFill
- except:
- record.Record.log.error("unable to load recd colorFill")
-
- if (el.getAttributeNode(Constants.recdBuddy) != None):
- recd.buddy = (el.getAttribute(Constants.recdBuddy) == "True")
-
- if (el.getAttributeNode(Constants.recdMediaMd5) != None):
- recd.mediaMd5 = el.getAttribute(Constants.recdMediaMd5)
-
- if (el.getAttributeNode(Constants.recdThumbMd5) != None):
- recd.thumbMd5 = el.getAttribute(Constants.recdThumbMd5)
-
- if (el.getAttributeNode(Constants.recdMediaBytes) != None):
- recd.mediaBytes = el.getAttribute(Constants.recdMediaBytes)
-
- if (el.getAttributeNode(Constants.recdThumbBytes) != None):
- recd.thumbBytes = el.getAttribute(Constants.recdThumbBytes)
-
- bt = el.getAttributeNode(Constants.recdBase64Thumb)
- if (bt != None):
- try:
- thumbPath = os.path.join(Instance.instancePath, "datastoreThumb.jpg")
- thumbPath = utils.getUniqueFilepath( thumbPath, 0 )
- thumbImg = utils.getPixbufFromString( bt.nodeValue )
- thumbImg.save(thumbPath, "jpeg", {"quality":"85"} )
- recd.thumbFilename = os.path.basename(thumbPath)
- record.Record.log.debug("saved thumbFilename")
- except:
- record.Record.log.error("unable to getRecdBase64Thumb")
-
- ai = el.getAttributeNode(Constants.recdAudioImage)
- if (not ai == None):
- try:
- audioImagePath = os.path.join(Instance.instancePath, "audioImage.png")
- audioImagePath = utils.getUniqueFilepath( audioImagePath, 0 )
- audioImage = utils.getPixbufFromString( ai.nodeValue )
- audioImage.save(audioImagePath, "png", {} )
- recd.audioImageFilename = os.path.basename(audioImagePath)
- record.Record.log.debug("loaded audio image and set audioImageFilename")
- except:
- record.Record.log.error("unable to load audio image")
-
- datastoreNode = el.getAttributeNode(Constants.recdDatastoreId)
- if (datastoreNode != None):
- recd.datastoreId = datastoreNode.nodeValue
-
- return recd
+ if (el.getAttributeNode(Constants.recdType) != None):
+ typeInt = int(el.getAttribute(Constants.recdType))
+ recd.type = typeInt
+
+ if (el.getAttributeNode(Constants.recdTitle) != None):
+ recd.title = el.getAttribute(Constants.recdTitle)
+
+ if (el.getAttributeNode(Constants.recdTime) != None):
+ timeInt = int(el.getAttribute(Constants.recdTime))
+ recd.time = timeInt
+
+ if (el.getAttributeNode(Constants.recdRecorderName) != None):
+ recd.recorderName = el.getAttribute(Constants.recdRecorderName)
+
+ if (el.getAttributeNode(Constants.recdTags) != None):
+ recd.tags = el.getAttribute(Constants.recdTags)
+ else:
+ recd.tags = ""
+
+ if (el.getAttributeNode(Constants.recdRecorderHash) != None):
+ recd.recorderHash = el.getAttribute(Constants.recdRecorderHash)
+
+ if (el.getAttributeNode(Constants.recdColorStroke) != None):
+ try:
+ colorStrokeHex = el.getAttribute(Constants.recdColorStroke)
+ colorStroke = Color()
+ colorStroke.init_hex(colorStrokeHex)
+ recd.colorStroke = colorStroke
+ except:
+ record.Record.log.error("unable to load recd colorStroke")
+
+ if (el.getAttributeNode(Constants.recdColorFill) != None):
+ try:
+ colorFillHex = el.getAttribute(Constants.recdColorFill)
+ colorFill = Color()
+ colorFill.init_hex( colorFillHex )
+ recd.colorFill = colorFill
+ except:
+ record.Record.log.error("unable to load recd colorFill")
+
+ if (el.getAttributeNode(Constants.recdBuddy) != None):
+ recd.buddy = (el.getAttribute(Constants.recdBuddy) == "True")
+
+ if (el.getAttributeNode(Constants.recdMediaMd5) != None):
+ recd.mediaMd5 = el.getAttribute(Constants.recdMediaMd5)
+
+ if (el.getAttributeNode(Constants.recdThumbMd5) != None):
+ recd.thumbMd5 = el.getAttribute(Constants.recdThumbMd5)
+
+ if (el.getAttributeNode(Constants.recdMediaBytes) != None):
+ recd.mediaBytes = el.getAttribute(Constants.recdMediaBytes)
+
+ if (el.getAttributeNode(Constants.recdThumbBytes) != None):
+ recd.thumbBytes = el.getAttribute(Constants.recdThumbBytes)
+
+ bt = el.getAttributeNode(Constants.recdBase64Thumb)
+ if (bt != None):
+ try:
+ thumbPath = os.path.join(Instance.instancePath, "datastoreThumb.jpg")
+ thumbPath = utils.getUniqueFilepath( thumbPath, 0 )
+ thumbImg = utils.getPixbufFromString( bt.nodeValue )
+ thumbImg.save(thumbPath, "jpeg", {"quality":"85"} )
+ recd.thumbFilename = os.path.basename(thumbPath)
+ record.Record.log.debug("saved thumbFilename")
+ except:
+ record.Record.log.error("unable to getRecdBase64Thumb")
+
+ ai = el.getAttributeNode(Constants.recdAudioImage)
+ if (not ai == None):
+ try:
+ audioImagePath = os.path.join(Instance.instancePath, "audioImage.png")
+ audioImagePath = utils.getUniqueFilepath( audioImagePath, 0 )
+ audioImage = utils.getPixbufFromString( ai.nodeValue )
+ audioImage.save(audioImagePath, "png", {} )
+ recd.audioImageFilename = os.path.basename(audioImagePath)
+ record.Record.log.debug("loaded audio image and set audioImageFilename")
+ except:
+ record.Record.log.error("unable to load audio image")
+
+ datastoreNode = el.getAttributeNode(Constants.recdDatastoreId)
+ if (datastoreNode != None):
+ recd.datastoreId = datastoreNode.nodeValue
+
+ return recd
def getRecdXmlMeshString( recd ):
- impl = getDOMImplementation()
- recdXml = impl.createDocument(None, Constants.recdRecd, None)
- root = recdXml.documentElement
- _addRecdXmlAttrs( root, recd, True )
+ impl = getDOMImplementation()
+ recdXml = impl.createDocument(None, Constants.recdRecd, None)
+ root = recdXml.documentElement
+ _addRecdXmlAttrs( root, recd, True )
- writer = cStringIO.StringIO()
- recdXml.writexml(writer)
- return writer.getvalue()
+ writer = cStringIO.StringIO()
+ recdXml.writexml(writer)
+ return writer.getvalue()
def _addRecdXmlAttrs( el, recd, forMeshTransmit ):
- el.setAttribute(Constants.recdType, str(recd.type))
-
- if ((recd.type == Constants.TYPE_AUDIO) and (not forMeshTransmit)):
- aiPixbuf = recd.getAudioImagePixbuf( )
- aiPixbufString = str( utils.getStringFromPixbuf(aiPixbuf) )
- el.setAttribute(Constants.recdAudioImage, aiPixbufString)
-
- if ((recd.datastoreId != None) and (not forMeshTransmit)):
- el.setAttribute(Constants.recdDatastoreId, str(recd.datastoreId))
-
- el.setAttribute(Constants.recdTitle, recd.title)
- el.setAttribute(Constants.recdTime, str(recd.time))
- el.setAttribute(Constants.recdRecorderName, recd.recorderName)
- el.setAttribute(Constants.recdRecorderHash, str(recd.recorderHash) )
- el.setAttribute(Constants.recdColorStroke, str(recd.colorStroke.hex) )
- el.setAttribute(Constants.recdColorFill, str(recd.colorFill.hex) )
- el.setAttribute(Constants.recdBuddy, str(recd.buddy))
- el.setAttribute(Constants.recdMediaMd5, str(recd.mediaMd5))
- el.setAttribute(Constants.recdThumbMd5, str(recd.thumbMd5))
- el.setAttribute(Constants.recdMediaBytes, str(recd.mediaBytes))
- el.setAttribute(Constants.recdThumbBytes, str(recd.thumbBytes))
- el.setAttribute(Constants.recdRecordVersion, str(Constants.VERSION))
-
- pixbuf = recd.getThumbPixbuf( )
- thumb64 = str( utils.getStringFromPixbuf(pixbuf) )
- el.setAttribute(Constants.recdBase64Thumb, thumb64)
+ el.setAttribute(Constants.recdType, str(recd.type))
+
+ if ((recd.type == Constants.TYPE_AUDIO) and (not forMeshTransmit)):
+ aiPixbuf = recd.getAudioImagePixbuf( )
+ aiPixbufString = str( utils.getStringFromPixbuf(aiPixbuf) )
+ el.setAttribute(Constants.recdAudioImage, aiPixbufString)
+
+ if ((recd.datastoreId != None) and (not forMeshTransmit)):
+ el.setAttribute(Constants.recdDatastoreId, str(recd.datastoreId))
+
+ el.setAttribute(Constants.recdTitle, recd.title)
+ el.setAttribute(Constants.recdTime, str(recd.time))
+ el.setAttribute(Constants.recdRecorderName, recd.recorderName)
+ el.setAttribute(Constants.recdRecorderHash, str(recd.recorderHash) )
+ el.setAttribute(Constants.recdColorStroke, str(recd.colorStroke.hex) )
+ el.setAttribute(Constants.recdColorFill, str(recd.colorFill.hex) )
+ el.setAttribute(Constants.recdBuddy, str(recd.buddy))
+ el.setAttribute(Constants.recdMediaMd5, str(recd.mediaMd5))
+ el.setAttribute(Constants.recdThumbMd5, str(recd.thumbMd5))
+ el.setAttribute(Constants.recdMediaBytes, str(recd.mediaBytes))
+ el.setAttribute(Constants.recdThumbBytes, str(recd.thumbBytes))
+ el.setAttribute(Constants.recdRecordVersion, str(Constants.VERSION))
+
+ pixbuf = recd.getThumbPixbuf( )
+ thumb64 = str( utils.getStringFromPixbuf(pixbuf) )
+ el.setAttribute(Constants.recdBase64Thumb, thumb64)
def saveMediaHash( mediaHashs ):
- impl = getDOMImplementation()
- album = impl.createDocument(None, Constants.recdAlbum, None)
- root = album.documentElement
-
- #flag everything for saving...
- atLeastOne = False
- for type,value in Constants.mediaTypes.items():
- typeName = value[Constants.keyName]
- hash = mediaHashs[type]
- for i in range (0, len(hash)):
- recd = hash[i]
- recd.savedXml = False
- recd.savedMedia = False
- atLeastOne = True
-
- #and if there is anything to save, save it
- if (atLeastOne):
- for type,value in Constants.mediaTypes.items():
- typeName = value[Constants.keyName]
- hash = mediaHashs[type]
-
- for i in range (0, len(hash)):
- recd = hash[i]
- mediaEl = album.createElement( typeName )
- root.appendChild( mediaEl )
- _saveMedia( mediaEl, recd )
-
- return album
+ impl = getDOMImplementation()
+ album = impl.createDocument(None, Constants.recdAlbum, None)
+ root = album.documentElement
+
+ #flag everything for saving...
+ atLeastOne = False
+ for type,value in Constants.mediaTypes.items():
+ typeName = value[Constants.keyName]
+ hash = mediaHashs[type]
+ for i in range (0, len(hash)):
+ recd = hash[i]
+ recd.savedXml = False
+ recd.savedMedia = False
+ atLeastOne = True
+
+ #and if there is anything to save, save it
+ if (atLeastOne):
+ for type,value in Constants.mediaTypes.items():
+ typeName = value[Constants.keyName]
+ hash = mediaHashs[type]
+
+ for i in range (0, len(hash)):
+ recd = hash[i]
+ mediaEl = album.createElement( typeName )
+ root.appendChild( mediaEl )
+ _saveMedia( mediaEl, recd )
+
+ return album
def _saveMedia( el, recd ):
- if ( (recd.buddy == True) and (recd.datastoreId == None) and (not recd.downloadedFromBuddy) ):
- recd.savedMedia = True
- _saveXml( el, recd )
- else:
- recd.savedMedia = False
- _saveMediaToDatastore( el, recd )
+ if ( (recd.buddy == True) and (recd.datastoreId == None) and (not recd.downloadedFromBuddy) ):
+ recd.savedMedia = True
+ _saveXml( el, recd )
+ else:
+ recd.savedMedia = False
+ _saveMediaToDatastore( el, recd )
def _saveXml( el, recd ):
- if (recd.thumbFilename != None):
- _addRecdXmlAttrs( el, recd, False )
- else:
- record.Record.log.debug("WOAH, ERROR: recd has no thumbFilename?! " + str(recd) )
- recd.savedXml = True
+ if (recd.thumbFilename != None):
+ _addRecdXmlAttrs( el, recd, False )
+ else:
+ record.Record.log.debug("WOAH, ERROR: recd has no thumbFilename?! " + str(recd) )
+ recd.savedXml = True
def _saveMediaToDatastore( el, recd ):
- #note that we update the recds that go through here to how they would
- #look on a fresh load from file since this won't just happen on close()
-
- if (recd.datastoreId != None):
- #already saved to the datastore, don't need to re-rewrite the file since the mediums are immutable
- #However, they might have changed the name of the file
- if (recd.metaChange):
- recd.datastoreOb = getMediaFromDatastore( recd )
- if (recd.datastoreOb.metadata['title'] != recd.title):
- recd.datastoreOb.metadata['title'] = recd.title
- datastore.write(recd.datastoreOb)
- if (recd.datastoreOb.metadata['tags'] != recd.tags):
- recd.datastoreOb.metadata['tags'] = recd.tags
- datastore.write(recd.datastoreOb)
-
- #reset for the next title change if not closing...
- recd.metaChange = False
- #save the title to the xml
- recd.savedMedia = True
- _saveXml( el, recd )
- else:
- recd.savedMedia = True
- _saveXml( el, recd )
-
- else:
- #this will remove the media from being accessed on the local disk since it puts it away into cold storage
- #therefore this is only called when write_file is called by the activity superclass
- mediaObject = datastore.create()
- mediaObject.metadata['title'] = recd.title
- mediaObject.metadata['tags'] = recd.tags
-
- datastorePreviewPixbuf = recd.getThumbPixbuf()
- if (recd.type == Constants.TYPE_AUDIO):
- datastorePreviewPixbuf = recd.getAudioImagePixbuf()
- elif (recd.type == Constants.TYPE_PHOTO):
- datastorePreviewFilepath = recd.getMediaFilepath()
- datastorePreviewPixbuf = gtk.gdk.pixbuf_new_from_file(datastorePreviewFilepath)
-
- datastorePreviewWidth = 300
- datastorePreviewHeight = 225
- if (datastorePreviewPixbuf.get_width() != datastorePreviewWidth):
- datastorePreviewPixbuf = datastorePreviewPixbuf.scale_simple(datastorePreviewWidth, datastorePreviewHeight, gtk.gdk.INTERP_NEAREST)
-
- datastorePreviewBase64 = utils.getStringFromPixbuf(datastorePreviewPixbuf)
- mediaObject.metadata['preview'] = datastorePreviewBase64
-
- colors = str(recd.colorStroke.hex) + "," + str(recd.colorFill.hex)
- mediaObject.metadata['icon-color'] = colors
-
- mtype = Constants.mediaTypes[recd.type]
- mime = mtype[Constants.keyMime]
- mediaObject.metadata['mime_type'] = mime
-
- mediaObject.metadata['activity_id'] = Constants.activityId
-
- mediaFile = recd.getMediaFilepath()
- mediaObject.file_path = mediaFile
- mediaObject.transfer_ownership = True
-
- datastore.write( mediaObject )
-
- recd.datastoreId = mediaObject.object_id
- recd.savedMedia = True
-
- _saveXml( el, recd )
-
- recd.mediaFilename = None \ No newline at end of file
+ #note that we update the recds that go through here to how they would
+ #look on a fresh load from file since this won't just happen on close()
+
+ if (recd.datastoreId != None):
+ #already saved to the datastore, don't need to re-rewrite the file since the mediums are immutable
+ #However, they might have changed the name of the file
+ if (recd.metaChange):
+ recd.datastoreOb = getMediaFromDatastore( recd )
+ if (recd.datastoreOb.metadata['title'] != recd.title):
+ recd.datastoreOb.metadata['title'] = recd.title
+ datastore.write(recd.datastoreOb)
+ if (recd.datastoreOb.metadata['tags'] != recd.tags):
+ recd.datastoreOb.metadata['tags'] = recd.tags
+ datastore.write(recd.datastoreOb)
+
+ #reset for the next title change if not closing...
+ recd.metaChange = False
+ #save the title to the xml
+ recd.savedMedia = True
+ _saveXml( el, recd )
+ else:
+ recd.savedMedia = True
+ _saveXml( el, recd )
+
+ else:
+ #this will remove the media from being accessed on the local disk since it puts it away into cold storage
+ #therefore this is only called when write_file is called by the activity superclass
+ mediaObject = datastore.create()
+ mediaObject.metadata['title'] = recd.title
+ mediaObject.metadata['tags'] = recd.tags
+
+ datastorePreviewPixbuf = recd.getThumbPixbuf()
+ if (recd.type == Constants.TYPE_AUDIO):
+ datastorePreviewPixbuf = recd.getAudioImagePixbuf()
+ elif (recd.type == Constants.TYPE_PHOTO):
+ datastorePreviewFilepath = recd.getMediaFilepath()
+ datastorePreviewPixbuf = gtk.gdk.pixbuf_new_from_file(datastorePreviewFilepath)
+
+ datastorePreviewWidth = 300
+ datastorePreviewHeight = 225
+ if (datastorePreviewPixbuf.get_width() != datastorePreviewWidth):
+ datastorePreviewPixbuf = datastorePreviewPixbuf.scale_simple(datastorePreviewWidth, datastorePreviewHeight, gtk.gdk.INTERP_NEAREST)
+
+ datastorePreviewBase64 = utils.getStringFromPixbuf(datastorePreviewPixbuf)
+ mediaObject.metadata['preview'] = datastorePreviewBase64
+
+ colors = str(recd.colorStroke.hex) + "," + str(recd.colorFill.hex)
+ mediaObject.metadata['icon-color'] = colors
+
+ mtype = Constants.mediaTypes[recd.type]
+ mime = mtype[Constants.keyMime]
+ mediaObject.metadata['mime_type'] = mime
+
+ mediaObject.metadata['activity_id'] = Constants.activityId
+
+ mediaFile = recd.getMediaFilepath()
+ mediaObject.file_path = mediaFile
+ mediaObject.transfer_ownership = True
+
+ datastore.write( mediaObject )
+
+ recd.datastoreId = mediaObject.object_id
+ recd.savedMedia = True
+
+ _saveXml( el, recd )
+
+ recd.mediaFilename = None
diff --git a/setup.py b/setup.py
index bcfaaa5..876cd3f 100755
--- a/setup.py
+++ b/setup.py
@@ -17,9 +17,6 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from sugar.activity import bundlebuilder
-import os
-
-os.system("make")
bundlebuilder.start()
diff --git a/ui.py b/ui.py
index d1a6726..73812d3 100644
--- a/ui.py
+++ b/ui.py
@@ -34,6 +34,9 @@ import time
import pango
import hippo
+import logging
+logger = logging.getLogger('record:ui.py')
+
#from sugar.graphics.toolcombobox import ToolComboBox
#from sugar.graphics.tray import HTray
from sugar.graphics.toolbutton import ToolButton
@@ -50,2314 +53,2349 @@ from p5_button import P5Button
from p5_button import Polygon
from p5_button import Button
from glive import LiveVideoWindow
-from glivex import SlowLiveVideoWindow
from gplay import PlayVideoWindow
from recorded import Recorded
from button import RecdButton
import utils
import record
-import _camera
+import camerac
+import aplay
from tray import HTray
from toolbarcombobox import ToolComboBox
class UI:
- dim_THUMB_WIDTH = 108
- dim_THUMB_HEIGHT = 81
- dim_INSET = 10
- dim_PIPW = 160
- dim_PIPH = 120 #pipBorder
- dim_PIP_BORDER = 4
- dim_PGDW = dim_PIPW + (dim_PIP_BORDER*2)
- dim_PGDH = dim_PIPH + (dim_PIP_BORDER*2)
- dim_CONTROLBAR_HT = 55
-
- def __init__( self, pca ):
- self.ca = pca
- self.ACTIVE = False
- self.LAUNCHING = True
- self.ca.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
- self.ca.connect("visibility-notify-event", self._visibleNotifyCb)
-
- self.inset = self.__class__.dim_INSET
- self.pgdh = self.__class__.dim_PGDH
- self.pgdw = self.__class__.dim_PGDW
- self.thumbTrayHt = 150 #todo: get sugar constant here
- self.thumbSvgW = 124
- self.thumbSvgH = 124
- self.maxw = 49
- self.maxh = 49
- self.controlBarHt = 60
- self.recordButtWd = 55
- self.pipw = self.__class__.dim_PIPW
- self.piph = self.__class__.dim_PIPH
-
- #ui modes
-
- # True when we're in full-screen mode, False otherwise
- self.FULLSCREEN = False
-
- # True when we're showing live video feed in the primary screen
- # area, False otherwise (even when we are still showing live video
- # in a p-i-p)
- self.LIVEMODE = True
-
- self.LAST_MODE = -1
- self.LAST_FULLSCREEN = False
- self.LAST_LIVE = True
- self.LAST_MESHING = False
- self.LAST_RECD_INFO = False
- self.LAST_TRANSCODING = False
- self.TRANSCODING = False
- self.MESHING = False
-
- # RECD_INFO_ON is True when the 'info' for a recording is being
- # display on-screen (who recorded it, tags, etc), and False otherwise.
- self.RECD_INFO_ON = False
-
- self.UPDATE_DURATION_ID = 0
- self.UPDATE_TIMER_ID = 0
- self.COUNTINGDOWN = False
-
- #init
- self.mapped = False
- self.centered = False
- self.setup = False
-
- #prep for when to show
- self.shownRecd = None
-
- #this includes the default sharing tab
- self.toolbox = activity.ActivityToolbox(self.ca)
- self.ca.set_toolbox(self.toolbox)
- self.photoToolbar = PhotoToolbar()
- self.photoToolbar.set_sensitive( False )
- self.toolbox.add_toolbar( Constants.istrPhoto, self.photoToolbar )
- self.videoToolbar = VideoToolbar()
- self.videoToolbar.set_sensitive( False )
- self.toolbox.add_toolbar( Constants.istrVideo, self.videoToolbar )
- self.audioToolbar = AudioToolbar()
- self.audioToolbar.set_sensitive( False )
- self.toolbox.add_toolbar( Constants.istrAudio, self.audioToolbar )
- self.tbars = {Constants.MODE_PHOTO:self.photoToolbar,Constants.MODE_VIDEO:self.videoToolbar,Constants.MODE_AUDIO:self.audioToolbar}
- self.toolbox.set_current_toolbar(self.ca.m.MODE+1)
-
- self.toolbox.remove(self.toolbox._separator)
- #taken directly from toolbox.py b/c I don't know how to mod the hongry hippo
- separator = hippo.Canvas()
- box = hippo.CanvasBox(
- border_color=Constants.colorBlack.get_int(),
- background_color=Constants.colorBlack.get_int(),
- box_height=style.TOOLBOX_SEPARATOR_HEIGHT,
- border_bottom=style.LINE_WIDTH)
- separator.set_root(box)
- self.toolbox.pack_start(separator, False)
- self.toolbox.separator = separator
-
- self.TOOLBOX_SIZE_ALLOCATE_ID = self.toolbox.connect_after("size-allocate", self._toolboxSizeAllocateCb)
- self.toolbox._notebook.set_property("can-focus", False)
- self.toolbox.connect("current-toolbar-changed", self._toolbarChangeCb)
- self.toolbox.show_all()
-
-
- def _toolboxSizeAllocateCb( self, widget, event ):
- self.toolbox.disconnect( self.TOOLBOX_SIZE_ALLOCATE_ID)
-
- toolboxHt = self.toolbox.size_request()[1]
- self.vh = gtk.gdk.screen_height()-(self.thumbTrayHt+toolboxHt+self.controlBarHt)
- self.vw = int(self.vh/.75)
- self.letterBoxW = (gtk.gdk.screen_width() - self.vw)/2
- self.letterBoxVW = (self.vw/2)-(self.inset*2)
- self.letterBoxVH = int(self.letterBoxVW*.75)
-
- self.setUpWindows()
-
- #now that we know how big the toolbox is, we can layout more
- gobject.idle_add( self.layout )
-
-
- def layout( self ):
- self.mainBox = gtk.VBox()
- self.ca.set_canvas(self.mainBox)
-
- topBox = gtk.HBox()
- self.mainBox.pack_start(topBox, expand=True)
-
- leftFill = gtk.VBox()
- leftFill.set_size_request( self.letterBoxW, -1 )
- self.leftFillBox = gtk.EventBox( )
- self.leftFillBox.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- leftFill.add( self.leftFillBox )
-
- topBox.pack_start( leftFill, expand=True )
-
- centerVBox = gtk.VBox()
- centerVBox.modify_bg(gtk.STATE_NORMAL, Constants.colorBlack.gColor)
- topBox.pack_start( centerVBox, expand=True )
- self.centerBox = gtk.EventBox()
- self.centerBox.set_size_request(self.vw, -1)
- self.centerBox.modify_bg(gtk.STATE_NORMAL, Constants.colorBlack.gColor)
- centerVBox.pack_start( self.centerBox, expand=True )
- centerSizer = gtk.VBox()
- centerSizer.set_size_request(self.vw, -1)
- centerSizer.modify_bg(gtk.STATE_NORMAL, Constants.colorBlack.gColor)
- self.centerBox.add(centerSizer)
-
- self.bottomCenter = gtk.EventBox()
- self.bottomCenter.modify_bg(gtk.STATE_NORMAL, Constants.colorBlack.gColor)
- self.bottomCenter.set_size_request(self.vw, self.controlBarHt)
- centerVBox.pack_start( self.bottomCenter, expand=False )
-
- #into the center box we can put this guy...
- self.backgdCanvasBox = gtk.VBox()
- self.backgdCanvasBox.modify_bg(gtk.STATE_NORMAL, Constants.colorBlack.gColor)
- self.backgdCanvasBox.set_size_request(self.vw, -1)
- self.backgdCanvas = PhotoCanvas()
- self.backgdCanvas.set_size_request(self.vw, self.vh)
- self.backgdCanvasBox.pack_start( self.backgdCanvas, expand=False )
-
- #or this guy...
- self.infoBox = gtk.EventBox()
- self.infoBox.modify_bg( gtk.STATE_NORMAL, Constants.colorButton.gColor )
- iinfoBox = gtk.VBox(spacing=self.inset)
- self.infoBox.add( iinfoBox )
- iinfoBox.set_size_request(self.vw, -1)
- iinfoBox.set_border_width(self.inset)
-
- rightFill = gtk.VBox()
- rightFill.set_size_request( self.letterBoxW, -1 )
- rightFillBox = gtk.EventBox()
- rightFillBox.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- rightFill.add( rightFillBox )
- topBox.pack_start( rightFill, expand=True )
-
- #info box innards:
- self.infoBoxTop = gtk.HBox()
- iinfoBox.pack_start( self.infoBoxTop, expand=True )
- self.infoBoxTopLeft = gtk.VBox(spacing=self.inset)
- self.infoBoxTop.pack_start( self.infoBoxTopLeft )
- self.infoBoxTopRight = gtk.VBox()
- self.infoBoxTopRight.set_size_request(self.letterBoxVW, -1)
- self.infoBoxTop.pack_start( self.infoBoxTopRight )
-
- self.namePanel = gtk.HBox()
- leftInfBalance = gtk.VBox()
- self.nameLabel = gtk.Label("<b><span foreground='white'>"+Constants.istrTitle+"</span></b>")
- self.nameLabel.set_use_markup( True )
- self.namePanel.pack_start( self.nameLabel, expand=False, padding=self.inset )
- self.nameLabel.set_alignment(0, .5)
- self.nameTextfield = gtk.Entry(140)
- self.nameTextfield.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
- self.nameTextfield.connect('changed', self._nameTextfieldEditedCb )
- self.nameTextfield.set_alignment(0)
- self.nameTextfield.set_size_request( -1, self.controlBarHt-(self.inset*2) )
- self.namePanel.pack_start(self.nameTextfield)
-
- self.photographerPanel = gtk.VBox(spacing=self.inset)
- self.infoBoxTopLeft.pack_start(self.photographerPanel, expand=False)
- photographerLabel = gtk.Label("<b>" + Constants.istrRecorder + "</b>")
- photographerLabel.set_use_markup( True )
- self.photographerPanel.pack_start(photographerLabel, expand=False)
- photographerLabel.set_alignment(0, .5)
- photoNamePanel = gtk.HBox(spacing=self.inset)
- self.photographerPanel.pack_start(photoNamePanel)
-
- self.photoXoPanel = xoPanel()
- photoNamePanel.pack_start( self.photoXoPanel, expand=False )
- self.photoXoPanel.set_size_request( 40, 40 )
-
- self.photographerNameLabel = gtk.Label("")
- self.photographerNameLabel.set_alignment(0, .5)
- photoNamePanel.pack_start(self.photographerNameLabel)
-
- self.datePanel = gtk.HBox(spacing=self.inset)
- self.infoBoxTopLeft.pack_start(self.datePanel, expand=False)
- dateLabel = gtk.Label("<b>"+Constants.istrDate+"</b>")
- dateLabel.set_use_markup(True)
- self.datePanel.pack_start(dateLabel, expand=False)
- self.dateDateLabel = gtk.Label("")
- self.dateDateLabel.set_alignment(0, .5)
- self.datePanel.pack_start(self.dateDateLabel)
-
- self.tagsPanel = gtk.VBox(spacing=self.inset)
- tagsLabel = gtk.Label("<b>"+Constants.istrTags+"</b>")
- tagsLabel.set_use_markup(True)
- tagsLabel.set_alignment(0, .5)
- self.tagsPanel.pack_start(tagsLabel, expand=False)
- self.tagsBuffer = gtk.TextBuffer()
- self.tagsBuffer.connect('changed', self._tagsBufferEditedCb)
- self.tagsField = gtk.TextView(self.tagsBuffer)
- self.tagsField.set_size_request( 100, 100 )
- self.tagsPanel.pack_start(self.tagsField, expand=True)
- self.infoBoxTopLeft.pack_start(self.tagsPanel, expand=True)
-
- infoBotBox = gtk.HBox()
- infoBotBox.set_size_request( -1, self.pgdh+self.inset )
- iinfoBox.pack_start(infoBotBox, expand=False)
-
- thumbnailsEventBox = gtk.EventBox()
- thumbnailsEventBox.set_size_request( -1, self.thumbTrayHt )
- thumbnailsBox = gtk.HBox( )
- thumbnailsEventBox.add( thumbnailsBox )
-
- self.thumbTray = HTray()
- self.thumbTray.set_size_request( -1, self.thumbTrayHt )
- self.mainBox.pack_end( self.thumbTray, expand=False )
- self.thumbTray.show()
-
- self.CENTER_SIZE_ALLOCATE_ID = self.centerBox.connect_after("size-allocate", self._centerSizeAllocateCb)
- self.ca.show_all()
-
-
- def _centerSizeAllocateCb( self, widget, event ):
- #initial setup of the panels
- self.centerBox.disconnect(self.CENTER_SIZE_ALLOCATE_ID)
- self.centerBoxPos = self.centerBox.translate_coordinates( self.ca, 0, 0 )
-
- centerKid = self.centerBox.get_child()
- if (centerKid != None):
- self.centerBox.remove( centerKid )
-
- self.centered = True
- self.setUp()
-
-
- def _mapEventCb( self, widget, event ):
- #when your parent window is ready, turn on the feed of live video
- self.liveVideoWindow.disconnect(self.MAP_EVENT_ID)
- self.mapped = True
- self.setUp()
-
-
- def setUp( self ):
- if (self.mapped and self.centered and not self.setup):
- self.setup = True
-
- #set correct window sizes
- self.setUpWindowsSizes()
-
- #listen for ctrl+c & game key buttons
- self.ca.connect('key-press-event', self._keyPressEventCb)
- #overlay widgets can go away after they've been on screen for a while
- self.HIDE_WIDGET_TIMEOUT_ID = 0
- self.hiddenWidgets = False
- self.resetWidgetFadeTimer()
- self.showLiveVideoTags()
-
- self.photoToolbar.set_sensitive( True )
- self.videoToolbar.set_sensitive( True )
- self.audioToolbar.set_sensitive( True )
-
- #initialize the app with the default thumbs
- self.ca.m.setupMode( self.ca.m.MODE, False )
-
- gobject.idle_add( self.finalSetUp )
-
-
- def finalSetUp( self ):
- self.LAUNCHING = False
- self.ACTIVE = self.ca.get_property( "visible" )
- self.updateVideoComponents()
-
- if (self.ACTIVE):
- self.ca.glive.play()
-
-
- def setUpWindows( self ):
- #image windows
- self.windowStack = []
-
- #live video windows
- self.livePhotoWindow = gtk.Window()
- self.livePhotoWindow.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.livePhotoWindow.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
- self.addToWindowStack( self.livePhotoWindow, self.ca )
- self.livePhotoCanvas = PhotoCanvas()
- self.livePhotoWindow.add(self.livePhotoCanvas)
- self.livePhotoWindow.connect("button_release_event", self._mediaClickedForPlayback)
- self.livePhotoWindow.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
- self.livePhotoWindow.connect("visibility-notify-event", self._visibleNotifyCb)
-
- #video playback windows
- self.playOggWindow = PlayVideoWindow(Constants.colorBlack.gColor)
- self.addToWindowStack( self.playOggWindow, self.windowStack[len(self.windowStack)-1] )
- #self.playOggWindow.set_gplay(self.ca.gplay)
- self.ca.gplay.window = self.playOggWindow
- self.playOggWindow.set_events(gtk.gdk.BUTTON_RELEASE_MASK)
- self.playOggWindow.connect("button_release_event", self._mediaClickedForPlayback)
- self.playOggWindow.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
- self.playOggWindow.connect("visibility-notify-event", self._visibleNotifyCb)
-
- #border behind
- self.pipBgdWindow = gtk.Window()
- self.pipBgdWindow.modify_bg( gtk.STATE_NORMAL, Constants.colorWhite.gColor )
- self.pipBgdWindow.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorWhite.gColor )
- self.addToWindowStack( self.pipBgdWindow, self.windowStack[len(self.windowStack)-1] )
-
- self.liveVideoWindow = LiveVideoWindow(Constants.colorBlack.gColor)
- self.addToWindowStack( self.liveVideoWindow, self.windowStack[len(self.windowStack)-1] )
- self.liveVideoWindow.set_glive(self.ca.glive)
- self.liveVideoWindow.set_events(gtk.gdk.BUTTON_RELEASE_MASK)
- self.liveVideoWindow.connect("button_release_event", self._liveButtonReleaseCb)
- self.liveVideoWindow.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
- self.liveVideoWindow.connect("visibility-notify-event", self._visibleNotifyCb)
-
- self.slowLiveVideoWindow = SlowLiveVideoWindow(Constants.colorBlack.gColor)
- self.addToWindowStack( self.slowLiveVideoWindow, self.windowStack[len(self.windowStack)-1] )
- self.slowLiveVideoWindow.set_glivex(self.ca.glivex)
- self.slowLiveVideoWindow.set_events(gtk.gdk.BUTTON_RELEASE_MASK)
- self.slowLiveVideoWindow.connect("button_release_event", self._returnButtonReleaseCb)
- self.slowLiveVideoWindow.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
- self.slowLiveVideoWindow.connect("visibility-notify-event", self._visibleNotifyCb)
-
- self.recordWindow = RecordWindow(self)
- self.addToWindowStack( self.recordWindow, self.windowStack[len(self.windowStack)-1] )
-
- self.progressWindow = ProgressWindow(self)
- self.addToWindowStack( self.progressWindow, self.windowStack[len(self.windowStack)-1] )
-
- self.maxWindow = gtk.Window()
- self.maxWindow.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.maxWindow.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
- maxButton = MaxButton(self)
- self.maxWindow.add( maxButton )
- self.addToWindowStack( self.maxWindow, self.windowStack[len(self.windowStack)-1] )
-
- self.scrubWindow = ScrubberWindow(self)
- self.addToWindowStack( self.scrubWindow, self.windowStack[len(self.windowStack)-1] )
-
- self.infWindow = gtk.Window()
- self.infWindow.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.infWindow.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
- infButton= InfButton(self)
- self.infWindow.add(infButton)
- self.addToWindowStack( self.infWindow, self.windowStack[len(self.windowStack)-1] )
-
- self.hideAllWindows()
- self.MAP_EVENT_ID = self.liveVideoWindow.connect_after("map-event", self._mapEventCb)
- for i in range (0, len(self.windowStack)):
-# self.windowStack[i].add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
-# self.windowStack[i].connect("visibility-notify-event", self._visibleNotifyCb)
- self.windowStack[i].show_all()
-
-
- def _visibleNotifyCb( self, widget, event ):
-
- if (self.LAUNCHING):
- return
-
- temp_ACTIVE = True
-
- if (event.state == gtk.gdk.VISIBILITY_FULLY_OBSCURED):
-
- if (not self.FULLSCREEN):
- if (widget == self.ca):
- temp_ACTIVE = False
-
- else:
- if (self.ca.m.MODE == Constants.MODE_PHOTO):
- if (not self.LIVEMODE and widget == self.livePhotoWindow):
- temp_ACTIVE = False
- if ( self.LIVEMODE and widget == self.liveVideoWindow):
- temp_ACTIVE = False
-
- if (self.ca.m.MODE == Constants.MODE_VIDEO):
- if (not self.LIVEMODE and widget == self.playOggWindow):
- temp_ACTIVE = False
- if ( self.LIVEMODE and widget == self.liveVideoWindow):
- temp_ACTIVE = False
-
-
- if (temp_ACTIVE != self.ACTIVE):
- self.ACTIVE = temp_ACTIVE
- if (self.ACTIVE):
- self.ca.restartPipes()
- else:
- self.ca.stopPipes()
-
-
- def setUpWindowsSizes( self ):
- pipDim = self.getPipDim(False)
- eyeDim = self.getEyeDim(False)
- imgDim = self.getImgDim( False )
- pgdDim = self.getPgdDim( False )
- maxDim = self.getMaxDim( False )
- prgDim = self.getPrgDim( False )
- infDim = self.getInfDim( False )
- self.livePhotoWindow.resize( imgDim[0], imgDim[1] )
- self.pipBgdWindow.resize( pgdDim[0], pgdDim[1] )
- self.liveVideoWindow.resize( imgDim[0], imgDim[1] )
- self.playOggWindow.resize( imgDim[0], imgDim[1] )
- self.recordWindow.resize( eyeDim[0], eyeDim[1] )
- self.maxWindow.resize( maxDim[0], maxDim[1] )
- self.progressWindow.resize( prgDim[0], prgDim[1] )
- self.infWindow.resize( infDim[0], infDim[1] )
-
-
- def _toolbarChangeCb( self, tbox, num ):
- if (num != 0) and (self.ca.m.RECORDING or self.ca.m.UPDATING):
- self.toolbox.set_current_toolbar( self.ca.m.MODE+1 )
- else:
- num = num - 1 #offset the default activity tab
- if (num == Constants.MODE_PHOTO) and (self.ca.m.MODE != Constants.MODE_PHOTO):
- self.ca.m.doPhotoMode()
- elif(num == Constants.MODE_VIDEO) and (self.ca.m.MODE != Constants.MODE_VIDEO):
- self.ca.m.doVideoMode()
- elif(num == Constants.MODE_AUDIO) and (self.ca.m.MODE != Constants.MODE_AUDIO):
- self.ca.m.doAudioMode()
-
-
- def addToWindowStack( self, win, parent ):
- self.windowStack.append( win )
- win.set_transient_for( parent )
- win.set_type_hint( gtk.gdk.WINDOW_TYPE_HINT_DIALOG )
- win.set_decorated( False )
- win.set_focus_on_map( False )
- win.set_property("accept-focus", False)
-
-
- def resetWidgetFadeTimer( self ):
- #only show the clutter when the mouse moves
- self.mx = -1
- self.my = -1
- self.hideWidgetsTimer = time.time()
- if (self.hiddenWidgets):
- self.showWidgets()
- self.hiddenWidgets = False
-
- #remove, then add
- self.doMouseListener( False )
- if (self.HIDE_WIDGET_TIMEOUT_ID != 0):
- gobject.source_remove( self.HIDE_WIDGET_TIMEOUT_ID)
-
- self.HIDE_WIDGET_TIMEOUT_ID = gobject.timeout_add( 500, self._mouseMightaMovedCb )
-
-
- def doMouseListener( self, listen ):
- if (listen):
- self.resetWidgetFadeTimer()
- else:
- if (self.HIDE_WIDGET_TIMEOUT_ID != None):
- if (self.HIDE_WIDGET_TIMEOUT_ID != 0):
- gobject.source_remove( self.HIDE_WIDGET_TIMEOUT_ID )
-
-
- def hideWidgets( self ):
- self.moveWinOffscreen( self.maxWindow )
- self.moveWinOffscreen( self.pipBgdWindow )
- self.moveWinOffscreen( self.infWindow )
- self.moveWinOffscreen( self.slowLiveVideoWindow )
-
- if (self.FULLSCREEN):
- self.moveWinOffscreen( self.recordWindow )
- self.moveWinOffscreen( self.progressWindow )
- self.moveWinOffscreen( self.scrubWindow )
-
- if (self.ca.m.MODE == Constants.MODE_PHOTO):
- if (not self.LIVEMODE):
- self.moveWinOffscreen( self.liveVideoWindow )
- elif (self.ca.m.MODE == Constants.MODE_VIDEO):
- if (not self.LIVEMODE):
- self.moveWinOffscreen( self.liveVideoWindow )
- elif (self.ca.m.MODE == Constants.MODE_AUDIO):
- if (not self.LIVEMODE):
- self.moveWinOffscreen( self.liveVideoWindow )
- self.LAST_MODE = -1
-
-
- def _mouseMightaMovedCb( self ):
- x, y = self.ca.get_pointer()
- passedTime = 0
-
- if (x != self.mx or y != self.my):
- self.hideWidgetsTimer = time.time()
- if (self.hiddenWidgets):
- self.showWidgets()
- self.hiddenWidgets = False
- else:
- passedTime = time.time() - self.hideWidgetsTimer
-
- if (self.ca.m.RECORDING):
- self.hideWidgetsTimer = time.time()
- passedTime = 0
-
- if (passedTime >= 3):
- if (not self.hiddenWidgets):
- if (self.mouseInWidget(x,y)):
- self.hideWidgetsTimer = time.time()
- elif (self.RECD_INFO_ON):
- self.hideWidgetsTimer = time.time()
- elif (self.UPDATE_TIMER_ID != 0):
- self.hideWidgetsTimer = time.time()
- else:
- self.hideWidgets()
- self.hiddenWidgets = True
-
- self.mx = x
- self.my = y
- return True
-
-
- def mouseInWidget( self, mx, my ):
- if (self.ca.m.MODE != Constants.MODE_AUDIO):
- if (self.inWidget( mx, my, self.getLoc("max", self.FULLSCREEN), self.getDim("max", self.FULLSCREEN))):
- return True
-
- if (not self.LIVEMODE):
- if (self.inWidget( mx, my, self.getLoc("pgd", self.FULLSCREEN), self.getDim("pgd", self.FULLSCREEN))):
- return True
-
- if (self.inWidget( mx, my, self.getLoc("inb", self.FULLSCREEN), self.getDim("inb", self.FULLSCREEN))):
- return True
-
- if (self.inWidget( mx, my, self.getLoc("prg", self.FULLSCREEN), self.getDim("prg", self.FULLSCREEN))):
- return True
-
- if (self.inWidget( mx, my, self.getLoc("inf", self.FULLSCREEN), self.getDim("inf", self.FULLSCREEN))):
- return True
-
- if (self.LIVEMODE):
- if (self.inWidget( mx, my, self.getLoc("eye", self.FULLSCREEN), self.getDim("eye", self.FULLSCREEN))):
- return True
-
- return False
-
-
- def _mediaClickedForPlayback(self, widget, event):
- if (not self.LIVEMODE):
- if (self.shownRecd != None):
- if (self.ca.m.MODE != Constants.MODE_PHOTO):
- self.showThumbSelection( self.shownRecd )
-
-
- def inWidget( self, mx, my, loc, dim ):
- if ( (mx > loc[0]) and (my > loc[1]) ):
- if ( (mx < loc[0]+dim[0]) and (my < loc[1]+dim[1]) ):
- return True
-
-
- def _nameTextfieldEditedCb(self, widget):
- if (self.shownRecd != None):
- if (self.nameTextfield.get_text() != self.shownRecd.title):
- self.shownRecd.setTitle( self.nameTextfield.get_text() )
-
-
- def _tagsBufferEditedCb(self, widget):
- if (self.shownRecd != None):
- txt = self.tagsBuffer.get_text( self.tagsBuffer.get_start_iter(), self.tagsBuffer.get_end_iter() )
- if (txt != self.shownRecd.tags):
- self.shownRecd.setTags( txt )
-
-
- def _keyPressEventCb( self, widget, event):
- #todo: trac #4144
-
- self.resetWidgetFadeTimer()
-
- #we listen here for CTRL+C events and game keys, and pass on events to gtk.Entry fields
- keyname = gtk.gdk.keyval_name(event.keyval)
-
- if (keyname == 'KP_Page_Up'): #O, up
- if (self.LIVEMODE):
- if (not self.ca.m.UPDATING):
- self.doShutter()
- else:
- if (self.COUNTINGDOWN):
- self.doShutter()
- else:
- if (self.ca.m.MODE == Constants.MODE_PHOTO):
- self.resumeLiveVideo()
- else:
- self.resumePlayLiveVideo()
- elif (keyname == 'KP_Page_Down'): #x, down
- if (not self.ca.m.UPDATING and not self.ca.m.RECORDING):
- self.ca.m.showLastThumb()
- elif (keyname == 'KP_Home'): #square, left
- if (not self.ca.m.UPDATING and not self.ca.m.RECORDING and not self.LIVEMODE):
- self.ca.m.showPrevThumb( self.shownRecd )
- elif (keyname == 'KP_End'): #check, right
- if (not self.ca.m.UPDATING and not self.ca.m.RECORDING and not self.LIVEMODE):
- self.ca.m.showNextThumb( self.shownRecd )
- elif (keyname == 'c' and event.state == gtk.gdk.CONTROL_MASK):
- if (self.shownRecd != None):
- self.copyToClipboard( self.shownRecd )
- elif (keyname == 'Escape'):
- if (self.FULLSCREEN):
- self.FULLSCREEN = False
- if (self.RECD_INFO_ON):
- self.infoButtonClicked()
- else:
- self.updateVideoComponents()
- elif (keyname == 'i' and event.state == gtk.gdk.CONTROL_MASK):
- if (not self.LIVEMODE):
- self.infoButtonClicked()
-
- return False
-
-
- def copyToClipboard( self, recd ):
- if (recd.isClipboardCopyable( )):
- tmpImgPath = self.doClipboardCopyStart( recd )
- gtk.Clipboard().set_with_data( [('text/uri-list', 0, 0)], self._clipboardGetFuncCb, self._clipboardClearFuncCb, tmpImgPath )
- return True
+ dim_THUMB_WIDTH = 108
+ dim_THUMB_HEIGHT = 81
+ dim_INSET = 10
+ dim_PIPW = 160
+ dim_PIPH = 120 #pipBorder
+ dim_PIP_BORDER = 4
+ dim_PGDW = dim_PIPW + (dim_PIP_BORDER*2)
+ dim_PGDH = dim_PIPH + (dim_PIP_BORDER*2)
+ dim_CONTROLBAR_HT = 55
+
+ def __init__( self, pca ):
+ self.ca = pca
+ self.ACTIVE = False
+ self.LAUNCHING = True
+ self.ca.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
+ self.ca.connect("visibility-notify-event", self._visibleNotifyCb)
+
+ self.inset = self.__class__.dim_INSET
+ self.pgdh = self.__class__.dim_PGDH
+ self.pgdw = self.__class__.dim_PGDW
+ self.thumbTrayHt = 150 #todo: get sugar constant here
+ self.thumbSvgW = 124
+ self.thumbSvgH = 124
+ self.maxw = 49
+ self.maxh = 49
+ self.controlBarHt = 60
+ self.recordButtWd = 55
+ self.pipw = self.__class__.dim_PIPW
+ self.piph = self.__class__.dim_PIPH
+
+ #ui modes
+
+ # True when we're in full-screen mode, False otherwise
+ self.FULLSCREEN = False
+
+ # True when we're showing live video feed in the primary screen
+ # area, False otherwise (even when we are still showing live video
+ # in a p-i-p)
+ self.LIVEMODE = True
+
+ self.LAST_MODE = -1
+ self.LAST_FULLSCREEN = False
+ self.LAST_LIVE = True
+ self.LAST_MESHING = False
+ self.LAST_RECD_INFO = False
+ self.LAST_TRANSCODING = False
+ self.TRANSCODING = False
+ self.MESHING = False
+
+ # RECD_INFO_ON is True when the 'info' for a recording is being
+ # display on-screen (who recorded it, tags, etc), and False otherwise.
+ self.RECD_INFO_ON = False
+
+ self.UPDATE_DURATION_ID = 0
+ self.UPDATE_TIMER_ID = 0
+ self.COUNTINGDOWN = False
+
+ #init
+ self.mapped = False
+ self.centered = False
+ self.setup = False
+
+ #prep for when to show
+ self.shownRecd = None
+
+ #this includes the default sharing tab
+ self.toolbox = activity.ActivityToolbox(self.ca)
+ self.ca.set_toolbox(self.toolbox)
+ self.photoToolbar = PhotoToolbar()
+ self.photoToolbar.set_sensitive( False )
+ self.toolbox.add_toolbar( Constants.istrPhoto, self.photoToolbar )
+ self.videoToolbar = VideoToolbar()
+ self.videoToolbar.set_sensitive( False )
+ self.toolbox.add_toolbar( Constants.istrVideo, self.videoToolbar )
+ self.audioToolbar = AudioToolbar()
+ self.audioToolbar.set_sensitive( False )
+ self.toolbox.add_toolbar( Constants.istrAudio, self.audioToolbar )
+ self.tbars = {Constants.MODE_PHOTO:self.photoToolbar,Constants.MODE_VIDEO:self.videoToolbar,Constants.MODE_AUDIO:self.audioToolbar}
+ self.toolbox.set_current_toolbar(self.ca.m.MODE+1)
+
+ self.toolbox.remove(self.toolbox._separator)
+ #taken directly from toolbox.py b/c I don't know how to mod the hongry hippo
+ separator = hippo.Canvas()
+ box = hippo.CanvasBox(
+ border_color=Constants.colorBlack.get_int(),
+ background_color=Constants.colorBlack.get_int(),
+ box_height=style.TOOLBOX_SEPARATOR_HEIGHT,
+ border_bottom=style.LINE_WIDTH)
+ separator.set_root(box)
+ self.toolbox.pack_start(separator, False)
+ self.toolbox.separator = separator
+
+ self.TOOLBOX_SIZE_ALLOCATE_ID = self.toolbox.connect_after("size-allocate", self._toolboxSizeAllocateCb)
+ self.toolbox._notebook.set_property("can-focus", False)
+ self.toolbox.connect("current-toolbar-changed", self._toolbarChangeCb)
+ self.toolbox.show_all()
+
+ def serialize(self):
+ data = {}
+ data['photo_timer'] = self.photoToolbar.timerCb.combo.get_active()
+ data['video_timer'] = self.videoToolbar.timerCb.combo.get_active()
+ data['video_duration'] = self.videoToolbar.durCb.combo.get_active()
+ data['video_quality'] = self.videoToolbar.quality.combo.get_active()
+ data['audio_timer'] = self.audioToolbar.timerCb.combo.get_active()
+ data['audio_duration'] = self.audioToolbar.durCb.combo.get_active()
+ return data
+
+ def deserialize(self, data):
+ self.photoToolbar.timerCb.combo.set_active(data.get('photo_timer', 0))
+ self.videoToolbar.timerCb.combo.set_active(data.get('video_timer', 0))
+ self.videoToolbar.durCb.combo.set_active(data.get('video_duration', 0))
+ self.videoToolbar.quality.combo.set_active(data.get('video_quality', 0))
+ self.audioToolbar.timerCb.combo.set_active(data.get('audio_timer', 0))
+ self.audioToolbar.durCb.combo.set_active(data.get('audio_duration'))
+
+ def _toolboxSizeAllocateCb( self, widget, event ):
+ self.toolbox.disconnect( self.TOOLBOX_SIZE_ALLOCATE_ID)
+
+ toolboxHt = self.toolbox.size_request()[1]
+ self.vh = gtk.gdk.screen_height()-(self.thumbTrayHt+toolboxHt+self.controlBarHt)
+ self.vw = int(self.vh/.75)
+ self.letterBoxW = (gtk.gdk.screen_width() - self.vw)/2
+ self.letterBoxVW = (self.vw/2)-(self.inset*2)
+ self.letterBoxVH = int(self.letterBoxVW*.75)
+
+ self.setUpWindows()
+
+ #now that we know how big the toolbox is, we can layout more
+ gobject.idle_add( self.layout )
+
+
+ def layout( self ):
+ self.mainBox = gtk.VBox()
+ self.ca.set_canvas(self.mainBox)
+
+ topBox = gtk.HBox()
+ self.mainBox.pack_start(topBox, expand=True)
+
+ leftFill = gtk.VBox()
+ leftFill.set_size_request( self.letterBoxW, -1 )
+ self.leftFillBox = gtk.EventBox( )
+ self.leftFillBox.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ leftFill.add( self.leftFillBox )
+
+ topBox.pack_start( leftFill, expand=True )
+
+ centerVBox = gtk.VBox()
+ centerVBox.modify_bg(gtk.STATE_NORMAL, Constants.colorBlack.gColor)
+ topBox.pack_start( centerVBox, expand=True )
+ self.centerBox = gtk.EventBox()
+ self.centerBox.set_size_request(self.vw, -1)
+ self.centerBox.modify_bg(gtk.STATE_NORMAL, Constants.colorBlack.gColor)
+ centerVBox.pack_start( self.centerBox, expand=True )
+ centerSizer = gtk.VBox()
+ centerSizer.set_size_request(self.vw, -1)
+ centerSizer.modify_bg(gtk.STATE_NORMAL, Constants.colorBlack.gColor)
+ self.centerBox.add(centerSizer)
+
+ self.bottomCenter = gtk.EventBox()
+ self.bottomCenter.modify_bg(gtk.STATE_NORMAL, Constants.colorBlack.gColor)
+ self.bottomCenter.set_size_request(self.vw, self.controlBarHt)
+ centerVBox.pack_start( self.bottomCenter, expand=False )
+
+ #into the center box we can put this guy...
+ self.backgdCanvasBox = gtk.VBox()
+ self.backgdCanvasBox.modify_bg(gtk.STATE_NORMAL, Constants.colorBlack.gColor)
+ self.backgdCanvasBox.set_size_request(self.vw, -1)
+ self.backgdCanvas = PhotoCanvas()
+ self.backgdCanvas.set_size_request(self.vw, self.vh)
+ self.backgdCanvasBox.pack_start( self.backgdCanvas, expand=False )
+
+ #or this guy...
+ self.infoBox = gtk.EventBox()
+ self.infoBox.modify_bg( gtk.STATE_NORMAL, Constants.colorButton.gColor )
+ iinfoBox = gtk.VBox(spacing=self.inset)
+ self.infoBox.add( iinfoBox )
+ iinfoBox.set_size_request(self.vw, -1)
+ iinfoBox.set_border_width(self.inset)
+
+ rightFill = gtk.VBox()
+ rightFill.set_size_request( self.letterBoxW, -1 )
+ rightFillBox = gtk.EventBox()
+ rightFillBox.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ rightFill.add( rightFillBox )
+ topBox.pack_start( rightFill, expand=True )
+
+ #info box innards:
+ self.infoBoxTop = gtk.HBox()
+ iinfoBox.pack_start( self.infoBoxTop, expand=True )
+ self.infoBoxTopLeft = gtk.VBox(spacing=self.inset)
+ self.infoBoxTop.pack_start( self.infoBoxTopLeft )
+ self.infoBoxTopRight = gtk.VBox()
+ self.infoBoxTopRight.set_size_request(self.letterBoxVW, -1)
+ self.infoBoxTop.pack_start( self.infoBoxTopRight )
+
+ self.namePanel = gtk.HBox()
+ leftInfBalance = gtk.VBox()
+ self.nameLabel = gtk.Label("<b><span foreground='white'>"+Constants.istrTitle+"</span></b>")
+ self.nameLabel.set_use_markup( True )
+ self.namePanel.pack_start( self.nameLabel, expand=False, padding=self.inset )
+ self.nameLabel.set_alignment(0, .5)
+ self.nameTextfield = gtk.Entry(140)
+ self.nameTextfield.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
+ self.nameTextfield.connect('changed', self._nameTextfieldEditedCb )
+ self.nameTextfield.set_alignment(0)
+ self.nameTextfield.set_size_request( -1, self.controlBarHt-(self.inset*2) )
+ self.namePanel.pack_start(self.nameTextfield)
+
+ self.photographerPanel = gtk.VBox(spacing=self.inset)
+ self.infoBoxTopLeft.pack_start(self.photographerPanel, expand=False)
+ photographerLabel = gtk.Label("<b>" + Constants.istrRecorder + "</b>")
+ photographerLabel.set_use_markup( True )
+ self.photographerPanel.pack_start(photographerLabel, expand=False)
+ photographerLabel.set_alignment(0, .5)
+ photoNamePanel = gtk.HBox(spacing=self.inset)
+ self.photographerPanel.pack_start(photoNamePanel)
+
+ self.photoXoPanel = xoPanel()
+ photoNamePanel.pack_start( self.photoXoPanel, expand=False )
+ self.photoXoPanel.set_size_request( 40, 40 )
+
+ self.photographerNameLabel = gtk.Label("")
+ self.photographerNameLabel.set_alignment(0, .5)
+ photoNamePanel.pack_start(self.photographerNameLabel)
+
+ self.datePanel = gtk.HBox(spacing=self.inset)
+ self.infoBoxTopLeft.pack_start(self.datePanel, expand=False)
+ dateLabel = gtk.Label("<b>"+Constants.istrDate+"</b>")
+ dateLabel.set_use_markup(True)
+ self.datePanel.pack_start(dateLabel, expand=False)
+ self.dateDateLabel = gtk.Label("")
+ self.dateDateLabel.set_alignment(0, .5)
+ self.datePanel.pack_start(self.dateDateLabel)
+
+ self.tagsPanel = gtk.VBox(spacing=self.inset)
+ tagsLabel = gtk.Label("<b>"+Constants.istrTags+"</b>")
+ tagsLabel.set_use_markup(True)
+ tagsLabel.set_alignment(0, .5)
+ self.tagsPanel.pack_start(tagsLabel, expand=False)
+ self.tagsBuffer = gtk.TextBuffer()
+ self.tagsBuffer.connect('changed', self._tagsBufferEditedCb)
+ self.tagsField = gtk.TextView(self.tagsBuffer)
+ self.tagsField.set_size_request( 100, 100 )
+ self.tagsPanel.pack_start(self.tagsField, expand=True)
+ self.infoBoxTopLeft.pack_start(self.tagsPanel, expand=True)
+
+ infoBotBox = gtk.HBox()
+ infoBotBox.set_size_request( -1, self.pgdh+self.inset )
+ iinfoBox.pack_start(infoBotBox, expand=False)
+
+ thumbnailsEventBox = gtk.EventBox()
+ thumbnailsEventBox.set_size_request( -1, self.thumbTrayHt )
+ thumbnailsBox = gtk.HBox( )
+ thumbnailsEventBox.add( thumbnailsBox )
+
+ self.thumbTray = HTray()
+ self.thumbTray.set_size_request( -1, self.thumbTrayHt )
+ self.mainBox.pack_end( self.thumbTray, expand=False )
+ self.thumbTray.show()
+
+ self.CENTER_SIZE_ALLOCATE_ID = self.centerBox.connect_after("size-allocate", self._centerSizeAllocateCb)
+ self.ca.show_all()
+
+
+ def _centerSizeAllocateCb( self, widget, event ):
+ #initial setup of the panels
+ self.centerBox.disconnect(self.CENTER_SIZE_ALLOCATE_ID)
+ self.centerBoxPos = self.centerBox.translate_coordinates( self.ca, 0, 0 )
+
+ centerKid = self.centerBox.get_child()
+ if (centerKid != None):
+ self.centerBox.remove( centerKid )
+
+ self.centered = True
+ self.setUp()
+
+
+ def _mapEventCb( self, widget, event ):
+ #when your parent window is ready, turn on the feed of live video
+ self.liveVideoWindow.disconnect(self.MAP_EVENT_ID)
+ self.mapped = True
+ self.setUp()
+
+
+ def setUp( self ):
+ if (self.mapped and self.centered and not self.setup):
+ self.setup = True
+
+ #set correct window sizes
+ self.setUpWindowsSizes()
+
+ #listen for ctrl+c & game key buttons
+ self.ca.connect('key-press-event', self._keyPressEventCb)
+ #overlay widgets can go away after they've been on screen for a while
+ self.HIDE_WIDGET_TIMEOUT_ID = 0
+ self.hiddenWidgets = False
+ self.resetWidgetFadeTimer()
+ self.showLiveVideoTags()
+
+ self.photoToolbar.set_sensitive( True )
+ self.videoToolbar.set_sensitive( True )
+ self.audioToolbar.set_sensitive( True )
+
+ #initialize the app with the default thumbs
+ self.ca.m.setupMode( self.ca.m.MODE, True )
+
+ gobject.idle_add( self.finalSetUp )
+
+
+ def finalSetUp( self ):
+ self.LAUNCHING = False
+ self.ACTIVE = self.ca.get_property( "visible" )
+ self.updateVideoComponents()
+
+ if (self.ACTIVE):
+ self.ca.glive.play()
+
+
+ def setUpWindows( self ):
+ #image windows
+ self.windowStack = []
+
+ #live video windows
+ self.livePhotoWindow = gtk.Window()
+ self.livePhotoWindow.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.livePhotoWindow.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
+ self.addToWindowStack( self.livePhotoWindow, self.ca )
+ self.livePhotoCanvas = PhotoCanvas()
+ self.livePhotoWindow.add(self.livePhotoCanvas)
+ self.livePhotoWindow.connect("button_release_event", self._mediaClickedForPlayback)
+ self.livePhotoWindow.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
+ self.livePhotoWindow.connect("visibility-notify-event", self._visibleNotifyCb)
+
+ #video playback windows
+ self.playOggWindow = PlayVideoWindow(Constants.colorBlack.gColor)
+ self.addToWindowStack( self.playOggWindow, self.windowStack[len(self.windowStack)-1] )
+ #self.playOggWindow.set_gplay(self.ca.gplay)
+ self.ca.gplay.window = self.playOggWindow
+ self.playOggWindow.set_events(gtk.gdk.BUTTON_RELEASE_MASK)
+ self.playOggWindow.connect("button_release_event", self._mediaClickedForPlayback)
+ self.playOggWindow.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
+ self.playOggWindow.connect("visibility-notify-event", self._visibleNotifyCb)
+
+ #border behind
+ self.pipBgdWindow = gtk.Window()
+ self.pipBgdWindow.modify_bg( gtk.STATE_NORMAL, Constants.colorWhite.gColor )
+ self.pipBgdWindow.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorWhite.gColor )
+ self.addToWindowStack( self.pipBgdWindow, self.windowStack[len(self.windowStack)-1] )
+
+ self.liveVideoWindow = LiveVideoWindow(Constants.colorBlack.gColor)
+ self.addToWindowStack( self.liveVideoWindow, self.windowStack[len(self.windowStack)-1] )
+ self.liveVideoWindow.set_glive(self.ca.glive)
+ self.liveVideoWindow.set_events(gtk.gdk.BUTTON_RELEASE_MASK)
+ self.liveVideoWindow.connect("button_release_event", self._liveButtonReleaseCb)
+ self.liveVideoWindow.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
+ self.liveVideoWindow.connect("visibility-notify-event", self._visibleNotifyCb)
+
+ self.recordWindow = RecordWindow(self)
+ self.addToWindowStack( self.recordWindow, self.windowStack[len(self.windowStack)-1] )
+
+ self.progressWindow = ProgressWindow(self)
+ self.addToWindowStack( self.progressWindow, self.windowStack[len(self.windowStack)-1] )
+
+ self.maxWindow = gtk.Window()
+ self.maxWindow.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.maxWindow.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
+ maxButton = MaxButton(self)
+ self.maxWindow.add( maxButton )
+ self.addToWindowStack( self.maxWindow, self.windowStack[len(self.windowStack)-1] )
+
+ self.scrubWindow = ScrubberWindow(self)
+ self.addToWindowStack( self.scrubWindow, self.windowStack[len(self.windowStack)-1] )
+
+ self.infWindow = gtk.Window()
+ self.infWindow.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.infWindow.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
+ infButton= InfButton(self)
+ self.infWindow.add(infButton)
+ self.addToWindowStack( self.infWindow, self.windowStack[len(self.windowStack)-1] )
+
+ self.hideAllWindows()
+ self.MAP_EVENT_ID = self.liveVideoWindow.connect_after("map-event", self._mapEventCb)
+ for i in range (0, len(self.windowStack)):
+# self.windowStack[i].add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
+# self.windowStack[i].connect("visibility-notify-event", self._visibleNotifyCb)
+ self.windowStack[i].show_all()
+
+
+ def _visibleNotifyCb( self, widget, event ):
+
+ if (self.LAUNCHING):
+ return
+
+ temp_ACTIVE = True
+
+ if (event.state == gtk.gdk.VISIBILITY_FULLY_OBSCURED):
+
+ if (not self.FULLSCREEN):
+ if (widget == self.ca):
+ temp_ACTIVE = False
+
+ else:
+ if (self.ca.m.MODE == Constants.MODE_PHOTO):
+ if (not self.LIVEMODE and widget == self.livePhotoWindow):
+ temp_ACTIVE = False
+ if ( self.LIVEMODE and widget == self.liveVideoWindow):
+ temp_ACTIVE = False
+
+ if (self.ca.m.MODE == Constants.MODE_VIDEO):
+ if (not self.LIVEMODE and widget == self.playOggWindow):
+ temp_ACTIVE = False
+ if ( self.LIVEMODE and widget == self.liveVideoWindow):
+ temp_ACTIVE = False
+
+
+ if (temp_ACTIVE != self.ACTIVE):
+ self.ACTIVE = temp_ACTIVE
+ if (self.ACTIVE):
+ self.ca.restartPipes()
+ else:
+ self.ca.stopPipes()
+
+
+ def setUpWindowsSizes( self ):
+ pipDim = self.getPipDim(False)
+ eyeDim = self.getEyeDim(False)
+ imgDim = self.getImgDim( False )
+ pgdDim = self.getPgdDim( False )
+ maxDim = self.getMaxDim( False )
+ prgDim = self.getPrgDim( False )
+ infDim = self.getInfDim( False )
+ self.livePhotoWindow.resize( imgDim[0], imgDim[1] )
+ self.pipBgdWindow.resize( pgdDim[0], pgdDim[1] )
+ self.liveVideoWindow.resize( imgDim[0], imgDim[1] )
+ self.playOggWindow.resize( imgDim[0], imgDim[1] )
+ self.recordWindow.resize( eyeDim[0], eyeDim[1] )
+ self.maxWindow.resize( maxDim[0], maxDim[1] )
+ self.progressWindow.resize( prgDim[0], prgDim[1] )
+ self.infWindow.resize( infDim[0], infDim[1] )
+
+
+ def _toolbarChangeCb( self, tbox, num ):
+ if (num != 0) and (self.ca.m.RECORDING or self.ca.m.UPDATING):
+ self.toolbox.set_current_toolbar( self.ca.m.MODE+1 )
+ else:
+ num = num - 1 #offset the default activity tab
+ if (num == Constants.MODE_PHOTO) and (self.ca.m.MODE != Constants.MODE_PHOTO):
+ self.ca.m.doPhotoMode()
+ elif(num == Constants.MODE_VIDEO) and (self.ca.m.MODE != Constants.MODE_VIDEO):
+ self.ca.m.doVideoMode()
+ elif(num == Constants.MODE_AUDIO) and (self.ca.m.MODE != Constants.MODE_AUDIO):
+ self.ca.m.doAudioMode()
+
+
+ def addToWindowStack( self, win, parent ):
+ self.windowStack.append( win )
+ win.set_transient_for( parent )
+ win.set_type_hint( gtk.gdk.WINDOW_TYPE_HINT_DIALOG )
+ win.set_decorated( False )
+ win.set_focus_on_map( False )
+ win.set_property("accept-focus", False)
+ win.props.destroy_with_parent = True
+
+
+ def resetWidgetFadeTimer( self ):
+ #only show the clutter when the mouse moves
+ self.mx = -1
+ self.my = -1
+ self.hideWidgetsTimer = time.time()
+ if (self.hiddenWidgets):
+ self.showWidgets()
+ self.hiddenWidgets = False
+
+ #remove, then add
+ self.doMouseListener( False )
+ if (self.HIDE_WIDGET_TIMEOUT_ID != 0):
+ gobject.source_remove( self.HIDE_WIDGET_TIMEOUT_ID)
+
+ self.HIDE_WIDGET_TIMEOUT_ID = gobject.timeout_add( 500, self._mouseMightaMovedCb )
+
+
+ def doMouseListener( self, listen ):
+ if (listen):
+ self.resetWidgetFadeTimer()
+ else:
+ if (self.HIDE_WIDGET_TIMEOUT_ID != None):
+ if (self.HIDE_WIDGET_TIMEOUT_ID != 0):
+ gobject.source_remove( self.HIDE_WIDGET_TIMEOUT_ID )
+
+
+ def hideWidgets( self ):
+ self.moveWinOffscreen( self.maxWindow )
+ self.moveWinOffscreen( self.pipBgdWindow )
+ self.moveWinOffscreen( self.infWindow )
+
+ if (self.FULLSCREEN):
+ self.moveWinOffscreen( self.recordWindow )
+ self.moveWinOffscreen( self.progressWindow )
+ self.moveWinOffscreen( self.scrubWindow )
+
+ if (self.ca.m.MODE == Constants.MODE_PHOTO):
+ if (not self.LIVEMODE):
+ self.moveWinOffscreen( self.liveVideoWindow )
+ elif (self.ca.m.MODE == Constants.MODE_VIDEO):
+ if (not self.LIVEMODE):
+ self.moveWinOffscreen( self.liveVideoWindow )
+ elif (self.ca.m.MODE == Constants.MODE_AUDIO):
+ if (not self.LIVEMODE):
+ self.moveWinOffscreen( self.liveVideoWindow )
+ self.LAST_MODE = -1
+
+
+ def _mouseMightaMovedCb( self ):
+ x, y = self.ca.get_pointer()
+ passedTime = 0
+
+ if (x != self.mx or y != self.my):
+ self.hideWidgetsTimer = time.time()
+ if (self.hiddenWidgets):
+ self.showWidgets()
+ self.hiddenWidgets = False
+ else:
+ passedTime = time.time() - self.hideWidgetsTimer
+
+ if (self.ca.m.RECORDING):
+ self.hideWidgetsTimer = time.time()
+ passedTime = 0
+
+ if (passedTime >= 3):
+ if (not self.hiddenWidgets):
+ if (self.mouseInWidget(x,y)):
+ self.hideWidgetsTimer = time.time()
+ elif (self.RECD_INFO_ON):
+ self.hideWidgetsTimer = time.time()
+ elif (self.UPDATE_TIMER_ID != 0):
+ self.hideWidgetsTimer = time.time()
+ else:
+ self.hideWidgets()
+ self.hiddenWidgets = True
+
+ self.mx = x
+ self.my = y
+ return True
+
+
+ def mouseInWidget( self, mx, my ):
+ if (self.ca.m.MODE != Constants.MODE_AUDIO):
+ if (self.inWidget( mx, my, self.getLoc("max", self.FULLSCREEN), self.getDim("max", self.FULLSCREEN))):
+ return True
+
+ if (not self.LIVEMODE):
+ if (self.inWidget( mx, my, self.getLoc("pgd", self.FULLSCREEN), self.getDim("pgd", self.FULLSCREEN))):
+ return True
+
+ if (self.inWidget( mx, my, self.getLoc("inb", self.FULLSCREEN), self.getDim("inb", self.FULLSCREEN))):
+ return True
+
+ if (self.inWidget( mx, my, self.getLoc("prg", self.FULLSCREEN), self.getDim("prg", self.FULLSCREEN))):
+ return True
+
+ if (self.inWidget( mx, my, self.getLoc("inf", self.FULLSCREEN), self.getDim("inf", self.FULLSCREEN))):
+ return True
+
+ if (self.LIVEMODE):
+ if (self.inWidget( mx, my, self.getLoc("eye", self.FULLSCREEN), self.getDim("eye", self.FULLSCREEN))):
+ return True
+
+ return False
+
+
+ def _mediaClickedForPlayback(self, widget, event):
+ if (not self.LIVEMODE):
+ if (self.shownRecd != None):
+ if (self.ca.m.MODE != Constants.MODE_PHOTO):
+ self.showThumbSelection( self.shownRecd )
+
+
+ def inWidget( self, mx, my, loc, dim ):
+ if ( (mx > loc[0]) and (my > loc[1]) ):
+ if ( (mx < loc[0]+dim[0]) and (my < loc[1]+dim[1]) ):
+ return True
+
+
+ def _nameTextfieldEditedCb(self, widget):
+ if (self.shownRecd != None):
+ if (self.nameTextfield.get_text() != self.shownRecd.title):
+ self.shownRecd.setTitle( self.nameTextfield.get_text() )
+
+
+ def _tagsBufferEditedCb(self, widget):
+ if (self.shownRecd != None):
+ txt = self.tagsBuffer.get_text( self.tagsBuffer.get_start_iter(), self.tagsBuffer.get_end_iter() )
+ if (txt != self.shownRecd.tags):
+ self.shownRecd.setTags( txt )
+
+
+ def _keyPressEventCb( self, widget, event):
+ #todo: trac #4144
+ self.resetWidgetFadeTimer()
+
+ #we listen here for CTRL+C events and game keys, and pass on events to gtk.Entry fields
+ keyname = gtk.gdk.keyval_name(event.keyval)
- def doClipboardCopyStart( self, recd ):
- imgPath_s = recd.getMediaFilepath()
- if (imgPath_s == None):
- record.Record.log.error("doClipboardCopyStart: imgPath_s==None")
- return None
+ if (keyname == 'KP_Page_Up'): #O, up
+ if (self.LIVEMODE):
+ if (not self.ca.m.UPDATING):
+ self.doShutter()
+ else:
+ if (self.COUNTINGDOWN):
+ self.doShutter()
+ else:
+ if (self.ca.m.MODE == Constants.MODE_PHOTO):
+ self.resumeLiveVideo()
+ else:
+ self.resumePlayLiveVideo()
+ elif (keyname == 'KP_Page_Down'): #x, down
+ if (not self.ca.m.UPDATING and not self.ca.m.RECORDING):
+ self.ca.m.showLastThumb()
+ elif (keyname == 'KP_Home'): #square, left
+ if (not self.ca.m.UPDATING and not self.ca.m.RECORDING and not self.LIVEMODE):
+ self.ca.m.showPrevThumb( self.shownRecd )
+ elif (keyname == 'KP_End'): #check, right
+ if (not self.ca.m.UPDATING and not self.ca.m.RECORDING and not self.LIVEMODE):
+ self.ca.m.showNextThumb( self.shownRecd )
+ elif (keyname == 'c' and event.state == gtk.gdk.CONTROL_MASK):
+ if (self.shownRecd != None):
+ self.copyToClipboard( self.shownRecd )
+ elif (keyname == 'Escape'):
+ if (self.FULLSCREEN):
+ self.FULLSCREEN = False
+ if (self.RECD_INFO_ON):
+ self.infoButtonClicked()
+ else:
+ self.updateVideoComponents()
+ elif (keyname == 'i' and event.state == gtk.gdk.CONTROL_MASK):
+ if (not self.LIVEMODE):
+ self.infoButtonClicked()
- tmpImgPath = recd.getMediaFilepath()
- tmpImgPath = utils.getUniqueFilepath(tmpImgPath, 0)
- shutil.copyfile( imgPath_s, tmpImgPath )
- return tmpImgPath
+ return False
- def doClipboardCopyCopy( self, tmpImgPath, selection_data ):
- tmpImgUri = "file://" + tmpImgPath
- selection_data.set( "text/uri-list", 8, tmpImgUri )
-
-
- def doClipboardCopyFinish( self, tmpImgPath ):
- if (tmpImgPath != None):
- if (os.path.exists(tmpImgPath)):
- os.remove( tmpImgPath )
- tmpImgPath = None
-
-
- def _clipboardGetFuncCb( self, clipboard, selection_data, info, data):
- self.doClipboardCopyCopy( data, selection_data )
-
-
- def _clipboardClearFuncCb( self, clipboard, data):
- self.doClipboardCopyFinish( data )
-
-
- def showPhoto( self, recd ):
- pixbuf = self.getPhotoPixbuf( recd )
- if (pixbuf != None):
- #self.shownRecd = recd
-
- img = _camera.cairo_surface_from_gdk_pixbuf(pixbuf)
- self.livePhotoCanvas.setImage( img )
-
- self.LIVEMODE = False
- self.updateVideoComponents()
-
- self.showRecdMeta(recd)
-
-
- def getPhotoPixbuf( self, recd ):
- pixbuf = None
-
- downloading = self.ca.requestMeshDownload(recd)
- self.MESHING = downloading
-
- if (not downloading):
- self.progressWindow.updateProgress(0, "")
- imgPath = recd.getMediaFilepath()
- if (not imgPath == None):
- if ( os.path.isfile(imgPath) ):
- pixbuf = gtk.gdk.pixbuf_new_from_file(imgPath)
-
- if (pixbuf == None):
- #maybe it is not downloaded from the mesh yet...
- #but we can show the low res thumb in the interim
- pixbuf = recd.getThumbPixbuf()
-
- return pixbuf
+ def copyToClipboard( self, recd ):
+ if (recd.isClipboardCopyable( )):
+ tmpImgPath = self.doClipboardCopyStart( recd )
+ gtk.Clipboard().set_with_data( [('text/uri-list', 0, 0)], self._clipboardGetFuncCb, self._clipboardClearFuncCb, tmpImgPath )
+ return True
- def showLiveVideoTags( self ):
- self.shownRecd = None
- self.livePhotoCanvas.setImage( None )
- self.nameTextfield.set_text("")
- self.tagsBuffer.set_text("")
+ def doClipboardCopyStart( self, recd ):
+ imgPath_s = recd.getMediaFilepath()
+ if (imgPath_s == None):
+ record.Record.log.error("doClipboardCopyStart: imgPath_s==None")
+ return None
- self.scrubWindow.removeCallbacks()
- self.scrubWindow.reset()
- self.MESHING = False
- self.progressWindow.updateProgress( 0, "" )
+ tmpImgPath = recd.getMediaFilepath()
+ tmpImgPath = utils.getUniqueFilepath(tmpImgPath, 0)
+ shutil.copyfile( imgPath_s, tmpImgPath )
+ return tmpImgPath
+
+
+ def doClipboardCopyCopy( self, tmpImgPath, selection_data ):
+ tmpImgUri = "file://" + tmpImgPath
+ selection_data.set( "text/uri-list", 8, tmpImgUri )
+
+
+ def doClipboardCopyFinish( self, tmpImgPath ):
+ if (tmpImgPath != None):
+ if (os.path.exists(tmpImgPath)):
+ os.remove( tmpImgPath )
+ tmpImgPath = None
+
+
+ def _clipboardGetFuncCb( self, clipboard, selection_data, info, data):
+ self.doClipboardCopyCopy( data, selection_data )
+
+
+ def _clipboardClearFuncCb( self, clipboard, data):
+ self.doClipboardCopyFinish( data )
+
+
+ def showPhoto( self, recd ):
+ pixbuf = self.getPhotoPixbuf( recd )
+ if (pixbuf != None):
+ #self.shownRecd = recd
+
+ img = camerac.cairo_surface_from_gdk_pixbuf(pixbuf)
+ self.livePhotoCanvas.setImage( img )
+
+ self.ca.glive.thumb_play()
+ self.LIVEMODE = False
+ self.updateVideoComponents()
+
+ self.showRecdMeta(recd)
+
+
+ def getPhotoPixbuf( self, recd ):
+ pixbuf = None
+
+ downloading = self.ca.requestMeshDownload(recd)
+ self.MESHING = downloading
+
+ if (not downloading):
+ self.progressWindow.updateProgress(0, "")
+ imgPath = recd.getMediaFilepath()
+ if (not imgPath == None):
+ if ( os.path.isfile(imgPath) ):
+ pixbuf = gtk.gdk.pixbuf_new_from_file(imgPath)
+
+ if (pixbuf == None):
+ #maybe it is not downloaded from the mesh yet...
+ #but we can show the low res thumb in the interim
+ pixbuf = recd.getThumbPixbuf()
+
+ return pixbuf
+
+
+ def showLiveVideoTags( self ):
+ self.shownRecd = None
+ self.livePhotoCanvas.setImage( None )
+ self.nameTextfield.set_text("")
+ self.tagsBuffer.set_text("")
- self.resetWidgetFadeTimer( )
+ self.scrubWindow.removeCallbacks()
+ self.scrubWindow.reset()
+ self.MESHING = False
+ self.progressWindow.updateProgress( 0, "" )
+ self.resetWidgetFadeTimer( )
- def updateButtonSensitivities( self ):
- switchStuff = ((not self.ca.m.UPDATING) and (not self.ca.m.RECORDING))
- self.photoToolbar.set_sensitive( switchStuff )
- self.videoToolbar.set_sensitive( switchStuff )
- self.audioToolbar.set_sensitive( switchStuff )
- if (not self.COUNTINGDOWN):
- if (self.ca.m.UPDATING):
- self.ca.ui.setWaitCursor( self.ca.window )
- for i in range (0, len(self.windowStack)):
- self.ca.ui.setWaitCursor( self.windowStack[i].window )
- else:
- self.ca.ui.setDefaultCursor( self.ca.window )
- for i in range (0, len(self.windowStack)):
- self.ca.ui.setDefaultCursor( self.windowStack[i].window )
+ def updateButtonSensitivities( self ):
+ switchStuff = ((not self.ca.m.UPDATING) and (not self.ca.m.RECORDING))
+ self.photoToolbar.set_sensitive( switchStuff )
+ self.videoToolbar.set_sensitive( switchStuff )
+ self.audioToolbar.set_sensitive( switchStuff )
- #display disc is full messages
- self.ca.m.updateXoFullStatus()
- self.recordWindow.displayDiscFullText(self.ca.m.FULL)
- if (self.ca.m.FULL):
- self.recordWindow.shutterButton.set_sensitive( False, True)
- fullMessage = Constants.istrYourDiskIsFull % {"1":Constants.istrJournal}
- self.progressWindow.updateProgress( 1, fullMessage, "gray" )
- else:
- self.recordWindow.shutterButton.set_sensitive( not self.ca.m.UPDATING, False )
- if (self.ca.m.RECORDING):
- self.recordWindow.shutterButton.doRecordButton()
- else:
- self.recordWindow.shutterButton.doNormalButton()
+ if (not self.COUNTINGDOWN):
+ if (self.ca.m.UPDATING):
+ self.ca.ui.setWaitCursor( self.ca.window )
+ for i in range (0, len(self.windowStack)):
+ self.ca.ui.setWaitCursor( self.windowStack[i].window )
+ else:
+ self.ca.ui.setDefaultCursor( self.ca.window )
+ for i in range (0, len(self.windowStack)):
+ self.ca.ui.setDefaultCursor( self.windowStack[i].window )
- kids = self.thumbTray.get_children()
- for i in range (0, len(kids)):
- if (self.ca.m.UPDATING or self.ca.m.RECORDING):
- if (kids[i].getButtClickedId() != 0):
- kids[i].disconnect( kids[i].getButtClickedId() )
- kids[i].setButtClickedId(0)
- else:
- if (kids[i].getButtClickedId() == 0):
- BUTT_CLICKED_ID = kids[i].connect( "clicked", self._thumbClicked, kids[i].recd )
- kids[i].setButtClickedId(BUTT_CLICKED_ID)
+ #display disc is full messages
+ self.ca.m.updateXoFullStatus()
+ self.recordWindow.displayDiscFullText(self.ca.m.FULL)
+ if (self.ca.m.FULL):
+ self.recordWindow.shutterButton.set_sensitive( False, True)
+ fullMessage = Constants.istrYourDiskIsFull % {"1":Constants.istrJournal}
+ self.progressWindow.updateProgress( 1, fullMessage, "gray" )
+ else:
+ self.recordWindow.shutterButton.set_sensitive( not self.ca.m.UPDATING, False )
+ if (self.ca.m.RECORDING):
+ self.recordWindow.shutterButton.doRecordButton()
+ else:
+ self.recordWindow.shutterButton.doNormalButton()
+ kids = self.thumbTray.get_children()
+ for i in range (0, len(kids)):
+ if (self.ca.m.UPDATING or self.ca.m.RECORDING):
+ if (kids[i].getButtClickedId() != 0):
+ kids[i].disconnect( kids[i].getButtClickedId() )
+ kids[i].setButtClickedId(0)
+ else:
+ if (kids[i].getButtClickedId() == 0):
+ BUTT_CLICKED_ID = kids[i].connect( "clicked", self._thumbClicked, kids[i].recd )
+ kids[i].setButtClickedId(BUTT_CLICKED_ID)
- def hideAllWindows( self ):
- for i in range (0, len(self.windowStack)):
- self.moveWinOffscreen( self.windowStack[i] )
+ def hideAllWindows( self ):
+ for i in range (0, len(self.windowStack)):
+ self.moveWinOffscreen( self.windowStack[i] )
- def _liveButtonReleaseCb(self, widget, event):
- self.resumeLiveVideo()
+ def _liveButtonReleaseCb(self, widget, event):
+ self.ca.gplay.stop()
+ self.ca.glive.play()
+ self.resumeLiveVideo()
- def _returnButtonReleaseCb(self, widget, event):
- self.ca.gplay.stop()
- self.ca.glivex.stop()
- self.ca.glive.play()
- self.resumeLiveVideo()
+ def resumeLiveVideo( self ):
+ self.livePhotoCanvas.setImage( None )
- def resumeLiveVideo( self ):
- self.livePhotoCanvas.setImage( None )
+ bottomKid = self.bottomCenter.get_child()
+ if (bottomKid != None):
+ self.bottomCenter.remove( bottomKid )
- bottomKid = self.bottomCenter.get_child()
- if (bottomKid != None):
- self.bottomCenter.remove( bottomKid )
+ self.RECD_INFO_ON = False
- self.RECD_INFO_ON = False
+ if (not self.LIVEMODE):
+ self.ca.m.setUpdating(True)
+ self.ca.gplay.stop()
+ self.showLiveVideoTags()
+ self.LIVEMODE = True
+ self.updateVideoComponents()
+ self.ca.m.setUpdating(False)
- if (not self.LIVEMODE):
- self.ca.m.setUpdating(True)
- self.ca.gplay.stop()
- self.showLiveVideoTags()
- self.LIVEMODE = True
- self.updateVideoComponents()
- self.ca.m.setUpdating(False)
+ def _playLiveButtonReleaseCb(self, widget, event):
+ self.resumePlayLiveVideo()
- def _playLiveButtonReleaseCb(self, widget, event):
- self.resumePlayLiveVideo()
+ def resumePlayLiveVideo( self ):
+ self.ca.gplay.stop()
- def resumePlayLiveVideo( self ):
- self.ca.gplay.stop()
+ self.RECD_INFO_ON = False
+ #if you are big on the screen, don't go changing anything, ok?
+ if (self.LIVEMODE):
+ return
- self.RECD_INFO_ON = False
- #if you are big on the screen, don't go changing anything, ok?
- if (self.LIVEMODE):
- return
+ self.showLiveVideoTags()
+ self.LIVEMODE = True
+ self.startLiveVideo( False )
+ self.updateVideoComponents()
- self.showLiveVideoTags()
- self.LIVEMODE = True
- self.startLiveVideo( False )
- self.updateVideoComponents()
+ def recordVideo( self ):
+ self.ca.glive.startRecordingVideo(self.videoToolbar.getQuality())
+ self.beginRecordingTimer( )
- def recordVideo( self ):
- self.ca.glive.startRecordingVideo( )
- self.beginRecordingTimer( )
+ def recordAudio( self ):
+ self.ca.glive.startRecordingAudio( )
+ self.beginRecordingTimer( )
- def recordAudio( self ):
- self.ca.glive.startRecordingAudio( )
- self.beginRecordingTimer( )
+ def beginRecordingTimer( self ):
+ self.recTime = time.time()
+ self.UPDATE_DURATION_ID = gobject.timeout_add( 500, self._updateDurationCb )
- def beginRecordingTimer( self ):
- self.recTime = time.time()
- self.UPDATE_DURATION_ID = gobject.timeout_add( 500, self._updateDurationCb )
+ def _updateDurationCb( self ):
+ passedTime = time.time() - self.recTime
- def _updateDurationCb( self ):
- passedTime = time.time() - self.recTime
+ duration = 10.0
+ if (self.ca.m.MODE == Constants.MODE_VIDEO):
+ duration = self.videoToolbar.getDuration()+0.0
+ elif (self.ca.m.MODE == Constants.MODE_AUDIO):
+ duration = self.audioToolbar.getDuration()+0.0
- duration = 10.0
- if (self.ca.m.MODE == Constants.MODE_VIDEO):
- duration = self.videoToolbar.getDuration()+0.0
- elif (self.ca.m.MODE == Constants.MODE_AUDIO):
- duration = self.audioToolbar.getDuration()+0.0
+ if (passedTime >= duration ):
+ self.completeCountdown()
+ self.progressWindow.updateProgress( 1, Constants.istrFinishedRecording )
+ if (self.ca.m.RECORDING):
+ gobject.idle_add( self.doShutter )
- if (passedTime >= duration ):
- self.completeCountdown()
- self.progressWindow.updateProgress( 1, Constants.istrFinishedRecording )
- if (self.ca.m.RECORDING):
- gobject.idle_add( self.doShutter )
+ return False
+ else:
+ secsRemaining = duration - passedTime
+ timeRemainStr = Constants.istrSecondsRemaining % {"1":str(int(secsRemaining))}
+ if (secsRemaining >= 60):
+ mins = int( secsRemaining/60 )
+ secs = int( secsRemaining%60 )
+ timeRemainStr = Constants.istrMinutesSecondsRemaining % {"1":str(int(mins)), "2":str(int(secs))}
- return False
- else:
- secsRemaining = duration - passedTime
- timeRemainStr = Constants.istrSecondsRemaining % {"1":str(int(secsRemaining))}
- if (secsRemaining >= 60):
- mins = int( secsRemaining/60 )
- secs = int( secsRemaining%60 )
- timeRemainStr = Constants.istrMinutesSecondsRemaining % {"1":str(int(mins)), "2":str(int(secs))}
+ self.progressWindow.updateProgress( passedTime/duration, Constants.istrDuration + " " + timeRemainStr )
+ return True
- self.progressWindow.updateProgress( passedTime/duration, Constants.istrDuration + " " + timeRemainStr )
- return True
+ def completeCountdown( self ):
+ if (self.UPDATE_DURATION_ID != 0):
+ gobject.source_remove( self.UPDATE_DURATION_ID )
+ self.UPDATE_DURATION_ID = 0
- def completeCountdown( self ):
- if (self.UPDATE_DURATION_ID != 0):
- gobject.source_remove( self.UPDATE_DURATION_ID )
- self.UPDATE_DURATION_ID = 0
+ def updateModeChange(self):
+ #this is called when a menubar button is clicked
+ self.LIVEMODE = True
+ self.FULLSCREEN = False
+ self.RECD_INFO_ON = False
+ self.MESHING = False
- def updateModeChange(self):
- #this is called when a menubar button is clicked
- self.LIVEMODE = True
- self.FULLSCREEN = False
- self.RECD_INFO_ON = False
- self.MESHING = False
+ self.progressWindow.updateProgress(0, "")
- self.progressWindow.updateProgress(0, "")
+ #set up the x & xv x-ition (if need be)
+ self.ca.gplay.stop()
+ self.startLiveVideo( True )
- #set up the x & xv x-ition (if need be)
- self.ca.gplay.stop()
- self.startLiveVideo( True )
+ bottomKid = self.bottomCenter.get_child()
+ if (bottomKid != None):
+ self.bottomCenter.remove( bottomKid )
- bottomKid = self.bottomCenter.get_child()
- if (bottomKid != None):
- self.bottomCenter.remove( bottomKid )
+ self.doMouseListener( True )
+ self.showLiveVideoTags()
+ self.LAST_MODE = -1 #force an update
+ self.updateVideoComponents()
+ self.resetWidgetFadeTimer()
- self.doMouseListener( True )
- self.showLiveVideoTags()
- self.LAST_MODE = -1 #force an update
- self.updateVideoComponents()
- self.resetWidgetFadeTimer()
+ def startLiveVideo(self, force):
+ #We need to know which window and which pipe here
- def startLiveVideo(self, force):
- #We need to know which window and which pipe here
+ #if returning from another activity, active won't be false and needs to be to get started
+ if (self.ca.glive.window == self.liveVideoWindow
+ and self.ca.props.active
+ and not force):
+ return
- #if returning from another activity, active won't be false and needs to be to get started
- if (self.ca.glive.window == self.liveVideoWindow
- and self.ca.props.active
- and not force):
- return
+ self.liveVideoWindow.set_glive(self.ca.glive)
+ self.ca.glive.play()
- self.liveVideoWindow.set_glive(self.ca.glive)
- self.ca.glive.play()
+ def doFullscreen( self ):
+ self.FULLSCREEN = not self.FULLSCREEN
+ self.updateVideoComponents()
- def doFullscreen( self ):
- self.FULLSCREEN = not self.FULLSCREEN
- self.updateVideoComponents()
+ def moveWinOffscreen( self, win ):
+ #we move offscreen to resize or else we get flashes on screen, and setting hide() doesn't allow resize & moves
+ offW = (gtk.gdk.screen_width() + 100)
+ offH = (gtk.gdk.screen_height() + 100)
+ self.smartMove(win, offW, offH)
- def moveWinOffscreen( self, win ):
- #we move offscreen to resize or else we get flashes on screen, and setting hide() doesn't allow resize & moves
- offW = (gtk.gdk.screen_width() + 100)
- offH = (gtk.gdk.screen_height() + 100)
- self.smartMove(win, offW, offH)
+ def setImgLocDim( self, win ):
+ imgDim = self.getImgDim( self.FULLSCREEN )
+ self.smartResize( win, imgDim[0], imgDim[1] )
+ imgLoc = self.getImgLoc( self.FULLSCREEN )
+ self.smartMove( win, imgLoc[0], imgLoc[1] )
- def setImgLocDim( self, win ):
- imgDim = self.getImgDim( self.FULLSCREEN )
- self.smartResize( win, imgDim[0], imgDim[1] )
- imgLoc = self.getImgLoc( self.FULLSCREEN )
- self.smartMove( win, imgLoc[0], imgLoc[1] )
+ def setPrgLocDim( self, win ):
+ prgDim = self.getPrgDim( self.FULLSCREEN )
+ self.smartResize( win, prgDim[0], prgDim[1] )
+ prgLoc = self.getPrgLoc( self.FULLSCREEN )
+ self.smartMove( win, prgLoc[0], prgLoc[1] )
- def setPrgLocDim( self, win ):
- prgDim = self.getPrgDim( self.FULLSCREEN )
- self.smartResize( win, prgDim[0], prgDim[1] )
- prgLoc = self.getPrgLoc( self.FULLSCREEN )
- self.smartMove( win, prgLoc[0], prgLoc[1] )
+ def setTmrLocDim( self, win ):
+ tmrDim = self.getTmrDim( self.FULLSCREEN )
+ self.smartResize( win, tmrDim[0], tmrDim[1] )
+ tmrLoc = self.getTmrLoc( self.FULLSCREEN )
+ self.smartMove( win, tmrLoc[0], tmrLoc[1] )
- def setTmrLocDim( self, win ):
- tmrDim = self.getTmrDim( self.FULLSCREEN )
- self.smartResize( win, tmrDim[0], tmrDim[1] )
- tmrLoc = self.getTmrLoc( self.FULLSCREEN )
- self.smartMove( win, tmrLoc[0], tmrLoc[1] )
+ def setScrLocDim( self, win ):
+ scrDim = self.getScrDim( self.FULLSCREEN )
+ self.smartResize( win, scrDim[0], scrDim[1] )
+ scrLoc = self.getScrLoc( self.FULLSCREEN )
+ self.smartMove( win, scrLoc[0], scrLoc[1] )
- def setScrLocDim( self, win ):
- scrDim = self.getScrDim( self.FULLSCREEN )
- self.smartResize( win, scrDim[0], scrDim[1] )
- scrLoc = self.getScrLoc( self.FULLSCREEN )
- self.smartMove( win, scrLoc[0], scrLoc[1] )
+ def setInfLocDim( self, win ):
+ infDim = self.getInfDim( self.FULLSCREEN )
+ self.smartResize( win, infDim[0], infDim[1] )
+ infLoc = self.getInfLoc( self.FULLSCREEN )
+ self.smartMove( win, infLoc[0], infLoc[1] )
- def setInfLocDim( self, win ):
- infDim = self.getInfDim( self.FULLSCREEN )
- self.smartResize( win, infDim[0], infDim[1] )
- infLoc = self.getInfLoc( self.FULLSCREEN )
- self.smartMove( win, infLoc[0], infLoc[1] )
+ def getScrDim( self, full ):
+ if (full):
+ return [gtk.gdk.screen_width()-(self.inset+self.pgdw+self.inset+self.inset), self.controlBarHt]
+ else:
+ return [self.vw, self.controlBarHt]
- def getScrDim( self, full ):
- if (full):
- return [gtk.gdk.screen_width()-(self.inset+self.pgdw+self.inset+self.inset), self.controlBarHt]
- else:
- return [self.vw, self.controlBarHt]
+ def getScrLoc( self, full ):
+ if (full):
+ return [(self.inset+self.pgdw+self.inset), gtk.gdk.screen_height()-(self.inset+self.controlBarHt)]
+ else:
+ return [self.centerBoxPos[0], self.centerBoxPos[1]+self.vh]
- def getScrLoc( self, full ):
- if (full):
- return [(self.inset+self.pgdw+self.inset), gtk.gdk.screen_height()-(self.inset+self.controlBarHt)]
- else:
- return [self.centerBoxPos[0], self.centerBoxPos[1]+self.vh]
+ def getImgDim( self, full ):
+ if (full):
+ return [gtk.gdk.screen_width(), gtk.gdk.screen_height()]
+ else:
+ return [self.vw, self.vh]
- def getImgDim( self, full ):
- if (full):
- return [gtk.gdk.screen_width(), gtk.gdk.screen_height()]
- else:
- return [self.vw, self.vh]
+ def getImgLoc( self, full ):
+ if (full):
+ return[0, 0]
+ else:
+ return[self.centerBoxPos[0], self.centerBoxPos[1]]
- def getImgLoc( self, full ):
- if (full):
- return[0, 0]
- else:
- return[self.centerBoxPos[0], self.centerBoxPos[1]]
+ def getTmrLoc( self, full ):
+ if (not full):
+ return [self.centerBoxPos[0], self.centerBoxPos[1]+self.vh]
+ else:
+ return [self.inset, gtk.gdk.screen_height()-(self.inset+self.controlBarHt)]
- def getTmrLoc( self, full ):
- if (not full):
- return [self.centerBoxPos[0], self.centerBoxPos[1]+self.vh]
- else:
- return [self.inset, gtk.gdk.screen_height()-(self.inset+self.controlBarHt)]
+ def getTmrDim( self, full ):
+ if (not full):
+ return [self.vw, self.controlBarHt]
+ else:
+ return [gtk.gdk.screen_width()-(self.inset+self.inset), self.controlBarHt]
- def getTmrDim( self, full ):
- if (not full):
- return [self.vw, self.controlBarHt]
- else:
- return [gtk.gdk.screen_width()-(self.inset+self.inset), self.controlBarHt]
+ def setPipLocDim( self, win ):
+ self.smartResize( win, self.pipw, self.piph )
- def setPipLocDim( self, win ):
- self.smartResize( win, self.pipw, self.piph )
+ loc = self.getPipLoc( self.FULLSCREEN )
+ self.smartMove( win, loc[0], loc[1] )
- loc = self.getPipLoc( self.FULLSCREEN )
- self.smartMove( win, loc[0], loc[1] )
+ def getPipLoc( self, full ):
+ if (full):
+ return [self.inset+self.__class__.dim_PIP_BORDER, gtk.gdk.screen_height()-(self.inset+self.piph+self.__class__.dim_PIP_BORDER)]
+ else:
+ return [self.centerBoxPos[0]+self.inset+self.__class__.dim_PIP_BORDER, (self.centerBoxPos[1]+self.vh)-(self.inset+self.piph+self.__class__.dim_PIP_BORDER)]
- def getPipLoc( self, full ):
- if (full):
- return [self.inset+self.__class__.dim_PIP_BORDER, gtk.gdk.screen_height()-(self.inset+self.piph+self.__class__.dim_PIP_BORDER)]
- else:
- return [self.centerBoxPos[0]+self.inset+self.__class__.dim_PIP_BORDER, (self.centerBoxPos[1]+self.vh)-(self.inset+self.piph+self.__class__.dim_PIP_BORDER)]
+ def setPipBgdLocDim( self, win ):
+ pgdLoc = self.getPgdLoc( self.FULLSCREEN )
+ self.smartMove( win, pgdLoc[0], pgdLoc[1] )
- def setPipBgdLocDim( self, win ):
- pgdLoc = self.getPgdLoc( self.FULLSCREEN )
- self.smartMove( win, pgdLoc[0], pgdLoc[1] )
+ def getPgdLoc( self, full ):
+ if (full):
+ return [self.inset, gtk.gdk.screen_height()-(self.inset+self.pgdh)]
+ else:
+ return [self.centerBoxPos[0]+self.inset, (self.centerBoxPos[1]+self.vh)-(self.inset+self.pgdh)]
- def getPgdLoc( self, full ):
- if (full):
- return [self.inset, gtk.gdk.screen_height()-(self.inset+self.pgdh)]
- else:
- return [self.centerBoxPos[0]+self.inset, (self.centerBoxPos[1]+self.vh)-(self.inset+self.pgdh)]
+ def setMaxLocDim( self, win ):
+ maxLoc = self.getMaxLoc( self.FULLSCREEN )
+ self.smartMove( win, maxLoc[0], maxLoc[1] )
- def setMaxLocDim( self, win ):
- maxLoc = self.getMaxLoc( self.FULLSCREEN )
- self.smartMove( win, maxLoc[0], maxLoc[1] )
+ def getMaxLoc( self, full ):
+ if (full):
+ return [gtk.gdk.screen_width()-(self.maxw+self.inset), self.inset]
+ else:
+ return [(self.centerBoxPos[0]+self.vw)-(self.inset+self.maxw), self.centerBoxPos[1]+self.inset]
- def getMaxLoc( self, full ):
- if (full):
- return [gtk.gdk.screen_width()-(self.maxw+self.inset), self.inset]
- else:
- return [(self.centerBoxPos[0]+self.vw)-(self.inset+self.maxw), self.centerBoxPos[1]+self.inset]
+ def getInfLoc( self, full ):
+ if (full):
+ return [gtk.gdk.screen_width()+100,gtk.gdk.screen_height()+100 ]
+ else:
+ dim = self.getInfDim(self.FULLSCREEN)
+ return [(self.centerBoxPos[0]+self.vw)-dim[0], (self.centerBoxPos[1]+self.vh)-dim[1]]
- def getInfLoc( self, full ):
- if (full):
- return [gtk.gdk.screen_width()+100,gtk.gdk.screen_height()+100 ]
- else:
- dim = self.getInfDim(self.FULLSCREEN)
- return [(self.centerBoxPos[0]+self.vw)-dim[0], (self.centerBoxPos[1]+self.vh)-dim[1]]
+ def setEyeLocDim( self, win ):
+ dim = self.getEyeDim( self.FULLSCREEN )
+ self.smartResize( win, dim[0], dim[1] )
+ loc = self.getEyeLoc( self.FULLSCREEN )
+ self.smartMove( win, loc[0], loc[1] )
- def setEyeLocDim( self, win ):
- dim = self.getEyeDim( self.FULLSCREEN )
- self.smartResize( win, dim[0], dim[1] )
- loc = self.getEyeLoc( self.FULLSCREEN )
- self.smartMove( win, loc[0], loc[1] )
+ def getEyeLoc( self, full ):
+ if (not full):
+ return [self.centerBoxPos[0], self.centerBoxPos[1]+self.vh]
+ else:
+ return [self.inset, gtk.gdk.screen_height()-(self.inset+self.controlBarHt)]
- def getEyeLoc( self, full ):
- if (not full):
- return [self.centerBoxPos[0], self.centerBoxPos[1]+self.vh]
- else:
- return [self.inset, gtk.gdk.screen_height()-(self.inset+self.controlBarHt)]
+ def getEyeDim( self, full ):
+ if (not full):
+ if (self.ca.m.MODE == Constants.MODE_PHOTO):
+ return [self.vw, self.controlBarHt]
+ else:
+ return [self.recordButtWd, self.controlBarHt]
+ else:
+ if (self.ca.m.MODE == Constants.MODE_PHOTO):
+ return [gtk.gdk.screen_width()-(self.inset*2), self.controlBarHt]
+ else:
+ return [self.recordButtWd, self.controlBarHt]
- def getEyeDim( self, full ):
- if (not full):
- if (self.ca.m.MODE == Constants.MODE_PHOTO):
- return [self.vw, self.controlBarHt]
- else:
- return [self.recordButtWd, self.controlBarHt]
- else:
- if (self.ca.m.MODE == Constants.MODE_PHOTO):
- return [gtk.gdk.screen_width()-(self.inset*2), self.controlBarHt]
- else:
- return [self.recordButtWd, self.controlBarHt]
+ def getInbLoc( self, full ):
+ return [(self.centerBoxPos[0]+self.vw)-(self.inset+self.letterBoxVW), self.centerBoxPos[1]+self.inset]
- def getInbLoc( self, full ):
- return [(self.centerBoxPos[0]+self.vw)-(self.inset+self.letterBoxVW), self.centerBoxPos[1]+self.inset]
+ def setInbLocDim( self, win ):
+ dim = self.getInbDim( self.FULLSCREEN )
+ self.smartResize( win, dim[0], dim[1] )
+ loc = self.getInbLoc(self.FULLSCREEN)
+ self.smartMove( win, loc[0], loc[1] )
- def setInbLocDim( self, win ):
- dim = self.getInbDim( self.FULLSCREEN )
- self.smartResize( win, dim[0], dim[1] )
- loc = self.getInbLoc(self.FULLSCREEN)
- self.smartMove( win, loc[0], loc[1] )
+ def smartResize( self, win, w, h ):
+ winSize = win.get_size()
+ if ( (winSize[0] != w) or (winSize[1] != h) ):
+ win.resize( w, h )
+ return True
+ else:
+ return False
- def smartResize( self, win, w, h ):
- winSize = win.get_size()
- if ( (winSize[0] != w) or (winSize[1] != h) ):
- win.resize( w, h )
- return True
- else:
- return False
+ def smartMove( self, win, x, y ):
+ winLoc = win.get_position()
+ if ( (winLoc[0] != x) or (winLoc[1] != y) ):
+ win.move( x, y )
+ return True
+ else:
+ return False
- def smartMove( self, win, x, y ):
- winLoc = win.get_position()
- if ( (winLoc[0] != x) or (winLoc[1] != y) ):
- win.move( x, y )
- return True
- else:
- return False
+ def getDim( self, pos, full ):
+ if (pos == "pip"):
+ return self.getPipDim( full )
+ elif(pos == "pgd"):
+ return self.getPgdDim( full )
+ elif(pos == "max"):
+ return self.getMaxDim( full )
+ elif(pos == "img"):
+ return self.getImgDim( full )
+ elif(pos == "eye"):
+ return self.getEyeDim( full )
+ elif(pos == "inb"):
+ return self.getInbDim( full )
+ elif(pos == "prg"):
+ return self.getPrgDim( full )
+ elif(pos == "inf"):
+ return self.getInfDim( full )
+
+
+ def getMaxDim( self, full ):
+ return [self.maxw, self.maxh]
- def getDim( self, pos, full ):
- if (pos == "pip"):
- return self.getPipDim( full )
- elif(pos == "pgd"):
- return self.getPgdDim( full )
- elif(pos == "max"):
- return self.getMaxDim( full )
- elif(pos == "img"):
- return self.getImgDim( full )
- elif(pos == "eye"):
- return self.getEyeDim( full )
- elif(pos == "inb"):
- return self.getInbDim( full )
- elif(pos == "prg"):
- return self.getPrgDim( full )
- elif(pos == "inf"):
- return self.getInfDim( full )
-
-
- def getMaxDim( self, full ):
- return [self.maxw, self.maxh]
+ def getInfDim( self, full ):
+ return [75, 75]
+
+
+ def getPipDim( self, full ):
+ return [self.pipw, self.piph]
+
+
+ def getPgdDim( self, full ):
+ return [self.pgdw, self.pgdh]
+
+
+ def getInbDim( self, full ):
+ return [self.letterBoxVW, self.letterBoxVH]
+
+
+ def getPrgDim( self, full ):
+ if (not full):
+ return [self.vw-self.recordButtWd, self.controlBarHt]
+ else:
+ return [gtk.gdk.screen_width()-(self.inset+self.inset+self.recordButtWd), self.controlBarHt]
+
+
+ def getPrgLoc( self, full ):
+ if (not full):
+ return [self.centerBoxPos[0]+self.recordButtWd, self.centerBoxPos[1]+self.vh]
+ else:
+ return [self.inset+self.recordButtWd, gtk.gdk.screen_height()-(self.inset+self.controlBarHt)]
+
+
+ def getLoc( self, pos, full ):
+ if (pos == "pip"):
+ return self.getPipLoc( full )
+ elif(pos == "pgd"):
+ return self.getPgdLoc( full )
+ elif(pos == "max"):
+ return self.getMaxLoc( full )
+ elif(pos == "img"):
+ return self.getImgLoc( full )
+ elif(pos == "eye"):
+ return self.getEyeLoc( full )
+ elif(pos == "inb"):
+ return self.getInbLoc( full )
+ elif(pos == "prg"):
+ return self.getPrgLoc( full )
+ elif(pos == "inf"):
+ return self.getInfLoc( full )
+
+
+ def _shutterClickCb( self, arg ):
+ self.doShutter()
+
+
+ def doShutter( self ):
+ if (self.UPDATE_TIMER_ID == 0):
+ if (not self.ca.m.RECORDING):
+
+ self.ca.m.updateXoFullStatus()
+ if (self.ca.m.FULL):
+ self.updateButtonSensitivities()
+ return
+
+ #there is no update timer running, so we need to find out if there is a timer needed
+ timerTime = 0
+ if (self.ca.m.MODE == Constants.MODE_PHOTO):
+ timerTime = self.photoToolbar.getTimer()
+ elif (self.ca.m.MODE == Constants.MODE_VIDEO):
+ timerTime = self.videoToolbar.getTimer()
+ elif (self.ca.m.MODE == Constants.MODE_AUDIO):
+ timerTime = self.audioToolbar.getTimer()
+
+ if (timerTime > 0):
+ self.timerStartTime = time.time()
+ self.UPDATE_TIMER_ID = gobject.timeout_add( 500, self._updateTimerCb )
+ self.COUNTINGDOWN = True
+ self.ca.m.setUpdating(True)
+ else:
+ self.clickShutter()
+ else:
+ #or, if there is no countdown, it might be because we are recording
+ self.clickShutter()
+
+ else:
+ #we're timing down something, but interrupted by user click or the timer completing
+ self.completeTimer()
+ gobject.idle_add( self.clickShutter )
+
+
+ def completeTimer( self ):
+ self.COUNTINGDOWN = False
+ self.ca.m.setUpdating(False)
+ self.recordWindow.updateCountdown(-1)
+ self.progressWindow.updateProgress( 1, "" )
+ gobject.source_remove( self.UPDATE_TIMER_ID )
+ self.UPDATE_TIMER_ID = 0
+
+
+ def _updateTimerCb( self ):
+ nowTime = time.time()
+ passedTime = nowTime - self.timerStartTime
+
+ timerTime = 0
+ if (self.ca.m.MODE == Constants.MODE_PHOTO):
+ timerTime = self.photoToolbar.getTimer()
+ elif (self.ca.m.MODE == Constants.MODE_VIDEO):
+ timerTime = self.videoToolbar.getTimer()
+ elif (self.ca.m.MODE == Constants.MODE_AUDIO):
+ timerTime = self.audioToolbar.getTimer()
+
+ if (passedTime >= timerTime):
+ self.COUNTINGDOWN = False
+ self.ca.m.setUpdating(False)
+ self.doShutter()
+ return False
+ else:
+ secsRemaining = timerTime-passedTime
+ self.progressWindow.updateProgress( passedTime/timerTime, Constants.istrTimer + " " + Constants.istrSecondsRemaining % {"1":str(int(secsRemaining))} )
+ self.recordWindow.updateCountdown( int(secsRemaining) )
+ return True
+
+
+ def clickShutter( self ):
+ if (not self.ca.m.RECORDING):
+ aplay.play(Constants.soundClick)
+
+ wasRec = self.ca.m.RECORDING
+ self.ca.m.doShutter()
+ if (wasRec):
+ aplay.play(Constants.soundClick)
+
+
+ def updateVideoComponents( self ):
+ logger.debug('updateVideoComponents: MODE=(%s,%s) FULLSCREEN=(%s,%s)' \
+ ' LIVE=(%s,%s) RECD_INFO=(%s,%s) TRANSCODING=(%s,%s)' \
+ ' MESHING=(%s,%s) windowStack=%s' \
+ % (self.LAST_MODE, self.ca.m.MODE,
+ self.LAST_FULLSCREEN, self.FULLSCREEN,
+ self.LAST_LIVE, self.LIVEMODE,
+ self.LAST_RECD_INFO, self.RECD_INFO_ON,
+ self.LAST_TRANSCODING, self.TRANSCODING,
+ self.LAST_MESHING, self.MESHING,
+ len(self.windowStack)))
+
+ if ( (self.LAST_MODE == self.ca.m.MODE)
+ and (self.LAST_FULLSCREEN == self.FULLSCREEN)
+ and (self.LAST_LIVE == self.LIVEMODE)
+ and (self.LAST_RECD_INFO == self.RECD_INFO_ON)
+ and (self.LAST_TRANSCODING == self.TRANSCODING)
+ and (self.LAST_MESHING == self.MESHING)
+ ):
+ return
+
+ #something's changing so start counting anew
+ self.resetWidgetFadeTimer()
+
+ pos = []
+ if (self.RECD_INFO_ON and not self.TRANSCODING):
+ if (self.ca.m.MODE == Constants.MODE_PHOTO):
+ pos.append({"position":"pgd", "window":self.pipBgdWindow} )
+ pos.append({"position":"pip", "window":self.liveVideoWindow} )
+ pos.append({"position":"inb", "window":self.livePhotoWindow} )
+ pos.append({"position":"inf", "window":self.infWindow} )
+ elif (self.ca.m.MODE == Constants.MODE_VIDEO):
+ pos.append({"position":"pgd", "window":self.pipBgdWindow} )
+ pos.append({"position":"pip", "window":self.liveVideoWindow} )
+ pos.append({"position":"inb", "window":self.playOggWindow} )
+ pos.append({"position":"inf", "window":self.infWindow} )
+ elif (self.ca.m.MODE == Constants.MODE_AUDIO):
+ pos.append({"position":"pgd", "window":self.pipBgdWindow} )
+ pos.append({"position":"pip", "window":self.liveVideoWindow} )
+ pos.append({"position":"inb", "window":self.livePhotoWindow} )
+ pos.append({"position":"inf", "window":self.infWindow} )
+ elif (not self.RECD_INFO_ON and not self.TRANSCODING):
+ if (self.ca.m.MODE == Constants.MODE_PHOTO):
+ if (self.LIVEMODE):
+ pos.append({"position":"img", "window":self.liveVideoWindow} )
+ pos.append({"position":"max", "window":self.maxWindow} )
+ pos.append({"position":"eye", "window":self.recordWindow} )
+ else:
+ pos.append({"position":"img", "window":self.livePhotoWindow} )
+ pos.append({"position":"pgd", "window":self.pipBgdWindow} )
+ pos.append({"position":"pip", "window":self.liveVideoWindow} )
+ if (not self.MESHING):
+ pos.append({"position":"max", "window":self.maxWindow} )
+ pos.append({"position":"inf", "window":self.infWindow} )
+ else:
+ pos.append({"position":"tmr", "window":self.progressWindow} )
+ elif (self.ca.m.MODE == Constants.MODE_VIDEO):
+ if (self.LIVEMODE):
+ pos.append({"position":"img", "window":self.liveVideoWindow} )
+ pos.append({"position":"max", "window":self.maxWindow} )
+ pos.append({"position":"eye", "window":self.recordWindow} )
+ pos.append({"position":"prg", "window":self.progressWindow} )
+ else:
+ pos.append({"position":"img", "window":self.playOggWindow} )
+ pos.append({"position":"pgd", "window":self.pipBgdWindow} )
+ pos.append({"position":"pip", "window":self.liveVideoWindow} )
+ if (not self.MESHING):
+ pos.append({"position":"max", "window":self.maxWindow} )
+ pos.append({"position":"scr", "window":self.scrubWindow} )
+ pos.append({"position":"inf", "window":self.infWindow} )
+ else:
+ pos.append({"position":"tmr", "window":self.progressWindow} )
+ elif (self.ca.m.MODE == Constants.MODE_AUDIO):
+ if (self.LIVEMODE):
+ pos.append({"position":"img", "window":self.liveVideoWindow} )
+ pos.append({"position":"eye", "window":self.recordWindow} )
+ pos.append({"position":"prg", "window":self.progressWindow} )
+ else:
+ pos.append({"position":"img", "window":self.livePhotoWindow} )
+ pos.append({"position":"pgd", "window":self.pipBgdWindow} )
+ pos.append({"position":"pip", "window":self.liveVideoWindow} )
+ if (not self.MESHING):
+ pos.append({"position":"scr", "window":self.scrubWindow} )
+ pos.append({"position":"inf", "window":self.infWindow} )
+ else:
+ pos.append({"position":"tmr", "window":self.progressWindow} )
+ elif (self.TRANSCODING):
+ pos.append({"position":"tmr", "window":self.progressWindow} )
+
+ for i in range (0, len(self.windowStack)):
+ self.windowStack[i].hide_all()
+
+ self.hideAllWindows()
+ self.updatePos( pos )
+
+ for i in range (0, len(self.windowStack)):
+ self.windowStack[i].show_all()
+
+ self.LAST_MODE = self.ca.m.MODE
+ self.LAST_FULLSCREEN = self.FULLSCREEN
+ self.LAST_LIVE = self.LIVEMODE
+ self.LAST_RECD_INFO = self.RECD_INFO_ON
+ self.LAST_TRANSCODING = self.TRANSCODING
+ self.LAST_MESHING = self.MESHING
+
+
+ def debugWindows( self ):
+ for i in range (0, len(self.windowStack)):
+ print self.windowStack[i], self.windowStack[i].get_size(), self.windowStack[i].get_position()
+
+
+ def showWidgets( self ):
+ pos = []
+ if (self.ca.m.MODE == Constants.MODE_PHOTO):
+ if (not self.LIVEMODE):
+ pos.append({"position":"pgd", "window":self.pipBgdWindow} )
+ pos.append({"position":"pip", "window":self.liveVideoWindow} )
+ if (not self.MESHING):
+ pos.append({"position":"max", "window":self.maxWindow} )
+ pos.append({"position":"inf", "window":self.infWindow} )
+ else:
+ pos.append({"position":"max", "window":self.maxWindow} )
+ pos.append({"position":"eye", "window":self.recordWindow} )
+ elif (self.ca.m.MODE == Constants.MODE_VIDEO):
+ if (not self.LIVEMODE):
+ pos.append({"position":"pgd", "window":self.pipBgdWindow} )
+ pos.append({"position":"pip", "window":self.liveVideoWindow} )
+ if (not self.MESHING):
+ pos.append({"position":"max", "window":self.maxWindow} )
+ pos.append({"position":"scr", "window":self.scrubWindow} )
+ pos.append({"position":"inf", "window":self.infWindow} )
+ else:
+ pos.append({"position":"max", "window":self.maxWindow} )
+ pos.append({"position":"eye", "window":self.recordWindow} )
+ pos.append({"position":"prg", "window":self.progressWindow} )
+ elif (self.ca.m.MODE == Constants.MODE_AUDIO):
+ if (not self.LIVEMODE):
+ pos.append({"position":"pgd", "window":self.pipBgdWindow} )
+ pos.append({"position":"pip", "window":self.liveVideoWindow} )
+ if (not self.MESHING):
+ pos.append({"position":"scr", "window":self.scrubWindow} )
+ pos.append({"position":"inf", "window":self.infWindow} )
+ else:
+ pos.append({"position":"eye", "window":self.recordWindow} )
+ pos.append({"position":"prg", "window":self.progressWindow} )
+
+ self.updatePos( pos )
+
+
+ def updatePos( self, pos ):
+ #now move those pieces where they need to be...
+ for i in range (0, len(self.windowStack)):
+ for j in range (0, len(pos)):
+ if (self.windowStack[i] == pos[j]["window"]):
+ if (pos[j]["position"] == "img"):
+ self.setImgLocDim( pos[j]["window"] )
+ elif (pos[j]["position"] == "max"):
+ self.setMaxLocDim( pos[j]["window"] )
+ elif (pos[j]["position"] == "pip"):
+ self.setPipLocDim( pos[j]["window"] )
+ elif (pos[j]["position"] == "pgd"):
+ self.setPipBgdLocDim( pos[j]["window"] )
+ elif (pos[j]["position"] == "eye"):
+ self.setEyeLocDim( pos[j]["window"] )
+ elif (pos[j]["position"] == "inb"):
+ self.setInbLocDim( pos[j]["window"])
+ elif (pos[j]["position"] == "prg"):
+ self.setPrgLocDim( pos[j]["window"])
+ elif (pos[j]["position"] == "tmr"):
+ self.setTmrLocDim( pos[j]["window"])
+ elif (pos[j]["position"] == "scr"):
+ self.setScrLocDim( pos[j]["window"])
+ elif (pos[j]["position"] == "inf"):
+ self.setInfLocDim( pos[j]["window"])
+
+
+ def removeThumb( self, recd ):
+ kids = self.thumbTray.get_children()
+ for i in range (0, len(kids)):
+ if (kids[i].recd == recd):
+ self.thumbTray.remove_item(kids[i])
+ kids[i].cleanUp()
+ kids[i].disconnect( kids[i].getButtClickedId() )
+ kids[i].setButtClickedId(0)
+
+
+ def addThumb( self, recd, forceScroll ):
+ butt = RecdButton( self, recd )
+ BUTT_CLICKED_ID = butt.connect( "clicked", self._thumbClicked, recd )
+ butt.setButtClickedId(BUTT_CLICKED_ID)
+ self.thumbTray.add_item( butt, len(self.thumbTray.get_children()) )
+ butt.show()
+ if (forceScroll):
+ self.thumbTray.scroll_to_end()
+
+
+ def removeThumbs( self ):
+ kids = self.thumbTray.get_children()
+ for i in range (0, len(kids)):
+ self.thumbTray.remove_item(kids[i])
+ kids[i].cleanUp()
+ if (kids[i].getButtClickedId() != 0):
+ kids[i].disconnect( kids[i].getButtClickedId() )
+
+
+ def _thumbClicked( self, button, recd ):
+ self.showThumbSelection( recd )
+
+
+ def infoButtonClicked( self ):
+ self.RECD_INFO_ON = not self.RECD_INFO_ON
+
+ centerKid = self.centerBox.get_child()
+ if (centerKid != None):
+ self.centerBox.remove( centerKid )
+
+ bottomKid = self.bottomCenter.get_child()
+ if (bottomKid != None):
+ self.bottomCenter.remove( bottomKid )
+
+ if (not self.RECD_INFO_ON):
+ if (self.ca.m.MODE == Constants.MODE_PHOTO):
+ self.bottomCenter.add( self.namePanel )
+ self.bottomCenter.show_all( )
+ else:
+ self.centerBox.add( self.infoBox )
+ self.centerBox.show_all( )
+ self.bottomCenter.add( self.namePanel )
+ self.bottomCenter.show_all( )
+
+ self.updateVideoComponents( )
+
+
+ def showMeshRecd( self, recd ):
+ record.Record.log.debug('showMeshRecd: heres the downloaded recd to display...')
+
+ #if this thumbnail is being shown, add the option to copy it now
+ kids = self.thumbTray.get_children()
+ for i in range (0, len(kids)):
+ if (kids[i].recd == recd):
+ kids[i].addCopyMenuItem()
+
+ if (recd == self.shownRecd):
+ record.Record.log.debug('showMeshRecd: and since were still looking at same recd, here it is!')
+ self.showThumbSelection( recd )
+
+
+ def updateMeshProgress( self, progressMade, recd ):
+ self.resetWidgetFadeTimer()
+ if (self.shownRecd != recd):
+ if (self.shownRecd == None):
+ type = Constants.mediaTypes[recd.type][Constants.keyIstr]
+ if (progressMade):
+ msg = Constants.istrDownloadingFrom% {"1":type, "2":recd.meshDownloadingFromNick}
+ self.progressWindow.updateProgress(recd.meshDownlodingPercent, msg)
+
+ else:
+ type = Constants.mediaTypes[recd.type][Constants.keyIstr]
+ if (progressMade):
+ msg = Constants.istrDownloadingFrom% {"1":type, "2":recd.meshDownloadingFromNick}
+ self.progressWindow.updateProgress(recd.meshDownlodingPercent, msg)
+
+ else:
+ type = Constants.mediaTypes[recd.type][Constants.keyIstr]
+ msg = Constants.istrCannotDownload % {"1":type}
+ self.progressWindow.updateProgress(0, msg)
+
+
+ def showThumbSelection( self, recd ):
+ lastRecd = self.shownRecd
+ self.shownRecd = recd
+
+ #do we need to know the type, since we're showing based on the mode of the app?
+ if (recd.type == Constants.TYPE_PHOTO):
+ self.showPhoto( recd )
+ elif (recd.type == Constants.TYPE_VIDEO):
+ self.showVideo( recd )
+ elif (recd.type == Constants.TYPE_AUDIO):
+ self.showAudio( recd )
+
+ if (self.shownRecd != lastRecd):
+ self.photoXoPanel.updateXoColors(self.shownRecd.colorStroke.hex, self.shownRecd.colorFill.hex)
+
+ bottomKid = self.bottomCenter.get_child()
+ if (bottomKid != None):
+ self.bottomCenter.remove( bottomKid )
+
+ if (recd.type == Constants.TYPE_PHOTO):
+ self.bottomCenter.add( self.namePanel )
+ elif (recd.type == Constants.TYPE_VIDEO or recd.type == Constants.TYPE_AUDIO):
+ if (self.RECD_INFO_ON):
+ self.bottomCenter.add( self.namePanel )
+ self.bottomCenter.show_all()
+
+ self.resetWidgetFadeTimer()
+
+
+ def showAudio( self, recd ):
+ self.ca.glive.thumb_play()
+ self.LIVEMODE = False
+
+ #if (recd != self.shownRecd):
+ pixbuf = recd.getAudioImagePixbuf()
+ img = camerac.cairo_surface_from_gdk_pixbuf(pixbuf)
+ self.livePhotoCanvas.setImage( img )
+ #self.shownRecd = recd
+ self.showRecdMeta(recd)
+
+ downloading = self.ca.requestMeshDownload(recd)
+ self.MESHING = downloading
+ record.Record.log.debug("showAudio: downloading->" + str(downloading))
+ if (not downloading):
+ self.progressWindow.updateProgress(0, "")
+ mediaFilepath = recd.getMediaFilepath( )
+ record.Record.log.debug("showAudio: mediaFilepath->" + str(mediaFilepath))
+ if (mediaFilepath != None):
+ videoUrl = "file://" + str( mediaFilepath )
+ self.ca.gplay.setLocation(videoUrl)
+ self.scrubWindow.doPlay()
+
+ self.updateVideoComponents()
+
+
+ def showVideo( self, recd ):
+ logger.debug('showVideo')
+
+ downloading = self.ca.requestMeshDownload(recd)
+
+ if (not downloading):
+ self.progressWindow.updateProgress(0, "")
+
+ self.MESHING = downloading
+ self.LIVEMODE = False
+ #self.shownRecd = recd
+ self.updateVideoComponents()
+ gobject.idle_add( self.showVideo2, recd, downloading )
+
+
+ def showVideo2( self, recd, downloading ):
+ self.showRecdMeta(recd)
- def getInfDim( self, full ):
- return [75, 75]
-
-
- def getPipDim( self, full ):
- return [self.pipw, self.piph]
-
-
- def getPgdDim( self, full ):
- return [self.pgdw, self.pgdh]
-
-
- def getInbDim( self, full ):
- return [self.letterBoxVW, self.letterBoxVH]
-
-
- def getPrgDim( self, full ):
- if (not full):
- return [self.vw-self.recordButtWd, self.controlBarHt]
- else:
- return [gtk.gdk.screen_width()-(self.inset+self.inset+self.recordButtWd), self.controlBarHt]
-
-
- def getPrgLoc( self, full ):
- if (not full):
- return [self.centerBoxPos[0]+self.recordButtWd, self.centerBoxPos[1]+self.vh]
- else:
- return [self.inset+self.recordButtWd, gtk.gdk.screen_height()-(self.inset+self.controlBarHt)]
-
-
- def getLoc( self, pos, full ):
- if (pos == "pip"):
- return self.getPipLoc( full )
- elif(pos == "pgd"):
- return self.getPgdLoc( full )
- elif(pos == "max"):
- return self.getMaxLoc( full )
- elif(pos == "img"):
- return self.getImgLoc( full )
- elif(pos == "eye"):
- return self.getEyeLoc( full )
- elif(pos == "inb"):
- return self.getInbLoc( full )
- elif(pos == "prg"):
- return self.getPrgLoc( full )
- elif(pos == "inf"):
- return self.getInfLoc( full )
-
-
- def _shutterClickCb( self, arg ):
- self.doShutter()
-
-
- def doShutter( self ):
- if (self.UPDATE_TIMER_ID == 0):
- if (not self.ca.m.RECORDING):
-
- self.ca.m.updateXoFullStatus()
- if (self.ca.m.FULL):
- self.updateButtonSensitivities()
- return
-
- #there is no update timer running, so we need to find out if there is a timer needed
- timerTime = 0
- if (self.ca.m.MODE == Constants.MODE_PHOTO):
- timerTime = self.photoToolbar.getTimer()
- elif (self.ca.m.MODE == Constants.MODE_VIDEO):
- timerTime = self.videoToolbar.getTimer()
- elif (self.ca.m.MODE == Constants.MODE_AUDIO):
- timerTime = self.audioToolbar.getTimer()
-
- if (timerTime > 0):
- self.timerStartTime = time.time()
- self.UPDATE_TIMER_ID = gobject.timeout_add( 500, self._updateTimerCb )
- self.COUNTINGDOWN = True
- self.ca.m.setUpdating(True)
- else:
- self.clickShutter()
- else:
- #or, if there is no countdown, it might be because we are recording
- self.clickShutter()
-
- else:
- #we're timing down something, but interrupted by user click or the timer completing
- self.completeTimer()
- gobject.idle_add( self.clickShutter )
-
-
- def completeTimer( self ):
- self.COUNTINGDOWN = False
- self.ca.m.setUpdating(False)
- self.recordWindow.updateCountdown(-1)
- self.progressWindow.updateProgress( 1, "" )
- gobject.source_remove( self.UPDATE_TIMER_ID )
- self.UPDATE_TIMER_ID = 0
-
-
- def _updateTimerCb( self ):
- nowTime = time.time()
- passedTime = nowTime - self.timerStartTime
-
- timerTime = 0
- if (self.ca.m.MODE == Constants.MODE_PHOTO):
- timerTime = self.photoToolbar.getTimer()
- elif (self.ca.m.MODE == Constants.MODE_VIDEO):
- timerTime = self.videoToolbar.getTimer()
- elif (self.ca.m.MODE == Constants.MODE_AUDIO):
- timerTime = self.audioToolbar.getTimer()
-
- if (passedTime >= timerTime):
- self.COUNTINGDOWN = False
- self.ca.m.setUpdating(False)
- self.doShutter()
- return False
- else:
- secsRemaining = timerTime-passedTime
- self.progressWindow.updateProgress( passedTime/timerTime, Constants.istrTimer + " " + Constants.istrSecondsRemaining % {"1":str(int(secsRemaining))} )
- self.recordWindow.updateCountdown( int(secsRemaining) )
- return True
-
-
- def clickShutter( self ):
- if (not self.ca.m.RECORDING):
- os.system( "aplay -t wav " + str(Constants.soundClick) )
-
- wasRec = self.ca.m.RECORDING
- self.ca.m.doShutter()
- if (wasRec):
- os.system( "aplay -t wav " + str(Constants.soundClick) )
-
-
- def updateVideoComponents( self ):
- if ( (self.LAST_MODE == self.ca.m.MODE)
- and (self.LAST_FULLSCREEN == self.FULLSCREEN)
- and (self.LAST_LIVE == self.LIVEMODE)
- and (self.LAST_RECD_INFO == self.RECD_INFO_ON)
- and (self.LAST_TRANSCODING == self.TRANSCODING)
- and (self.LAST_MESHING == self.MESHING)
- ):
- return
-
- #something's changing so start counting anew
- self.resetWidgetFadeTimer()
-
- pos = []
- if (self.RECD_INFO_ON and not self.TRANSCODING):
- if (self.ca.m.MODE == Constants.MODE_PHOTO):
- pos.append({"position":"pgd", "window":self.pipBgdWindow} )
- pos.append({"position":"pip", "window":self.liveVideoWindow} )
- pos.append({"position":"inb", "window":self.livePhotoWindow} )
- pos.append({"position":"inf", "window":self.infWindow} )
- elif (self.ca.m.MODE == Constants.MODE_VIDEO):
- pos.append({"position":"pgd", "window":self.pipBgdWindow} )
- pos.append({"position":"pip", "window":self.slowLiveVideoWindow} )
- pos.append({"position":"inb", "window":self.playOggWindow} )
- pos.append({"position":"inf", "window":self.infWindow} )
- elif (self.ca.m.MODE == Constants.MODE_AUDIO):
- pos.append({"position":"pgd", "window":self.pipBgdWindow} )
- pos.append({"position":"pip", "window":self.liveVideoWindow} )
- pos.append({"position":"inb", "window":self.livePhotoWindow} )
- pos.append({"position":"inf", "window":self.infWindow} )
- elif (not self.RECD_INFO_ON and not self.TRANSCODING):
- if (self.ca.m.MODE == Constants.MODE_PHOTO):
- if (self.LIVEMODE):
- pos.append({"position":"img", "window":self.liveVideoWindow} )
- pos.append({"position":"max", "window":self.maxWindow} )
- pos.append({"position":"eye", "window":self.recordWindow} )
- else:
- pos.append({"position":"img", "window":self.livePhotoWindow} )
- pos.append({"position":"pgd", "window":self.pipBgdWindow} )
- pos.append({"position":"pip", "window":self.liveVideoWindow} )
- if (not self.MESHING):
- pos.append({"position":"max", "window":self.maxWindow} )
- pos.append({"position":"inf", "window":self.infWindow} )
- else:
- pos.append({"position":"tmr", "window":self.progressWindow} )
- elif (self.ca.m.MODE == Constants.MODE_VIDEO):
- if (self.LIVEMODE):
- pos.append({"position":"img", "window":self.liveVideoWindow} )
- pos.append({"position":"max", "window":self.maxWindow} )
- pos.append({"position":"eye", "window":self.recordWindow} )
- pos.append({"position":"prg", "window":self.progressWindow} )
- else:
- pos.append({"position":"img", "window":self.playOggWindow} )
- pos.append({"position":"pgd", "window":self.pipBgdWindow} )
- pos.append({"position":"pip", "window":self.slowLiveVideoWindow} )
- if (not self.MESHING):
- pos.append({"position":"max", "window":self.maxWindow} )
- pos.append({"position":"scr", "window":self.scrubWindow} )
- pos.append({"position":"inf", "window":self.infWindow} )
- else:
- pos.append({"position":"tmr", "window":self.progressWindow} )
- elif (self.ca.m.MODE == Constants.MODE_AUDIO):
- if (self.LIVEMODE):
- pos.append({"position":"img", "window":self.liveVideoWindow} )
- pos.append({"position":"eye", "window":self.recordWindow} )
- pos.append({"position":"prg", "window":self.progressWindow} )
- else:
- pos.append({"position":"img", "window":self.livePhotoWindow} )
- pos.append({"position":"pgd", "window":self.pipBgdWindow} )
- pos.append({"position":"pip", "window":self.liveVideoWindow} )
- if (not self.MESHING):
- pos.append({"position":"scr", "window":self.scrubWindow} )
- pos.append({"position":"inf", "window":self.infWindow} )
- else:
- pos.append({"position":"tmr", "window":self.progressWindow} )
- elif (self.TRANSCODING):
- pos.append({"position":"tmr", "window":self.progressWindow} )
-
- for i in range (0, len(self.windowStack)):
- self.windowStack[i].hide_all()
-
- self.hideAllWindows()
- self.updatePos( pos )
-
- for i in range (0, len(self.windowStack)):
- self.windowStack[i].show_all()
-
- self.LAST_MODE = self.ca.m.MODE
- self.LAST_FULLSCREEN = self.FULLSCREEN
- self.LAST_LIVE = self.LIVEMODE
- self.LAST_RECD_INFO = self.RECD_INFO_ON
- self.LAST_TRANSCODING = self.TRANSCODING
- self.LAST_MESHING = self.MESHING
-
-
- def debugWindows( self ):
- for i in range (0, len(self.windowStack)):
- print self.windowStack[i], self.windowStack[i].get_size(), self.windowStack[i].get_position()
-
-
- def showWidgets( self ):
- pos = []
- if (self.ca.m.MODE == Constants.MODE_PHOTO):
- if (not self.LIVEMODE):
- pos.append({"position":"pgd", "window":self.pipBgdWindow} )
- pos.append({"position":"pip", "window":self.liveVideoWindow} )
- if (not self.MESHING):
- pos.append({"position":"max", "window":self.maxWindow} )
- pos.append({"position":"inf", "window":self.infWindow} )
- else:
- pos.append({"position":"max", "window":self.maxWindow} )
- pos.append({"position":"eye", "window":self.recordWindow} )
- elif (self.ca.m.MODE == Constants.MODE_VIDEO):
- if (not self.LIVEMODE):
- pos.append({"position":"pgd", "window":self.pipBgdWindow} )
- pos.append({"position":"pip", "window":self.slowLiveVideoWindow} )
- if (not self.MESHING):
- pos.append({"position":"max", "window":self.maxWindow} )
- pos.append({"position":"scr", "window":self.scrubWindow} )
- pos.append({"position":"inf", "window":self.infWindow} )
- else:
- pos.append({"position":"max", "window":self.maxWindow} )
- pos.append({"position":"eye", "window":self.recordWindow} )
- pos.append({"position":"prg", "window":self.progressWindow} )
- elif (self.ca.m.MODE == Constants.MODE_AUDIO):
- if (not self.LIVEMODE):
- pos.append({"position":"pgd", "window":self.pipBgdWindow} )
- pos.append({"position":"pip", "window":self.liveVideoWindow} )
- if (not self.MESHING):
- pos.append({"position":"scr", "window":self.scrubWindow} )
- pos.append({"position":"inf", "window":self.infWindow} )
- else:
- pos.append({"position":"eye", "window":self.recordWindow} )
- pos.append({"position":"prg", "window":self.progressWindow} )
-
- self.updatePos( pos )
-
-
- def updatePos( self, pos ):
- #now move those pieces where they need to be...
- for i in range (0, len(self.windowStack)):
- for j in range (0, len(pos)):
- if (self.windowStack[i] == pos[j]["window"]):
- if (pos[j]["position"] == "img"):
- self.setImgLocDim( pos[j]["window"] )
- elif (pos[j]["position"] == "max"):
- self.setMaxLocDim( pos[j]["window"] )
- elif (pos[j]["position"] == "pip"):
- self.setPipLocDim( pos[j]["window"] )
- elif (pos[j]["position"] == "pgd"):
- self.setPipBgdLocDim( pos[j]["window"] )
- elif (pos[j]["position"] == "eye"):
- self.setEyeLocDim( pos[j]["window"] )
- elif (pos[j]["position"] == "inb"):
- self.setInbLocDim( pos[j]["window"])
- elif (pos[j]["position"] == "prg"):
- self.setPrgLocDim( pos[j]["window"])
- elif (pos[j]["position"] == "tmr"):
- self.setTmrLocDim( pos[j]["window"])
- elif (pos[j]["position"] == "scr"):
- self.setScrLocDim( pos[j]["window"])
- elif (pos[j]["position"] == "inf"):
- self.setInfLocDim( pos[j]["window"])
-
-
- def removeThumb( self, recd ):
- kids = self.thumbTray.get_children()
- for i in range (0, len(kids)):
- if (kids[i].recd == recd):
- self.thumbTray.remove_item(kids[i])
- kids[i].cleanUp()
- kids[i].disconnect( kids[i].getButtClickedId() )
- kids[i].setButtClickedId(0)
-
-
- def addThumb( self, recd, forceScroll ):
- butt = RecdButton( self, recd )
- BUTT_CLICKED_ID = butt.connect( "clicked", self._thumbClicked, recd )
- butt.setButtClickedId(BUTT_CLICKED_ID)
- self.thumbTray.add_item( butt, len(self.thumbTray.get_children()) )
- butt.show()
- if (forceScroll):
- self.thumbTray.scroll_to_end()
-
-
- def removeThumbs( self ):
- kids = self.thumbTray.get_children()
- for i in range (0, len(kids)):
- self.thumbTray.remove_item(kids[i])
- kids[i].cleanUp()
- if (kids[i].getButtClickedId() != 0):
- kids[i].disconnect( kids[i].getButtClickedId() )
-
-
- def _thumbClicked( self, button, recd ):
- self.showThumbSelection( recd )
-
-
- def infoButtonClicked( self ):
- self.RECD_INFO_ON = not self.RECD_INFO_ON
-
- centerKid = self.centerBox.get_child()
- if (centerKid != None):
- self.centerBox.remove( centerKid )
-
- bottomKid = self.bottomCenter.get_child()
- if (bottomKid != None):
- self.bottomCenter.remove( bottomKid )
-
- if (not self.RECD_INFO_ON):
- if (self.ca.m.MODE == Constants.MODE_PHOTO):
- self.bottomCenter.add( self.namePanel )
- self.bottomCenter.show_all( )
- else:
- self.centerBox.add( self.infoBox )
- self.centerBox.show_all( )
- self.bottomCenter.add( self.namePanel )
- self.bottomCenter.show_all( )
-
- self.updateVideoComponents( )
-
-
- def showMeshRecd( self, recd ):
- record.Record.log.debug('showMeshRecd: heres the downloaded recd to display...')
-
- #if this thumbnail is being shown, add the option to copy it now
- kids = self.thumbTray.get_children()
- for i in range (0, len(kids)):
- if (kids[i].recd == recd):
- kids[i].addCopyMenuItem()
-
- if (recd == self.shownRecd):
- record.Record.log.debug('showMeshRecd: and since were still looking at same recd, here it is!')
- self.showThumbSelection( recd )
-
-
- def updateMeshProgress( self, progressMade, recd ):
- self.resetWidgetFadeTimer()
- if (self.shownRecd != recd):
- if (self.shownRecd == None):
- type = Constants.mediaTypes[recd.type][Constants.keyIstr]
- if (progressMade):
- msg = Constants.istrDownloadingFrom% {"1":type, "2":recd.meshDownloadingFromNick}
- self.progressWindow.updateProgress(recd.meshDownlodingPercent, msg)
-
- else:
- type = Constants.mediaTypes[recd.type][Constants.keyIstr]
- if (progressMade):
- msg = Constants.istrDownloadingFrom% {"1":type, "2":recd.meshDownloadingFromNick}
- self.progressWindow.updateProgress(recd.meshDownlodingPercent, msg)
-
- else:
- type = Constants.mediaTypes[recd.type][Constants.keyIstr]
- msg = Constants.istrCannotDownload % {"1":type}
- self.progressWindow.updateProgress(0, msg)
-
-
- def showThumbSelection( self, recd ):
- lastRecd = self.shownRecd
- self.shownRecd = recd
-
- #do we need to know the type, since we're showing based on the mode of the app?
- if (recd.type == Constants.TYPE_PHOTO):
- self.showPhoto( recd )
- elif (recd.type == Constants.TYPE_VIDEO):
- self.showVideo( recd )
- elif (recd.type == Constants.TYPE_AUDIO):
- self.showAudio( recd )
-
- if (self.shownRecd != lastRecd):
- self.photoXoPanel.updateXoColors(self.shownRecd.colorStroke.hex, self.shownRecd.colorFill.hex)
-
- bottomKid = self.bottomCenter.get_child()
- if (bottomKid != None):
- self.bottomCenter.remove( bottomKid )
-
- if (recd.type == Constants.TYPE_PHOTO):
- self.bottomCenter.add( self.namePanel )
- elif (recd.type == Constants.TYPE_VIDEO or recd.type == Constants.TYPE_AUDIO):
- if (self.RECD_INFO_ON):
- self.bottomCenter.add( self.namePanel )
- self.bottomCenter.show_all()
+ ableToShowVideo = False
+ if (not downloading):
+ mediaFilepath = recd.getMediaFilepath()
+ if (mediaFilepath != None):
+ self.ca.glive.thumb_play(use_fallback=True)
+ logger.debug('showVideo2 file=%s' % mediaFilepath)
+ videoUrl = "file://" + str( mediaFilepath )
+ self.ca.gplay.setLocation(videoUrl)
+ self.scrubWindow.doPlay()
+ ableToShowVideo = True
- self.resetWidgetFadeTimer()
-
-
- def showAudio( self, recd ):
- self.LIVEMODE = False
-
- #if (recd != self.shownRecd):
- pixbuf = recd.getAudioImagePixbuf()
- img = _camera.cairo_surface_from_gdk_pixbuf(pixbuf)
- self.livePhotoCanvas.setImage( img )
- #self.shownRecd = recd
- self.showRecdMeta(recd)
-
- downloading = self.ca.requestMeshDownload(recd)
- self.MESHING = downloading
- record.Record.log.debug("showAudio: downloading->" + str(downloading))
- if (not downloading):
- self.progressWindow.updateProgress(0, "")
- mediaFilepath = recd.getMediaFilepath( )
- record.Record.log.debug("showAudio: mediaFilepath->" + str(mediaFilepath))
- if (mediaFilepath != None):
- videoUrl = "file://" + str( mediaFilepath )
- self.ca.gplay.setLocation(videoUrl)
- self.scrubWindow.doPlay()
-
- self.updateVideoComponents()
-
-
- def showVideo( self, recd ):
- downloading = self.ca.requestMeshDownload(recd)
-
- if (not downloading):
- self.progressWindow.updateProgress(0, "")
-
- self.MESHING = downloading
- self.LIVEMODE = False
- #self.shownRecd = recd
- self.updateVideoComponents()
- gobject.idle_add( self.showVideo2, recd, downloading )
-
-
- def showVideo2( self, recd, downloading ):
- self.showRecdMeta(recd)
+ if (not ableToShowVideo):
+ self.ca.glive.thumb_play(use_fallback=True)
+ # FIXME is this correct?
+ thumbFilepath = recd.getThumbFilepath( )
+ logger.debug('showVideo3 file=%s' % thumbFilepath)
+ thumbUrl = "file://" + str( thumbFilepath )
+ self.ca.gplay.setLocation(thumbUrl)
- ableToShowVideo = False
- if (not downloading):
- mediaFilepath = recd.getMediaFilepath()
- if (mediaFilepath != None):
- self.ca.glive.stop()
- self.ca.glivex.play()
- videoUrl = "file://" + str( mediaFilepath )
- self.ca.gplay.setLocation(videoUrl)
- self.scrubWindow.doPlay()
- ableToShowVideo = True
- if (not ableToShowVideo):
- # FIXME is this correct?
- self.ca.glive.stop()
- self.ca.glivex.play()
- thumbFilepath = recd.getThumbFilepath( )
- thumbUrl = "file://" + str( thumbFilepath )
- self.ca.gplay.setLocation(thumbUrl)
+ def deleteThumbSelection( self, recd ):
+ self.ca.m.deleteRecorded( recd )
+ self.ca.glive.play()
+ self.removeThumb( recd )
+ self.removeIfSelectedRecorded( recd )
- def deleteThumbSelection( self, recd ):
- self.ca.m.deleteRecorded( recd )
- self.removeThumb( recd )
- self.removeIfSelectedRecorded( recd )
+ def removeIfSelectedRecorded( self, recd ):
+ if (recd == self.shownRecd):
+ if (recd.type == Constants.TYPE_PHOTO):
+ self.livePhotoCanvas.setImage( None )
+ elif (recd.type == Constants.TYPE_VIDEO):
+ self.ca.gplay.stop()
+ self.startLiveVideo( False )
+ elif (recd.type == Constants.TYPE_AUDIO):
+ self.livePhotoCanvas.setImage( None )
+ self.startLiveAudio()
+ self.RECD_INFO_ON = False
+ self.LIVEMODE = True
+ self.updateVideoComponents()
- def removeIfSelectedRecorded( self, recd ):
- if (recd == self.shownRecd):
- if (recd.type == Constants.TYPE_PHOTO):
- self.livePhotoCanvas.setImage( None )
- elif (recd.type == Constants.TYPE_VIDEO):
- self.ca.gplay.stop()
- self.startLiveVideo( False )
- elif (recd.type == Constants.TYPE_AUDIO):
- self.livePhotoCanvas.setImage( None )
- self.startLiveAudio()
+ self.showLiveVideoTags()
- self.LIVEMODE = True
- self.updateVideoComponents()
- self.showLiveVideoTags()
+ def startLiveAudio( self ):
+ self.ca.m.setUpdating(True)
+ self.ca.gplay.stop()
+ self.liveVideoWindow.set_glive(self.ca.glive)
- def startLiveAudio( self ):
- self.ca.m.setUpdating(True)
- self.ca.gplay.stop()
+ self.showLiveVideoTags()
+ self.LIVEMODE = True
+ self.updateVideoComponents()
+ self.ca.m.setUpdating(False)
- self.liveVideoWindow.set_glive(self.ca.glive)
- self.showLiveVideoTags()
- self.LIVEMODE = True
- self.updateVideoComponents()
- self.ca.m.setUpdating(False)
+ def showPostProcessGfx( self, show ):
+ #not self.FULLSCREEN
+ centerKid = self.centerBox.get_child()
+ if (centerKid != None):
+ self.centerBox.remove( centerKid )
+ if ( show ):
+ self.centerBox.add( self.backgdCanvasBox )
+ self.centerBox.show_all()
+ else:
+ self.backgdCanvas.setImage( None )
- def showPostProcessGfx( self, show ):
- #not self.FULLSCREEN
- centerKid = self.centerBox.get_child()
- if (centerKid != None):
- self.centerBox.remove( centerKid )
- if ( show ):
- self.centerBox.add( self.backgdCanvasBox )
- self.centerBox.show_all()
- else:
- self.backgdCanvas.setImage( None )
+ def setPostProcessPixBuf( self, pixbuf ):
+ if (pixbuf.get_width()>self.__class__.dim_THUMB_WIDTH):
+ pixbuf = pixbuf.scale_simple(self.__class__.dim_THUMB_WIDTH, self.__class__.dim_THUMB_HEIGHT, gtk.gdk.INTERP_NEAREST)
+ pixbuf = utils.grayScalePixBuf(pixbuf, True)
+ img = camerac.cairo_surface_from_gdk_pixbuf(pixbuf)
+ self.backgdCanvas.setImage(img)
- def setPostProcessPixBuf( self, pixbuf ):
- if (pixbuf.get_width()>self.__class__.dim_THUMB_WIDTH):
- pixbuf = pixbuf.scale_simple(self.__class__.dim_THUMB_WIDTH, self.__class__.dim_THUMB_HEIGHT, gtk.gdk.INTERP_NEAREST)
- pixbuf = utils.grayScalePixBuf(pixbuf, True)
- img = _camera.cairo_surface_from_gdk_pixbuf(pixbuf)
- self.backgdCanvas.setImage(img)
+ def showRecdMeta( self, recd ):
+ self.photographerNameLabel.set_label( recd.recorderName )
+ self.nameTextfield.set_text( recd.title )
+ self.nameTextfield.set_sensitive( True )
+ self.tagsBuffer.set_text( recd.tags )
+ self.dateDateLabel.set_label( utils.getDateString(recd.time) )
+ self.photographerPanel.show()
+ self.namePanel.show()
+ self.datePanel.show()
+ self.tagsPanel.show()
+ self.tagsField.set_sensitive(True)
- def showRecdMeta( self, recd ):
- self.photographerNameLabel.set_label( recd.recorderName )
- self.nameTextfield.set_text( recd.title )
- self.nameTextfield.set_sensitive( True )
- self.tagsBuffer.set_text( recd.tags )
- self.dateDateLabel.set_label( utils.getDateString(recd.time) )
- self.photographerPanel.show()
- self.namePanel.show()
- self.datePanel.show()
- self.tagsPanel.show()
- self.tagsField.set_sensitive(True)
+ def setWaitCursor( self, win ):
+ win.set_cursor( gtk.gdk.Cursor(gtk.gdk.WATCH) )
- def setWaitCursor( self, win ):
- win.set_cursor( gtk.gdk.Cursor(gtk.gdk.WATCH) )
-
-
- def setDefaultCursor( self, win ):
- win.set_cursor( None )
+ def setDefaultCursor( self, win ):
+ win.set_cursor( None )
class PhotoCanvas(P5):
- def __init__(self):
- P5.__init__(self)
- self.img = None
- self.drawImg = None
- self.SCALING_IMG_ID = 0
- self.cacheWid = -1
- self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
+ def __init__(self):
+ P5.__init__(self)
+ self.img = None
+ self.drawImg = None
+ self.SCALING_IMG_ID = 0
+ self.cacheWid = -1
+ self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
- def draw(self, ctx, w, h):
- self.background( ctx, Constants.colorBlack, w, h )
+ def draw(self, ctx, w, h):
+ self.background( ctx, Constants.colorBlack, w, h )
- if (self.img != None):
+ if (self.img != None):
- if (w == self.img.get_width()):
- self.cacheWid == w
- self.drawImg = self.img
+ if (w == self.img.get_width()):
+ self.cacheWid == w
+ self.drawImg = self.img
- #only scale images when you need to, otherwise you're wasting cycles, fool!
- if (self.cacheWid != w):
- if (self.SCALING_IMG_ID == 0):
- self.drawImg = None
- self.SCALING_IMG_ID = gobject.idle_add( self.resizeImage, w, h )
+ #only scale images when you need to, otherwise you're wasting cycles, fool!
+ if (self.cacheWid != w):
+ if (self.SCALING_IMG_ID == 0):
+ self.drawImg = None
+ self.SCALING_IMG_ID = gobject.idle_add( self.resizeImage, w, h )
- if (self.drawImg != None):
- #center the image based on the image size, and w & h
- ctx.set_source_surface(self.drawImg, (w/2)-(self.drawImg.get_width()/2), (h/2)-(self.drawImg.get_height()/2))
- ctx.paint()
+ if (self.drawImg != None):
+ #center the image based on the image size, and w & h
+ ctx.set_source_surface(self.drawImg, (w/2)-(self.drawImg.get_width()/2), (h/2)-(self.drawImg.get_height()/2))
+ ctx.paint()
- self.cacheWid = w
+ self.cacheWid = w
- def setImage(self, img):
- self.cacheWid = -1
- self.img = img
- self.drawImg = None
- self.queue_draw()
+ def setImage(self, img):
+ self.cacheWid = -1
+ self.img = img
+ self.drawImg = None
+ self.queue_draw()
- def resizeImage(self, w, h):
- self.SCALING_IMG_ID = 0
- if (self.img == None):
- return
+ def resizeImage(self, w, h):
+ self.SCALING_IMG_ID = 0
+ if (self.img == None):
+ return
- #use image size in case 640 no more
- scaleImg = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
- sCtx = cairo.Context(scaleImg)
- sScl = (w+0.0)/(self.img.get_width()+0.0)
- sCtx.scale( sScl, sScl )
- sCtx.set_source_surface( self.img, 0, 0 )
- sCtx.paint()
- self.drawImg = scaleImg
- self.cacheWid = w
- self.queue_draw()
+ #use image size in case 640 no more
+ scaleImg = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
+ sCtx = cairo.Context(scaleImg)
+ sScl = (w+0.0)/(self.img.get_width()+0.0)
+ sCtx.scale( sScl, sScl )
+ sCtx.set_source_surface( self.img, 0, 0 )
+ sCtx.paint()
+ self.drawImg = scaleImg
+ self.cacheWid = w
+ self.queue_draw()
class xoPanel(P5):
- def __init__(self):
- P5.__init__(self)
- self.xoGuy = None
- self.lastStroke = None
- self.lastFill = None
+ def __init__(self):
+ P5.__init__(self)
+ self.xoGuy = None
+ self.lastStroke = None
+ self.lastFill = None
- def updateXoColors( self, strokeHex, fillHex ):
- if (self.lastStroke != None):
- if ((self.lastStroke == strokeHex) and (self.lastFill == fillHex)):
- return
+ def updateXoColors( self, strokeHex, fillHex ):
+ if (self.lastStroke != None):
+ if ((self.lastStroke == strokeHex) and (self.lastFill == fillHex)):
+ return
- lastStroke = strokeHex
- lastFill = fillHex
- self.xoGuy = utils.loadSvg(Constants.xoGuySvgData, strokeHex, fillHex)
- self.queue_draw()
+ lastStroke = strokeHex
+ lastFill = fillHex
+ self.xoGuy = utils.loadSvg(Constants.xoGuySvgData, strokeHex, fillHex)
+ self.queue_draw()
- def draw(self, ctx, w, h):
- #todo: 2x buffer
- self.background( ctx, Constants.colorButton, w, h )
+ def draw(self, ctx, w, h):
+ #todo: 2x buffer
+ self.background( ctx, Constants.colorButton, w, h )
- if (self.xoGuy != None):
- #todo: scale mr xo to fit in his box
- ctx.scale( .6, .6 )
- self.xoGuy.render_cairo( ctx )
+ if (self.xoGuy != None):
+ #todo: scale mr xo to fit in his box
+ ctx.scale( .6, .6 )
+ self.xoGuy.render_cairo( ctx )
class ScrubberWindow(gtk.Window):
- def __init__(self, ui):
- gtk.Window.__init__(self)
- self.ui = ui
- 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, Constants.colorBlack.gColor )
- self.hbox.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
- self.add( self.hbox )
-
- self.button = gtk.Button()
- buttBox = gtk.EventBox()
- buttBox.add(self.button)
- buttBox.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.button.set_image( Constants.recPlayImg )
- self.button.set_property('can-default', True)
- self.button.set_relief(gtk.RELIEF_NONE)
- self.button.set_size_request( self.ui.recordButtWd, self.ui.recordButtWd )
- buttBox.set_size_request( self.ui.recordButtWd, self.ui.recordButtWd )
- #self.button.set_border_width( UI.dim_INSET/2 )
- self.button.show()
-
- buttBox.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.button.modify_bg( gtk.STATE_ACTIVE, Constants.colorBlack.gColor )
-
- 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, Constants.colorBlack.gColor )
- 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 __init__(self, ui):
+ gtk.Window.__init__(self)
+ self.ui = ui
+ 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, Constants.colorBlack.gColor )
+ self.hbox.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
+ self.add( self.hbox )
+
+ self.button = gtk.Button()
+ buttBox = gtk.EventBox()
+ buttBox.add(self.button)
+ buttBox.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.button.set_image( Constants.recPlayImg )
+ self.button.set_property('can-default', True)
+ self.button.set_relief(gtk.RELIEF_NONE)
+ self.button.set_size_request( self.ui.recordButtWd, self.ui.recordButtWd )
+ buttBox.set_size_request( self.ui.recordButtWd, self.ui.recordButtWd )
+ #self.button.set_border_width( UI.dim_INSET/2 )
+ self.button.show()
+
+ buttBox.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.button.modify_bg( gtk.STATE_ACTIVE, Constants.colorBlack.gColor )
+
+ 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, Constants.colorBlack.gColor )
+ 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 reset(self):
+ self.adjustment.set_value(0)
- def _buttonClickedCb(self, widget):
- self.play_toggled()
+ def _buttonClickedCb(self, widget):
+ self.play_toggled()
- def set_button_play(self):
- self.button.set_image(Constants.recPlayImg)
+ def set_button_play(self):
+ self.button.set_image(Constants.recPlayImg)
- def set_button_pause(self):
- self.button.set_image(Constants.recPauseImg)
+ def set_button_pause(self):
+ self.button.set_image(Constants.recPauseImg)
- def play_toggled(self):
- self.p_position, self.p_duration = self.ui.ca.gplay.queryPosition()
- if (self.p_position == self.p_duration):
- self.ui.ca.gplay.seek(0)
- self.ui.ca.gplay.pause()
+ def play_toggled(self):
+ self.p_position, self.p_duration = self.ui.ca.gplay.queryPosition()
+ if (self.p_position == self.p_duration):
+ self.ui.ca.gplay.seek(0)
+ self.ui.ca.gplay.pause()
- if self.ui.ca.gplay.is_playing():
- self.ui.ca.gplay.pause()
- self.set_button_play()
- else:
- #if self.ui.ca.gplay.error:
- # #todo: check if we have "error", and also to disable everything
- # self.button.set_disabled()
- #else:
- self.doPlay()
+ if self.ui.ca.gplay.is_playing():
+ self.ui.ca.gplay.pause()
+ self.set_button_play()
+ else:
+ #if self.ui.ca.gplay.error:
+ # #todo: check if we have "error", and also to disable everything
+ # self.button.set_disabled()
+ #else:
+ self.doPlay()
- def doPlay(self):
- self.ui.ca.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 doPlay(self):
+ self.ui.ca.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.ui.ca.gplay.is_playing()
- if self.was_playing:
- self.ui.ca.gplay.pause()
+ def _scaleButtonPressCb(self, widget, event):
+ #self.button.set_sensitive(False)
+ self.was_playing = self.ui.ca.gplay.is_playing()
+ if self.was_playing:
+ self.ui.ca.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
+ # 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)
+ # 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
+ 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.ui.ca.gplay.play()
+ #self.button.set_sensitive(True)
+ if self.was_playing:
+ self.ui.ca.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)
+ 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.ui.ca.gplay.seek(real)
- # allow for a preroll
- self.ui.ca.gplay.get_state(timeout=50*gst.MSECOND) # 50 ms
+ def _scaleValueChangedCb(self, scale):
+ real = long(scale.get_value() * self.p_duration / 100) # in ns
+ self.ui.ca.gplay.seek(real)
+ # allow for a preroll
+ self.ui.ca.gplay.get_state(timeout=50*gst.MSECOND) # 50 ms
- def _updateScaleCb(self):
- self.p_position, self.p_duration = self.ui.ca.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
+ def _updateScaleCb(self):
+ self.p_position, self.p_duration = self.ui.ca.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)
+ self.adjustment.set_value(value)
- if self.ui.ca.gplay.is_playing() and (self.p_position == self.p_duration):
- self.ui.ca.gplay.pause()
- self.set_button_play()
+ if self.ui.ca.gplay.is_playing() and (self.p_position == self.p_duration):
+ self.ui.ca.gplay.pause()
+ self.set_button_play()
- return True
+ return True
class MaxButton(P5Button):
- def __init__(self, ui):
- P5Button.__init__(self)
- self.ui = ui
-
- self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
-
- xs = []
- ys = []
- xs.append(0)
- ys.append(0)
- xs.append(self.ui.maxw)
- ys.append(0)
- xs.append(self.ui.maxw)
- ys.append(self.ui.maxh)
- xs.append(0)
- ys.append(self.ui.maxh)
- poly = Polygon( xs, ys )
- butt = Button( poly, 0, 0)
- butt.addActionListener( self )
- self.maxS = "max"
- butt.setActionCommand( self.maxS )
- self._butts.append( butt )
-
-
- def draw(self, ctx, w, h):
- if (self.ui.FULLSCREEN):
- Constants.maxEnlargeSvg.render_cairo( ctx )
- else:
- Constants.maxReduceSvg.render_cairo( ctx )
-
-
- def fireButton(self, actionCommand):
- if (actionCommand == self.maxS):
- self.ui.doFullscreen()
+ def __init__(self, ui):
+ P5Button.__init__(self)
+ self.ui = ui
+
+ self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
+
+ xs = []
+ ys = []
+ xs.append(0)
+ ys.append(0)
+ xs.append(self.ui.maxw)
+ ys.append(0)
+ xs.append(self.ui.maxw)
+ ys.append(self.ui.maxh)
+ xs.append(0)
+ ys.append(self.ui.maxh)
+ poly = Polygon( xs, ys )
+ butt = Button( poly, 0, 0)
+ butt.addActionListener( self )
+ self.maxS = "max"
+ butt.setActionCommand( self.maxS )
+ self._butts.append( butt )
+
+
+ def draw(self, ctx, w, h):
+ if (self.ui.FULLSCREEN):
+ Constants.maxEnlargeSvg.render_cairo( ctx )
+ else:
+ Constants.maxReduceSvg.render_cairo( ctx )
+
+
+ def fireButton(self, actionCommand):
+ if (actionCommand == self.maxS):
+ self.ui.doFullscreen()
class InfButton(P5Button):
- #todo: just a gtk.Image here, no?
- def __init__(self, ui):
- P5Button.__init__(self)
- self.ui = ui
+ #todo: just a gtk.Image here, no?
+ def __init__(self, ui):
+ P5Button.__init__(self)
+ self.ui = ui
- self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
+ self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
- self.set_size_request( 75, 75 )
+ self.set_size_request( 75, 75 )
- xs = []
- ys = []
- xs.append(0)
- ys.append(0)
- xs.append(75)
- ys.append(0)
- xs.append(75)
- ys.append(75)
- xs.append(0)
- ys.append(75)
- poly = Polygon( xs, ys )
- butt = Button( poly, 0, 0)
- butt.addActionListener( self )
- self.infS = "inf"
- butt.setActionCommand( self.infS )
- self._butts.append( butt )
+ xs = []
+ ys = []
+ xs.append(0)
+ ys.append(0)
+ xs.append(75)
+ ys.append(0)
+ xs.append(75)
+ ys.append(75)
+ xs.append(0)
+ ys.append(75)
+ poly = Polygon( xs, ys )
+ butt = Button( poly, 0, 0)
+ butt.addActionListener( self )
+ self.infS = "inf"
+ butt.setActionCommand( self.infS )
+ self._butts.append( butt )
- def draw(self, ctx, w, h):
- self.background( ctx, Constants.colorBlack, w, h )
- Constants.infoOnSvg.render_cairo( ctx )
+ def draw(self, ctx, w, h):
+ self.background( ctx, Constants.colorBlack, w, h )
+ Constants.infoOnSvg.render_cairo( ctx )
- def fireButton(self, actionCommand):
- if (actionCommand == self.infS):
- self.ui.infoButtonClicked()
+ def fireButton(self, actionCommand):
+ if (actionCommand == self.infS):
+ self.ui.infoButtonClicked()
class RecordButton(gtk.Button):
- def __init__(self):
- gtk.Button.__init__(self)
- self.sens = True
- self.img = None
- #todo: check on record state, compare button imgs
+ def __init__(self):
+ gtk.Button.__init__(self)
+ self.sens = True
+ self.img = None
+ #todo: check on record state, compare button imgs
- def set_sensitive(self, sen, full):
- if (sen == self.sens):
- return
- self.sens = sen
+ def set_sensitive(self, sen, full):
+ if (sen == self.sens):
+ return
+ self.sens = sen
- if (self.sens):
- self.set_image( Constants.recImg )
- else:
- if (full):
- self.set_image( Constants.fullInsensitiveImg )
- else:
- self.set_image( Constants.recInsensitiveImg )
+ if (self.sens):
+ self.set_image( Constants.recImg )
+ else:
+ if (full):
+ self.set_image( Constants.fullInsensitiveImg )
+ else:
+ self.set_image( Constants.recInsensitiveImg )
- super(RecordButton, self).set_sensitive(self.sens)
+ super(RecordButton, self).set_sensitive(self.sens)
- def doRecordButton(self):
- if (not self.sens):
- return
- self.set_image( Constants.recRedImg )
+ def doRecordButton(self):
+ if (not self.sens):
+ return
+ self.set_image( Constants.recRedImg )
- def doNormalButton(self):
- if (not self.sens):
- return
- self.set_image( Constants.recImg )
+ def doNormalButton(self):
+ if (not self.sens):
+ return
+ self.set_image( Constants.recImg )
class RecordWindow(gtk.Window):
- def __init__(self, ui):
- gtk.Window.__init__(self)
- self.ui = ui
- self.num = -1
+ def __init__(self, ui):
+ gtk.Window.__init__(self)
+ self.ui = ui
+ self.num = -1
- self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.shutterButton = RecordButton()
- self.shutterButton.set_size_request(self.ui.recordButtWd, self.ui.recordButtWd)
- self.shutterButton.set_relief(gtk.RELIEF_NONE)
- self.shutterButton.set_image( Constants.recImg )
- self.shutterButton.connect("clicked", self.ui._shutterClickCb)
+ self.shutterButton = RecordButton()
+ self.shutterButton.set_size_request(self.ui.recordButtWd, self.ui.recordButtWd)
+ self.shutterButton.set_relief(gtk.RELIEF_NONE)
+ self.shutterButton.set_image( Constants.recImg )
+ self.shutterButton.connect("clicked", self.ui._shutterClickCb)
- shutterBox = gtk.EventBox()
- shutterBox.add( self.shutterButton )
- shutterBox.set_size_request( self.ui.controlBarHt, self.ui.controlBarHt )
+ shutterBox = gtk.EventBox()
+ shutterBox.add( self.shutterButton )
+ shutterBox.set_size_request( self.ui.controlBarHt, self.ui.controlBarHt )
- shutterBox.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.shutterButton.modify_bg( gtk.STATE_ACTIVE, Constants.colorBlack.gColor )
+ shutterBox.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.shutterButton.modify_bg( gtk.STATE_ACTIVE, Constants.colorBlack.gColor )
- hbox = gtk.HBox()
- self.add( hbox )
- leftPanel = gtk.VBox()
- self.leftEvent = gtk.EventBox()
- self.leftEvent.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.leftEvent.add( leftPanel )
- self.leftEvent.set_size_request(self.ui.vw/2-self.ui.controlBarHt, -1)
- hbox.pack_start( self.leftEvent, expand=True )
+ hbox = gtk.HBox()
+ self.add( hbox )
+ leftPanel = gtk.VBox()
+ self.leftEvent = gtk.EventBox()
+ self.leftEvent.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.leftEvent.add( leftPanel )
+ self.leftEvent.set_size_request(self.ui.vw/2-self.ui.controlBarHt, -1)
+ hbox.pack_start( self.leftEvent, expand=True )
- hbox.pack_start( shutterBox, expand=False )
+ hbox.pack_start( shutterBox, expand=False )
- rightPanel = gtk.VBox()
- self.rightEvent = gtk.EventBox()
- self.rightEvent.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.rightEvent.add( rightPanel )
- hbox.pack_start( self.rightEvent, expand=True )
+ rightPanel = gtk.VBox()
+ self.rightEvent = gtk.EventBox()
+ self.rightEvent.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.rightEvent.add( rightPanel )
+ hbox.pack_start( self.rightEvent, expand=True )
- self.rightPanelLabel = gtk.Label()
- rightPanel.pack_start( self.rightPanelLabel )
+ self.rightPanelLabel = gtk.Label()
+ rightPanel.pack_start( self.rightPanelLabel )
- def updateCountdown(self, num):
- if(num>0):
- if (num != self.num):
- ok = self.getCairoCountdown(num)
- self.shutterButton.set_image(ok)
- self.num = num
- else:
- self.num = -1
+ def updateCountdown(self, num):
+ if(num>0):
+ if (num != self.num):
+ ok = self.getCairoCountdown(num)
+ self.shutterButton.set_image(ok)
+ self.num = num
+ else:
+ self.num = -1
- def getCairoCountdown(self, num):
- return Constants.countdownImgs[int(num)]
+ def getCairoCountdown(self, num):
+ return Constants.countdownImgs[int(num)]
- def minimize( self ):
- self.leftEvent.set_size_request(-1, -1)
- self.rightEvent.set_size_request(-1, -1)
+ def minimize( self ):
+ self.leftEvent.set_size_request(-1, -1)
+ self.rightEvent.set_size_request(-1, -1)
- def maximize( self ):
- w = self.ui.vw/2-self.ui.controlBarHt
- self.rightEvent.set_size_request(w, -1)
- self.leftEvent.set_size_request(w, -1)
+ def maximize( self ):
+ w = self.ui.vw/2-self.ui.controlBarHt
+ self.rightEvent.set_size_request(w, -1)
+ self.leftEvent.set_size_request(w, -1)
- def displayDiscFullText( self, full ):
- if (not full or self.ui.ca.m.MODE != Constants.MODE_PHOTO):
- self.rightPanelLabel.set_text("")
- self.minimize()
- else:
- fullMessage = Constants.istrYourDiskIsFull % {"1":Constants.istrJournal}
- self.rightPanelLabel.set_text("<b><span foreground='gray'>" + fullMessage + "</span></b>")
- self.rightPanelLabel.set_use_markup( True )
- self.rightPanelLabel.set_alignment(1, 1)
- self.maximize()
+ def displayDiscFullText( self, full ):
+ if (not full or self.ui.ca.m.MODE != Constants.MODE_PHOTO):
+ self.rightPanelLabel.set_text("")
+ self.minimize()
+ else:
+ fullMessage = Constants.istrYourDiskIsFull % {"1":Constants.istrJournal}
+ self.rightPanelLabel.set_text("<b><span foreground='gray'>" + fullMessage + "</span></b>")
+ self.rightPanelLabel.set_use_markup( True )
+ self.rightPanelLabel.set_alignment(1, 1)
+ self.maximize()
class ProgressWindow(gtk.Window):
- def __init__(self, ui):
- gtk.Window.__init__(self)
- self.ui = ui
- self.update = ""
-
- self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
-
- eb = gtk.EventBox()
- eb.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- eb.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
- self.add( eb )
-
- vb = gtk.VBox()
- vb.set_border_width(5) #todo: use variable
- eb.add(vb)
-
- self.progBar = gtk.ProgressBar()
- self.progBar.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
- self.progBar.modify_bg( gtk.STATE_ACTIVE, Constants.colorBlack.gColor )
- self.progBar.modify_bg( gtk.STATE_PRELIGHT, Constants.colorBlack.gColor )
- self.progBar.modify_bg( gtk.STATE_SELECTED, Constants.colorBlack.gColor )
- self.progBar.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
- vb.add( self.progBar )
-
- hbox = gtk.HBox()
- vb.add( hbox )
- self.infoLabel = gtk.Label()
- self.infoLabel.set_alignment( 1, .5 )
- self.infoLabel.set_text( "<b><span foreground='black'>SPACE</span></b>")
- self.infoLabel.set_use_markup( True )
- hbox.pack_start(self.infoLabel)
-
-
- def updateProgress( self, amt, update, color='white' ):
- self.progBar.set_fraction( amt )
- if (update != None and update != self.update):
- self.update = update
- self.infoLabel.set_text( "<b><span foreground='" + color + "'>"+self.update+"</span></b>")
- self.infoLabel.set_use_markup( True )
-
- if (self.update==""):
- self.infoLabel.set_text( "<b><span foreground='black'>SPACE</span></b>")
- self.infoLabel.set_use_markup( True )
-
- if (amt >= 1):
- self.progBar.set_fraction( 0 )
-
-
-class PhotoToolbar(gtk.Toolbar):
- def __init__(self):
- gtk.Toolbar.__init__(self)
+ def __init__(self, ui):
+ gtk.Window.__init__(self)
+ self.ui = ui
+ self.update = ""
- img = ToolButton('media-photo')
- img.connect('clicked', self._shutterClickCb)
- img.get_icon_widget().set_property( 'fill-color', Instance.colorFill.hex )
- img.get_icon_widget().set_property( 'stroke-color', Instance.colorStroke.hex )
- self.insert(img, -1)
- img.set_sensitive(False)
- img.show()
+ self.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
- separator = gtk.SeparatorToolItem()
- separator.set_draw(False)
- separator.set_expand(True)
- self.insert(separator, -1)
- separator.show()
+ eb = gtk.EventBox()
+ eb.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ eb.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
+ self.add( eb )
- timerCbb = gtk.combo_box_new_text()
- self.timerCb = ToolComboBox(combo=timerCbb, label_text=Constants.istrTimer)
- for i in range (0, len(Constants.TIMERS)):
- if (i == 0):
- self.timerCb.combo.append_text( Constants.istrNow )
- else:
- self.timerCb.combo.append_text( Constants.istrSeconds % {"1":(str(Constants.TIMERS[i]))} )
- self.timerCb.combo.set_active(0)
- self.insert( self.timerCb, -1 )
+ vb = gtk.VBox()
+ vb.set_border_width(5) #todo: use variable
+ eb.add(vb)
+ self.progBar = gtk.ProgressBar()
+ self.progBar.modify_bg( gtk.STATE_NORMAL, Constants.colorBlack.gColor )
+ self.progBar.modify_bg( gtk.STATE_ACTIVE, Constants.colorBlack.gColor )
+ self.progBar.modify_bg( gtk.STATE_PRELIGHT, Constants.colorBlack.gColor )
+ self.progBar.modify_bg( gtk.STATE_SELECTED, Constants.colorBlack.gColor )
+ self.progBar.modify_bg( gtk.STATE_INSENSITIVE, Constants.colorBlack.gColor )
+ vb.add( self.progBar )
- def _shutterClickCb(self, button):
- pass
- #self.ui.doShutter()
+ hbox = gtk.HBox()
+ vb.add( hbox )
+ self.infoLabel = gtk.Label()
+ self.infoLabel.set_alignment( 1, .5 )
+ self.infoLabel.set_text( "<b><span foreground='black'>SPACE</span></b>")
+ self.infoLabel.set_use_markup( True )
+ hbox.pack_start(self.infoLabel)
- def getTimer(self):
- return Constants.TIMERS[self.timerCb.combo.get_active()]
+ def updateProgress( self, amt, update, color='white' ):
+ logging.debug('updateProgress %s' % amt)
+ self.progBar.set_fraction( amt )
+ if (update != None and update != self.update):
+ self.update = update
+ self.infoLabel.set_text( "<b><span foreground='" + color + "'>"+self.update+"</span></b>")
+ self.infoLabel.set_use_markup( True )
-class VideoToolbar(gtk.Toolbar):
- def __init__(self):
- gtk.Toolbar.__init__(self)
+ if (self.update==""):
+ self.infoLabel.set_text( "<b><span foreground='black'>SPACE</span></b>")
+ self.infoLabel.set_use_markup( True )
- img = ToolButton('media-video')
- img.connect('clicked', self._shutterClickCb)
- img.get_icon_widget().set_property( 'fill-color', Instance.colorFill.hex )
- img.get_icon_widget().set_property( 'stroke-color', Instance.colorStroke.hex )
- self.insert(img, -1)
- img.set_sensitive(False)
- img.show()
+ if (amt >= 1):
+ self.progBar.set_fraction( 0 )
- separator = gtk.SeparatorToolItem()
- separator.set_draw(False)
- separator.set_expand(True)
- self.insert(separator, -1)
- separator.show()
- timerCbb = gtk.combo_box_new_text()
- self.timerCb = ToolComboBox(combo=timerCbb, label_text=Constants.istrTimer)
- for i in range (0, len(Constants.TIMERS)):
- if (i == 0):
- self.timerCb.combo.append_text( Constants.istrNow )
- else:
- self.timerCb.combo.append_text( Constants.istrSeconds % {"1":(str(Constants.TIMERS[i]))} )
- self.timerCb.combo.set_active(0)
- self.insert( self.timerCb, -1 )
+class PhotoToolbar(gtk.Toolbar):
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
- separator2 = gtk.SeparatorToolItem()
- separator2.set_draw(False)
- separator2.set_expand(False)
- separator2.set_size_request(UI.dim_INSET, -1)
- self.insert( separator2, -1 )
+ img = ToolButton('media-photo')
+ img.connect('clicked', self._shutterClickCb)
+ img.get_icon_widget().set_property( 'fill-color', Instance.colorFill.hex )
+ img.get_icon_widget().set_property( 'stroke-color', Instance.colorStroke.hex )
+ self.insert(img, -1)
+ img.set_sensitive(False)
+ img.show()
- durCbb = gtk.combo_box_new_text()
- self.durCb = ToolComboBox(combo=durCbb, label_text=Constants.istrDuration)
- for i in range (0, len(Constants.DURATIONS)):
- self.durCb.combo.append_text( Constants.istrMinutes % {"1":(str(Constants.DURATIONS[i]))} )
- self.durCb.combo.set_active(0)
- self.insert(self.durCb, -1 )
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(False)
+ separator.set_expand(True)
+ self.insert(separator, -1)
+ separator.show()
+ timerCbb = gtk.combo_box_new_text()
+ self.timerCb = ToolComboBox(combo=timerCbb, label_text=Constants.istrTimer)
+ for i in range (0, len(Constants.TIMERS)):
+ if (i == 0):
+ self.timerCb.combo.append_text( Constants.istrNow )
+ else:
+ self.timerCb.combo.append_text( Constants.istrSeconds % {"1":(str(Constants.TIMERS[i]))} )
+ self.timerCb.combo.set_active(0)
+ self.insert( self.timerCb, -1 )
- def _shutterClickCb(self, button):
- pass
- #self.ui.doShutter()
+ def _shutterClickCb(self, button):
+ pass
+ #self.ui.doShutter()
- def getTimer(self):
- return Constants.TIMERS[self.timerCb.combo.get_active()]
+ def getTimer(self):
+ return Constants.TIMERS[self.timerCb.combo.get_active()]
- def getDuration(self):
- return 60 * Constants.DURATIONS[self.durCb.combo.get_active()]
+class VideoToolbar(gtk.Toolbar):
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+
+ img = ToolButton('media-video')
+ img.connect('clicked', self._shutterClickCb)
+ img.get_icon_widget().set_property( 'fill-color', Instance.colorFill.hex )
+ img.get_icon_widget().set_property( 'stroke-color', Instance.colorStroke.hex )
+ self.insert(img, -1)
+ img.set_sensitive(False)
+ img.show()
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(False)
+ separator.set_expand(True)
+ self.insert(separator, -1)
+ separator.show()
+
+ combo = gtk.combo_box_new_text()
+ self.quality = ToolComboBox(combo=combo,
+ label_text=Constants.istrQuality+':')
+ self.quality.combo.append_text(Constants.istrLowQuality)
+ self.quality.combo.append_text(Constants.istrHighQuality)
+ self.quality.combo.append_text(Constants.istrBestQuality)
+ self.quality.combo.set_active(0)
+ self.insert(self.quality, -1 )
+
+ timerCbb = gtk.combo_box_new_text()
+ self.timerCb = ToolComboBox(combo=timerCbb, label_text=Constants.istrTimer)
+ for i in range (0, len(Constants.TIMERS)):
+ if (i == 0):
+ self.timerCb.combo.append_text( Constants.istrNow )
+ else:
+ self.timerCb.combo.append_text( Constants.istrSeconds % {"1":(str(Constants.TIMERS[i]))} )
+ self.timerCb.combo.set_active(0)
+ self.insert( self.timerCb, -1 )
+
+ separator2 = gtk.SeparatorToolItem()
+ separator2.set_draw(False)
+ separator2.set_expand(False)
+ separator2.set_size_request(UI.dim_INSET, -1)
+ self.insert( separator2, -1 )
+
+ durCbb = gtk.combo_box_new_text()
+ self.durCb = ToolComboBox(combo=durCbb, label_text=Constants.istrDuration)
+ for i in range (0, len(Constants.DURATIONS)):
+ self.durCb.combo.append_text( Constants.istrMinutes % {"1":(str(Constants.DURATIONS[i]))} )
+ self.durCb.combo.set_active(0)
+ self.insert(self.durCb, -1 )
+
+
+ def _shutterClickCb(self, button):
+ pass
+ #self.ui.doShutter()
+
+
+ def getTimer(self):
+ return Constants.TIMERS[self.timerCb.combo.get_active()]
+
+
+ def getDuration(self):
+ return 60 * Constants.DURATIONS[self.durCb.combo.get_active()]
+
+
+ def getQuality(self):
+ return self.quality.combo.get_active()
class AudioToolbar(gtk.Toolbar):
- def __init__(self):
- gtk.Toolbar.__init__(self)
-
- img = ToolButton('media-audio')
- img.connect('clicked', self._shutterClickCb)
- img.get_icon_widget().set_property( 'fill-color', Instance.colorFill.hex )
- img.get_icon_widget().set_property( 'stroke-color', Instance.colorStroke.hex )
- self.insert(img, -1)
- img.set_sensitive(False)
- img.show()
-
- separator = gtk.SeparatorToolItem()
- separator.set_draw(False)
- separator.set_expand(True)
- self.insert(separator, -1)
- separator.show()
-
- timerCbb = gtk.combo_box_new_text()
- self.timerCb = ToolComboBox(combo=timerCbb, label_text=Constants.istrTimer)
- for i in range (0, len(Constants.TIMERS)):
- if (i == 0):
- self.timerCb.combo.append_text( Constants.istrNow )
- else:
- self.timerCb.combo.append_text( Constants.istrSeconds % {"1":(str(Constants.TIMERS[i]))} )
- self.timerCb.combo.set_active(0)
- self.insert( self.timerCb, -1 )
-
- separator2 = gtk.SeparatorToolItem()
- separator2.set_draw(False)
- separator2.set_expand(False)
- separator2.set_size_request(UI.dim_INSET, -1)
- self.insert( separator2, -1 )
-
- durCbb = gtk.combo_box_new_text()
- self.durCb = ToolComboBox(combo=durCbb, label_text=Constants.istrDuration)
- for i in range (0, len(Constants.DURATIONS)):
- self.durCb.combo.append_text( Constants.istrMinutes % {"1":(str(Constants.DURATIONS[i]))} )
- self.durCb.combo.set_active(0)
- self.insert(self.durCb, -1 )
-
-
- def _shutterClickCb(self, button):
- pass
- #self.ui.doShutter()
-
-
- def getTimer(self):
- return Constants.TIMERS[self.timerCb.combo.get_active()]
-
-
- def getDuration(self):
- return 60 * Constants.DURATIONS[self.durCb.combo.get_active()]
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+
+ img = ToolButton('media-audio')
+ img.connect('clicked', self._shutterClickCb)
+ img.get_icon_widget().set_property( 'fill-color', Instance.colorFill.hex )
+ img.get_icon_widget().set_property( 'stroke-color', Instance.colorStroke.hex )
+ self.insert(img, -1)
+ img.set_sensitive(False)
+ img.show()
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(False)
+ separator.set_expand(True)
+ self.insert(separator, -1)
+ separator.show()
+
+ timerCbb = gtk.combo_box_new_text()
+ self.timerCb = ToolComboBox(combo=timerCbb, label_text=Constants.istrTimer)
+ for i in range (0, len(Constants.TIMERS)):
+ if (i == 0):
+ self.timerCb.combo.append_text( Constants.istrNow )
+ else:
+ self.timerCb.combo.append_text( Constants.istrSeconds % {"1":(str(Constants.TIMERS[i]))} )
+ self.timerCb.combo.set_active(0)
+ self.insert( self.timerCb, -1 )
+
+ separator2 = gtk.SeparatorToolItem()
+ separator2.set_draw(False)
+ separator2.set_expand(False)
+ separator2.set_size_request(UI.dim_INSET, -1)
+ self.insert( separator2, -1 )
+
+ durCbb = gtk.combo_box_new_text()
+ self.durCb = ToolComboBox(combo=durCbb, label_text=Constants.istrDuration)
+ for i in range (0, len(Constants.DURATIONS)):
+ self.durCb.combo.append_text( Constants.istrMinutes % {"1":(str(Constants.DURATIONS[i]))} )
+ self.durCb.combo.set_active(0)
+ self.insert(self.durCb, -1 )
+
+
+ def _shutterClickCb(self, button):
+ pass
+ #self.ui.doShutter()
+
+
+ def getTimer(self):
+ return Constants.TIMERS[self.timerCb.combo.get_active()]
+
+
+ def getDuration(self):
+ return 60 * Constants.DURATIONS[self.durCb.combo.get_active()]
diff --git a/utils.py b/utils.py
index 7244ab0..e9aa6cf 100644
--- a/utils.py
+++ b/utils.py
@@ -6,113 +6,103 @@ import statvfs
import cairo
import gc
import gtk
-from hashlib import md5
import time
from time import strftime
from sugar import util
-import _camera
+import camerac
def getStringFromPixbuf(pixbuf):
- data = [""]
- pixbuf.save_to_callback(_saveDataToBufferCb, "png", {}, data)
- return base64.b64encode(str(data[0]))
+ data = [""]
+ pixbuf.save_to_callback(_saveDataToBufferCb, "png", {}, data)
+ return base64.b64encode(str(data[0]))
def _saveDataToBufferCb(buf, data):
- data[0] += buf
- return True
+ data[0] += buf
+ return True
def getPixbufFromString(str):
- pbl = gtk.gdk.PixbufLoader()
- data = base64.b64decode( str )
- pbl.write(data)
- pbl.close()
- return pbl.get_pixbuf()
+ pbl = gtk.gdk.PixbufLoader()
+ data = base64.b64decode( str )
+ pbl.write(data)
+ pbl.close()
+ return pbl.get_pixbuf()
def loadSvg( data, stroke, fill ):
- if ((stroke == None) or (fill == None)):
- return rsvg.Handle( data=data )
+ if ((stroke == None) or (fill == None)):
+ return rsvg.Handle( data=data )
- entity = '<!ENTITY fill_color "%s">' % fill
- data = re.sub('<!ENTITY fill_color .*>', entity, data)
+ entity = '<!ENTITY fill_color "%s">' % fill
+ data = re.sub('<!ENTITY fill_color .*>', entity, data)
- entity = '<!ENTITY stroke_color "%s">' % stroke
- data = re.sub('<!ENTITY stroke_color .*>', entity, data)
+ entity = '<!ENTITY stroke_color "%s">' % stroke
+ data = re.sub('<!ENTITY stroke_color .*>', entity, data)
- return rsvg.Handle( data=data )
+ return rsvg.Handle( data=data )
def getUniqueFilepath( path, i ):
- pathOb = os.path.abspath( path )
- newPath = os.path.join( os.path.dirname(pathOb), str( str(i) + os.path.basename(pathOb) ) )
- if (os.path.exists(newPath)):
- i = i + 1
- return getUniqueFilepath( pathOb, i )
- else:
- return os.path.abspath( newPath )
-
-
-def md5File( filepath ):
- md = md5()
- f = file( filepath, 'rb' )
- md.update( f.read() )
- digest = md.hexdigest()
- hash = util.printable_hash(digest)
- return hash
+ pathOb = os.path.abspath( path )
+ newPath = os.path.join( os.path.dirname(pathOb), str( str(i) + os.path.basename(pathOb) ) )
+ if (os.path.exists(newPath)):
+ i = i + 1
+ return getUniqueFilepath( pathOb, i )
+ else:
+ return os.path.abspath( newPath )
def generateThumbnail( pixbuf, scale, thumbw, thumbh ):
- #need to generate thumbnail version here
- thumbImg = cairo.ImageSurface(cairo.FORMAT_ARGB32, thumbw, thumbh)
- tctx = cairo.Context(thumbImg)
- img = _camera.cairo_surface_from_gdk_pixbuf(pixbuf)
- tctx.scale(scale, scale)
- tctx.set_source_surface(img, 0, 0)
- tctx.paint()
- gc.collect()
- return thumbImg
+ #need to generate thumbnail version here
+ thumbImg = cairo.ImageSurface(cairo.FORMAT_ARGB32, thumbw, thumbh)
+ tctx = cairo.Context(thumbImg)
+ img = camerac.cairo_surface_from_gdk_pixbuf(pixbuf)
+ tctx.scale(scale, scale)
+ tctx.set_source_surface(img, 0, 0)
+ tctx.paint()
+ gc.collect()
+ return thumbImg
def scaleSvgToDim( handle, dim ):
- #todo...
- scale = 1.0
+ #todo...
+ scale = 1.0
- svgDim = handle.get_dimension_data()
- if (svgDim[0] > dim[0]):
- pass
+ svgDim = handle.get_dimension_data()
+ if (svgDim[0] > dim[0]):
+ pass
- return scale
+ return scale
def getDateString( when ):
- return strftime( "%a, %b %d, %I:%M:%S %p", time.localtime(when) )
+ return strftime( "%a, %b %d, %I:%M:%S %p", time.localtime(when) )
def grayScalePixBuf2( pb, copy ):
- arr = pb.get_pixels_array()
- if (copy):
- arr = arr.copy()
- for row in arr:
- for pxl in row:
- y = 0.3*pxl[0][0]+0.59*pxl[1][0]+0.11*pxl[2][0]
- pxl[0][0] = y
- pxl[1][0] = y
- pxl[2][0] = y
- return gtk.gdk.pixbuf_new_from_array(arr, pb.get_colorspace(), pb.get_bits_per_sample())
+ arr = pb.get_pixels_array()
+ if (copy):
+ arr = arr.copy()
+ for row in arr:
+ for pxl in row:
+ y = 0.3*pxl[0][0]+0.59*pxl[1][0]+0.11*pxl[2][0]
+ pxl[0][0] = y
+ pxl[1][0] = y
+ pxl[2][0] = y
+ return gtk.gdk.pixbuf_new_from_array(arr, pb.get_colorspace(), pb.get_bits_per_sample())
def grayScalePixBuf( pb, copy ):
- pb2 = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, pb.get_width(), pb.get_height())
- pb.saturate_and_pixelate(pb2, 0, 0)
- return pb2
+ pb2 = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, pb.get_width(), pb.get_height())
+ pb.saturate_and_pixelate(pb2, 0, 0)
+ return pb2
def getFreespaceKb( ):
- stat = os.statvfs("/home")
- freebytes = stat[statvfs.F_BSIZE] * stat[statvfs.F_BAVAIL]
- freekb = freebytes / 1024
- return freekb
+ stat = os.statvfs("/home")
+ freebytes = stat[statvfs.F_BSIZE] * stat[statvfs.F_BAVAIL]
+ freekb = freebytes / 1024
+ return freekb