poster still

This commit is contained in:
j 2007-07-18 11:21:01 +00:00
parent 894d0399f0
commit cf952f05cf
5 changed files with 154 additions and 15 deletions

View file

@ -56,3 +56,11 @@ def loadTimeline(afile):
if exists(timeline): if exists(timeline):
return loadFile(timeline) return loadFile(timeline)
return '' return ''
def loadPosterStill(afile, position):
still = afile.posterStillFile
if not exists(still):
afile.extractPosterStill(position)
if exsts(still):
return loadFile(still)
return ''

View file

@ -46,4 +46,8 @@ class Root(controllers.RootController):
cherrypy.response.headerMap['Content-Type'] = "image/jpeg" cherrypy.response.headerMap['Content-Type'] = "image/jpeg"
cherrypy.response.headerMap["Expires"] = httpExpires(60*60*24*15) cherrypy.response.headerMap["Expires"] = httpExpires(60*60*24*15)
return f.frame(position) return f.frame(position)
elif action == 'posterStill':
cherrypy.response.headerMap['Content-Type'] = "image/png"
cherrypy.response.headerMap["Expires"] = httpExpires(60*60*24*15)
return f.posterStill(position)
return dict() return dict()

View file

@ -305,15 +305,16 @@ class ArchiveFile(SQLObject):
def updateMeta(self): def updateMeta(self):
self.findSubtitleLink() self.findSubtitleLink()
if exists(self.absolutePath): if exists(self.absolutePath):
info = midentify.identify(self.absolutePath) if not self.broken:
self.length = info['length'] info = midentify.identify(self.absolutePath)
self.width = info['width'] self.length = info['length']
self.frameAspect = "%0.6f" % info['aspect'] self.width = info['width']
self.height = info['height'] self.frameAspect = "%0.6f" % info['aspect']
self.bitrate = info['video_bitrate'] self.height = info['height']
self.fps = info['fps'] self.bitrate = info['video_bitrate']
self.audio = info['audio_codec'] self.fps = info['fps']
self.video = info['video_codec'] self.audio = info['audio_codec']
self.video = info['video_codec']
self.updatePixels() self.updatePixels()
self.updateBpp() self.updateBpp()
self.loadSubtitleFromFile() self.loadSubtitleFromFile()
@ -377,7 +378,7 @@ class ArchiveFile(SQLObject):
def _get_mini_movie_file(self): def _get_mini_movie_file(self):
return join(cache.cache_root, 'mini', self.md5sum[:4], "%s.avi" % self.md5sum) return join(cache.cache_root, 'mini', self.md5sum[:4], "%s.avi" % self.md5sum)
def _get_frameFolder(self): def _get_frameFolder(self):
f = join(cache.cache_root, 'frame', self.md5sum[:4], self.md5sum) f = join(cache.cache_root, 'frame', self.md5sum[:4], self.md5sum)
oxdb_makedir(f) oxdb_makedir(f)
@ -385,7 +386,10 @@ class ArchiveFile(SQLObject):
def _get_timelineFile(self): def _get_timelineFile(self):
return join(cache.cache_root, 'timeline', self.md5sum[:4], "%s.png" % self.md5sum) return join(cache.cache_root, 'timeline', self.md5sum[:4], "%s.png" % self.md5sum)
def _get_posterStillFile(self):
return join(cache.cache_root, 'posterStill', self.md5sum[:4], "%s.png" % self.md5sum)
def removeMiniMovie(self): def removeMiniMovie(self):
if exists(self.mini_movie_file): if exists(self.mini_movie_file):
os.remove(self.mini_movie_file) os.remove(self.mini_movie_file)
@ -458,6 +462,9 @@ class ArchiveFile(SQLObject):
for p in self._startPoints(): for p in self._startPoints():
self.extractFrame(p) self.extractFrame(p)
def extractPosterStill(self, position, img_folder=):
extract_poster_still(self.movieFile, self.posterStillFile, position)
def extractClipMovie(self, force = False): def extractClipMovie(self, force = False):
if self.broken: if self.broken:
return return
@ -485,8 +492,7 @@ class ArchiveFile(SQLObject):
cmd = "mencoder %s >/dev/null 2>&1" % options cmd = "mencoder %s >/dev/null 2>&1" % options
print cmd.encode('utf-8') print cmd.encode('utf-8')
os.system(cmd.encode('utf-8')) os.system(cmd.encode('utf-8'))
def removeTimeline(self): def removeTimeline(self):
if exists(self.timelineFile): if exists(self.timelineFile):
os.unlink(self.timelineFile) os.unlink(self.timelineFile)
@ -582,3 +588,6 @@ class ArchiveFile(SQLObject):
def timeline(self): def timeline(self):
return cache.loadTimeline(self) return cache.loadTimeline(self)
def posterStill(self, position):
return cache.loadPosterStill(self, position)

View file

@ -219,8 +219,18 @@ def extract_frame(movie_file, timestamp, img_folder, width=128, offset = 0, redo
else: else:
print "update the cache %s missing" % movie_file print "update the cache %s missing" % movie_file
shutil.rmtree(framedir) shutil.rmtree(framedir)
def extract_poster_still(movie_file, png_file, inpoint):
ext = movie_file.split('.')[-1]
if ext in ('sub', 'srt'):
print "this is not a movie file, will not try to extract frames"
return
inpoint = time_str2msec(inpoint)
extractClipScript = abspath(join(dirname(__file__), "tools/extract_poster_still.py"))
cmd = '''%s "%s" "%s" %s''' % (extractClipScript, movie_file, png_file, inpoint)
os.system(cmd.encode('utf-8'))
def extract_subtitles(movie_file, srt, img_folder, width=128, offset = 0, redo = False): def extract_subtitles(movie_file, srt, img_folder, width=128, offset = 0, redo = False):
subtitles = srt2dict(srt) subtitles = srt2dict(srt)
for k in sorted([int(k) for k in subtitles.keys()]): for k in sorted([int(k) for k in subtitles.keys()]):

View file

@ -0,0 +1,108 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# -*- Mode: Python; -*-
# vi:si:et:sw=2:sts=2:ts=2
#
import os
import time
import gobject
gobject.threads_init()
import pygst
pygst.require("0.10")
import gst
import Image
class PosterStill:
getShot = False
length = 0
height = 0
def __init__(self, videofile, png='', nseconds=-1, height=128):
s = ''' filesrc name=input
! decodebin name=dbin
! queue name =q
! ffmpegcolorspace ! video/x-raw-rgb
! fakesink name=output signal-handoffs=true
'''
self.height = height
self.pipeline = gst.parse_launch(s)
self.input = self.pipeline.get_by_name('input')
self.fakesink = self.pipeline.get_by_name('output')
self.dbin = self.pipeline.get_by_name('dbin')
self.bus = self.pipeline.get_bus()
self.input.props.location = videofile
self.pipeline.set_state(gst.STATE_PAUSED)
self.pipeline.get_state()
#length
queue = self.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, self.length = q.parse_duration()
if nseconds>-1 and png:
self.png(png, nseconds)
def close(self):
self.pipeline.set_state(gst.STATE_NULL)
self.pipeline.get_state()
def seek(self, nseconds):
if(self.length and self.length < nseconds):
nseconds = 0
event = gst.event_new_seek(1.0, gst.FORMAT_TIME,
gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE,
gst.SEEK_TYPE_SET, nseconds,
gst.SEEK_TYPE_NONE, 0)
res = self.fakesink.send_event(event)
if res:
self.pipeline.set_new_stream_time(0L)
else:
gst.error("seek to %r failed" % nseconds)
def png(self, png, nseconds):
self.png_frame = png
self.pipeline.set_state(gst.STATE_PAUSED)
self.pipeline.get_state()
self.seek(nseconds)
self.pipeline.set_state(gst.STATE_PLAYING)
self.pipeline.get_state()
ho = self.fakesink.connect("handoff", self.snapshot_png_handoff_cb)
self.getShot = True
while self.getShot:
msg = self.bus.poll(gst.MESSAGE_ANY, gst.SECOND)
if not msg:
break
self.fakesink.disconnect(ho)
def snapshot_png_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(s['width'], s['height'])
img = Image.fromstring('RGB',input_d,buffer)
img = img.resize(output_d, Image.ANTIALIAS)
img.save(self.png_frame)
self.getShot=False
def scaleto(self, width, height):
width = int(self.height * (float(width) / height))
width = width - width%2
self.width = width
return (self.width, self.height)
if __name__ == "__main__":
import sys
height = 128
inputFile = sys.argv[1]
outputFile = sys.argv[2]
offset = int(float(sys.argv[3]) * gst.MSECOND)
f = PosterStill(inputFile, outputFile, offset, height)