[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