[xiph-commits] r3210 - in arkaiv/trunk: . arkaiv/controllers
arkaiv/model arkaiv/templates data/templates
dcrowdy at svn.annodex.net
dcrowdy at svn.annodex.net
Wed Aug 29 17:30:37 PDT 2007
Author: dcrowdy
Date: 2007-08-29 17:30:37 -0700 (Wed, 29 Aug 2007)
New Revision: 3210
Added:
arkaiv/trunk/arkaiv/model/framer.py
Modified:
arkaiv/trunk/README.txt
arkaiv/trunk/TODO
arkaiv/trunk/arkaiv/controllers/page.py
arkaiv/trunk/arkaiv/controllers/page.pyc
arkaiv/trunk/arkaiv/templates/displayitem.mak
arkaiv/trunk/data/templates/displayitem.mak.py
arkaiv/trunk/data/templates/displayitem.mak.pyc
Log:
Improved clip frame creation - now using Frame class from cmmlwiki; removed previous mplayer implementation of this.
Modified: arkaiv/trunk/README.txt
===================================================================
--- arkaiv/trunk/README.txt 2007-08-29 12:28:49 UTC (rev 3209)
+++ arkaiv/trunk/README.txt 2007-08-30 00:30:37 UTC (rev 3210)
@@ -10,11 +10,11 @@
The python build tools for your distribution.
python-lxml
sqlite3
+Python gst (0.10)
Recent annodex libraries - including python-annodex and mod_annodex for apache
- see http://www.annodex.net
-
Pylons 0.9.6
AuthKit 0.3.0pre5
SQLAlchemy 0.3.10
@@ -34,6 +34,8 @@
INSTALLATION
+Only tested under linux so far.
+
Unpack the tarball, enter the directory, and edit production.ini to suit your
environment. At the moment the media files are kept in /var/www/arkaiv, so
you'll need to make sure that directory exists, and that you have write
Modified: arkaiv/trunk/TODO
===================================================================
--- arkaiv/trunk/TODO 2007-08-29 12:28:49 UTC (rev 3209)
+++ arkaiv/trunk/TODO 2007-08-30 00:30:37 UTC (rev 3210)
@@ -1,9 +1,10 @@
TODO
+When going to an item from a clip link on the search results page, any
+subsequent attempts to jump to clips fail. Fix.
+
Better screen layout in the main display page needed
-Clips should have an image generated for the link display
-
Just been at a coding gathering at Silvia Pfeiffer's house, and Marcin Lubonski
suggested it'd be good to be able to locally annotate remote media. A feature
well worth considering. The idea of leaving the media files in their original
@@ -20,6 +21,10 @@
DONE
+Thu Aug 30 09:43:10 EST 2007
+
+Clips should have an image generated for the link display
+
Mon Aug 27 11:09:20 EST 2007
Should really rename anxParser to cmmlParser, as that is what it is...
Modified: arkaiv/trunk/arkaiv/controllers/page.py
===================================================================
--- arkaiv/trunk/arkaiv/controllers/page.py 2007-08-29 12:28:49 UTC (rev 3209)
+++ arkaiv/trunk/arkaiv/controllers/page.py 2007-08-30 00:30:37 UTC (rev 3210)
@@ -26,6 +26,7 @@
from arkaiv.model.oggzinfo import OggzInfo
#from arkaiv.model.anxparser import anxParser
from arkaiv.model.cmmlparser import cmmlParser
+from arkaiv.model.framer import Frame
log = logging.getLogger(__name__)
@@ -229,24 +230,16 @@
if has_video == "Yes":
basename = os.path.splitext(cmmlfile)[0]
imagedirname = basename + "_clipimages"
-
+ clipimagename = str(clip['starttime']) + ".png"
oggsource = model.getsourcepath(clip['itemid'])
-
- # create an image using mplayer
- cmd = "mplayer -vo png:z=6 -vf scale -zoom -xy 96 -ao null -ss '" + str(clip['starttime']) + "' -frames 2 " + oggsource
cwd = os.getcwd()
- os.chdir(imagedirname)
-
- runit = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE
- , stderr=subprocess.PIPE)
- out, err = runit.communicate()
- # and the file we want will be called 00000002.png...
- # so rename to something more descriptive
- clipimagename = str(clip['starttime']) + ".png"
- shutil.move("00000002.png", clipimagename)
- os.chdir(cwd) # very ugly... better image creation needed allround really.
-
- # add that info to the dictionary - only needs to be a relative location
+ os.chdir(imagedirname) # ugly...
+ frameimage = Frame(oggsource, clip['starttime'], clipimagename)
+ os.chdir(cwd) # very ugly... #
+
+ # add that info to the dictionary - only needs to be a relative
+ # location
+
relpath = os.path.split(imagedirname)[1]
clip['img_src'] = relpath + "/" + clipimagename
else:
Modified: arkaiv/trunk/arkaiv/controllers/page.pyc
===================================================================
(Binary files differ)
Added: arkaiv/trunk/arkaiv/model/framer.py
===================================================================
--- arkaiv/trunk/arkaiv/model/framer.py (rev 0)
+++ arkaiv/trunk/arkaiv/model/framer.py 2007-08-30 00:30:37 UTC (rev 3210)
@@ -0,0 +1,152 @@
+# -*- coding: iso8859-1 -*-
+#
+# Copyright (C) 2005 CSIRO Australia All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which you should
+# have received as part of this distribution.
+#
+# This software consists of voluntary contributions made by many individuals.
+# For exact contribution history, see the revision history and logs.
+#
+# Author: Conrad Parker <conrad at annodex.net>
+
+# This class is originally from cmmliki. Modified very slightly for use in
+# arkaiv by Denis Crowdy
+
+import sys
+import os
+import shutil
+
+# Depends on GStreamer 0.10
+# Set to False if gst0.10 is not available, in which case it will
+# fall back to mplayer (which must be installed and capable of decoding
+# theora and generating png).
+# GStreamer tends to have more accurate frame seeking, hence it is
+# enabled by default.
+#FIXME: does not return an image if seeking beond eof
+#use_gst=True
+
+default_width=60
+
+class snapshot_gst:
+ getShot = False
+ def __init__ (self, source, png_frame, seconds):
+ global Image, pygst, gst
+ import Image
+ import pygst
+ pygst.require('0.10')
+ import gst
+
+ self.png_frame = png_frame
+
+ nseconds = int(seconds * gst.SECOND)
+ s = '''filesrc name=input
+ ! decodebin name=dbin
+ ! queue name=q
+ ! ffmpegcolorspace ! video/x-raw-rgb
+ ! fakesink name=output signal-handoffs=true'''
+ pipeline = gst.parse_launch (s)
+
+ input = pipeline.get_by_name ('input')
+ input.set_property ("location", source)
+
+ output = pipeline.get_by_name ('output')
+ output.connect ("handoff", self.snapshot_handoff_cb)
+
+ pipeline.set_state (gst.STATE_PAUSED)
+ pipeline.get_state ()
+
+ #length
+ length = 0
+ queue = pipeline.get_by_name('q')
+ pads = queue.sink_pads()
+ q = gst.query_new_duration(gst.FORMAT_TIME)
+ for pad in pads:
+ if pad.get_peer() and pad.get_peer().query(q):
+ format, length = q.parse_duration()
+
+ #show first frame if seekpoint is higher than length
+ if(length and length < nseconds):
+ nseconds = 0
+
+ #seek
+ event = gst.event_new_seek(1.0, gst.FORMAT_TIME,
+ gst.SEEK_FLAG_FLUSH,
+ gst.SEEK_TYPE_SET, nseconds,
+ gst.SEEK_TYPE_NONE, 0)
+ res = output.send_event(event)
+ if res:
+ pipeline.set_new_stream_time(0L)
+
+ pipeline.set_state (gst.STATE_PLAYING)
+ pipeline.get_state ()
+
+ bus = pipeline.get_bus ()
+
+ #get snapshot
+ self.getShot = True
+ while self.getShot:
+ msg = bus.poll (gst.MESSAGE_ANY, gst.SECOND)
+ if not msg:
+ break
+
+ pipeline.set_state (gst.STATE_NULL)
+
+
+ def scaleto (self, size_max, width, height):
+ if width > height:
+ a = float(height)/width
+ width = size_max
+ height = int(width * a)
+ else:
+ a = float(width)/height
+ height = size_max
+ width = int(height * a)
+ return (width, height)
+
+
+ def snapshot_handoff_cb (self, sink, buffer, pad):
+ if self.getShot:
+ caps = sink.sink_pads().next().get_negotiated_caps()
+ for s in caps:
+ input_d = (s['width'], s['height'])
+ output_d = self.scaleto (default_width, s['width'], s['height'])
+ img = Image.fromstring('RGB',input_d,buffer)
+ img = img.resize(output_d, Image.BICUBIC)
+ img.save(self.png_frame)
+ self.getShot=False
+
+def snapshot_mplayer(source, png_frame, timestamp):
+ framedir = os.tempnam()
+ os.mkdir(framedir)
+ os.chdir(framedir)
+ cmd = "mplayer -vo png:z=6 -vf scale -zoom -xy %d -ao null -ss '%s' -frames 2 \"%s\" >/dev/null 2>&1" % (default_width, timestamp, source)
+ os.system (cmd)
+ files = os.listdir(framedir)
+ os.rename(os.path.join(framedir,files[-1]), png_frame)
+ shutil.rmtree(framedir)
+
+def snapshot (source, png_frame, timestamp):
+ snapshot_gst (source, png_frame, timestamp)
+
+class Frame(object):
+
+ def __init__(self, source, timestamp, png_frame):
+ snapshot (source, png_frame, timestamp)
+ self.png_frame = png_frame
+
+ def content_type (self):
+ return 'image/png'
+
+ def last_modified(self):
+ source = self.inspector.ixi2source(self.ixi)
+ s = os.stat(source)
+ return epoch2httpdate(s.st_mtime)
+
+ def __str__(self):
+
+ f = open(self.png_frame,'rb')
+ i = f.read()
+ f.close()
+
+ return i
Modified: arkaiv/trunk/arkaiv/templates/displayitem.mak
===================================================================
--- arkaiv/trunk/arkaiv/templates/displayitem.mak 2007-08-29 12:28:49 UTC (rev 3209)
+++ arkaiv/trunk/arkaiv/templates/displayitem.mak 2007-08-30 00:30:37 UTC (rev 3210)
@@ -144,7 +144,12 @@
</tr>
% for clipinfo in c.cliplist:
<tr>
+% if c.sourcedict['has_video'] == "Yes":
<td><a onclick="javascript:SetLocation('${c.sourcedict['urlpath']}?id=${clipinfo['id']}')"><img src="${c.sourcedict['clipimageurl']}${clipinfo['img_src']}"></a></td>
+% endif
+% if c.sourcedict['has_video'] == "No":
+ <td><a onclick="javascript:SetLocation('${c.sourcedict['urlpath']}?id=${clipinfo['id']}')"><img src="/public/blank.png"></a></td>
+% endif
<td>${clipinfo['start_time']}</td>
<td>${clipinfo['id']}</td>
<td>${clipinfo['desc']}</td>
Modified: arkaiv/trunk/data/templates/displayitem.mak.py
===================================================================
--- arkaiv/trunk/data/templates/displayitem.mak.py 2007-08-29 12:28:49 UTC (rev 3209)
+++ arkaiv/trunk/data/templates/displayitem.mak.py 2007-08-30 00:30:37 UTC (rev 3210)
@@ -1,7 +1,7 @@
from mako import runtime, filters, cache
UNDEFINED = runtime.UNDEFINED
_magic_number = 2
-_modified_time = 1188390221.0295939
+_modified_time = 1188430842.531039
_template_filename='/home/dcrowdy/src/working/test/arkaiv/trunk/arkaiv/templates/displayitem.mak'
_template_uri='/displayitem.mak'
_template_cache=cache.Cache(__name__, _modified_time)
@@ -140,78 +140,90 @@
# SOURCE LINE 145
for clipinfo in c.cliplist:
# SOURCE LINE 146
- context.write(u'<tr>\n <td><a onclick="javascript:SetLocation(\'')
+ context.write(u'<tr>\n')
# SOURCE LINE 147
- context.write(unicode(c.sourcedict['urlpath']))
- context.write(u'?id=')
- context.write(unicode(clipinfo['id']))
- context.write(u'\')"><img src="')
- context.write(unicode(c.sourcedict['clipimageurl']))
- context.write(unicode(clipinfo['img_src']))
- context.write(u'"></a></td>\n <td>')
- # SOURCE LINE 148
+ if c.sourcedict['has_video'] == "Yes":
+ # SOURCE LINE 148
+ context.write(u' <td><a onclick="javascript:SetLocation(\'')
+ context.write(unicode(c.sourcedict['urlpath']))
+ context.write(u'?id=')
+ context.write(unicode(clipinfo['id']))
+ context.write(u'\')"><img src="')
+ context.write(unicode(c.sourcedict['clipimageurl']))
+ context.write(unicode(clipinfo['img_src']))
+ context.write(u'"></a></td>\n')
+ # SOURCE LINE 150
+ if c.sourcedict['has_video'] == "No":
+ # SOURCE LINE 151
+ context.write(u' <td><a onclick="javascript:SetLocation(\'')
+ context.write(unicode(c.sourcedict['urlpath']))
+ context.write(u'?id=')
+ context.write(unicode(clipinfo['id']))
+ context.write(u'\')"><img src="/public/blank.png"></a></td>\n')
+ # SOURCE LINE 153
+ context.write(u' <td>')
context.write(unicode(clipinfo['start_time']))
context.write(u'</td>\n <td>')
- # SOURCE LINE 149
+ # SOURCE LINE 154
context.write(unicode(clipinfo['id']))
context.write(u'</td>\n <td>')
- # SOURCE LINE 150
+ # SOURCE LINE 155
context.write(unicode(clipinfo['desc']))
context.write(u'</td>\n <td>')
- # SOURCE LINE 151
+ # SOURCE LINE 156
context.write(unicode(clipinfo['a_href']))
context.write(u'</td>\n\n\n')
- # SOURCE LINE 154
+ # SOURCE LINE 159
context.write(unicode( h.form(h.url(action='deleteclip'), multipart=True) ))
context.write(u'\n<td>')
- # SOURCE LINE 155
+ # SOURCE LINE 160
context.write(unicode( h.submit('Delete') ))
context.write(u' </td>\n')
- # SOURCE LINE 156
+ # SOURCE LINE 161
context.write(unicode( h.hidden_field('clipid', value=clipinfo['ixc']) ))
context.write(u'\n')
- # SOURCE LINE 157
+ # SOURCE LINE 162
context.write(unicode( h.hidden_field('itemid', value=c.itemid) ))
context.write(u'\n')
- # SOURCE LINE 158
+ # SOURCE LINE 163
context.write(unicode( h.end_form() ))
context.write(u' \n\n\n</tr> \n')
- # SOURCE LINE 163
+ # SOURCE LINE 168
context.write(u'</table>\n\nAdd new clip:\n')
- # SOURCE LINE 166
+ # SOURCE LINE 171
context.write(unicode( h.form(h.url(action='addclip'), multipart=True) ))
context.write(u'\n<table style="font-size:small">\n<tr>\n <td>Start time</td>\n <td>')
- # SOURCE LINE 170
+ # SOURCE LINE 175
context.write(unicode( h.text_field('starttime', size=5) ))
context.write(u'</td>\n <td>a_text</td>\n <td>')
- # SOURCE LINE 172
+ # SOURCE LINE 177
context.write(unicode( h.text_field('a_text') ))
context.write(u'</td>\n</tr>\n<tr>\n <td>Id</td>\n <td>')
- # SOURCE LINE 176
+ # SOURCE LINE 181
context.write(unicode( h.text_field('id', size=5) ))
context.write(u'</td>\n <td>a_href</td>\n <td>')
- # SOURCE LINE 178
+ # SOURCE LINE 183
context.write(unicode( h.text_field('a_href') ))
context.write(u'</td>\n</tr>\n<tr>\n <td>img_src</td>\n <td>')
- # SOURCE LINE 182
+ # SOURCE LINE 187
context.write(unicode( h.text_field('img_src', size=5) ))
context.write(u'</td>\n <td>desc</td>\n <td>')
- # SOURCE LINE 184
+ # SOURCE LINE 189
context.write(unicode( h.text_field('desc') ))
context.write(u'</td>\n</tr>\n</table>\n')
- # SOURCE LINE 187
+ # SOURCE LINE 192
context.write(unicode( h.hidden_field('headindex', value = c.headdict['ixh']) ))
context.write(u'\n')
- # SOURCE LINE 188
+ # SOURCE LINE 193
context.write(unicode( h.hidden_field('itemid', value=c.itemid) ))
context.write(u'\n')
- # SOURCE LINE 189
+ # SOURCE LINE 194
context.write(unicode( h.hidden_field('hasvideo', value=c.sourcedict['has_video']) ))
context.write(u'\n\n')
- # SOURCE LINE 191
+ # SOURCE LINE 196
context.write(unicode( h.submit('Add') ))
context.write(u' \n')
- # SOURCE LINE 192
+ # SOURCE LINE 197
context.write(unicode( h.end_form() ))
context.write(u' \n</div>\n<script>\nvar plugin = document.embeds[0];\nvar input = document.api.ifield;\nvar goto = document.api.gotofield;\nvar output = document.api.ofield;\n\nfunction Play() {\n plugin.play();\n addOutput("Play!");\n}\n\nfunction Pause() {\n plugin.pause();\n addOutput("Pause!");\n}\n\nfunction SetLocation(location) {\n// plugin.setPlayPosition(location);\n plugin.setCurrentMovie(location);\n addOutput("Current movie: " + plugin.getCurrentMovie());\n addOutput("setting a location: " + location + " ms");\n}\n\nfunction GetPlayPosition() {\n addOutput("Play position: " + plugin.getPlayPosition() + " ms");\n}\n\nfunction skip(dir) {\n// addOutput("we get here")\n i = getInput();\n addOutput("i is " + i);\n if (i <= 0) i = 1000;\n addOutput("dir is " + dir);\n t = plugin.getPlayPosition() + (i * dir);\n addOutput("t is " + t);\n addOutput("Skipping by " + i + " to " + t + " ms - " +\n (plugin.setPlayPositi
on(t) ? "succeeded" : "failed"));\n}\n\nfunction getInput() {\n i = parseInt(input.value);\n return isNaN(i) ? 0 : i;\n}\n\nfunction getGoto() {\n i = parseInt(goto.value);\n return isNaN(i) ? 0 : i;\n}\n\n\nfunction GotoPosition() {\n i = getGoto();\n i = i * 1000;\n plugin.setPlayPosition(i);\n}\n\nvar outLines = 0;\n\nfunction addOutput(str) {\n if (outLines == 0) {\n output.value = str;\n } else {\n output.value = str + "\\n" + output.value;\n }\n outLines++;\n if (outLines == 11) {\n i = output.value.lastIndexOf("\\n");\n output.value = output.value.substr(0, i);\n outLines--;\n }\n}\n</script>\n\n')
return ''
Modified: arkaiv/trunk/data/templates/displayitem.mak.pyc
===================================================================
(Binary files differ)
More information about the commits
mailing list