poster still
This commit is contained in:
parent
894d0399f0
commit
cf952f05cf
5 changed files with 154 additions and 15 deletions
|
@ -56,3 +56,11 @@ def loadTimeline(afile):
|
|||
if exists(timeline):
|
||||
return loadFile(timeline)
|
||||
return ''
|
||||
|
||||
def loadPosterStill(afile, position):
|
||||
still = afile.posterStillFile
|
||||
if not exists(still):
|
||||
afile.extractPosterStill(position)
|
||||
if exsts(still):
|
||||
return loadFile(still)
|
||||
return ''
|
||||
|
|
|
@ -46,4 +46,8 @@ class Root(controllers.RootController):
|
|||
cherrypy.response.headerMap['Content-Type'] = "image/jpeg"
|
||||
cherrypy.response.headerMap["Expires"] = httpExpires(60*60*24*15)
|
||||
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()
|
|
@ -305,6 +305,7 @@ class ArchiveFile(SQLObject):
|
|||
def updateMeta(self):
|
||||
self.findSubtitleLink()
|
||||
if exists(self.absolutePath):
|
||||
if not self.broken:
|
||||
info = midentify.identify(self.absolutePath)
|
||||
self.length = info['length']
|
||||
self.width = info['width']
|
||||
|
@ -386,6 +387,9 @@ class ArchiveFile(SQLObject):
|
|||
def _get_timelineFile(self):
|
||||
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):
|
||||
if exists(self.mini_movie_file):
|
||||
os.remove(self.mini_movie_file)
|
||||
|
@ -458,6 +462,9 @@ class ArchiveFile(SQLObject):
|
|||
for p in self._startPoints():
|
||||
self.extractFrame(p)
|
||||
|
||||
def extractPosterStill(self, position, img_folder=):
|
||||
extract_poster_still(self.movieFile, self.posterStillFile, position)
|
||||
|
||||
def extractClipMovie(self, force = False):
|
||||
if self.broken:
|
||||
return
|
||||
|
@ -486,7 +493,6 @@ class ArchiveFile(SQLObject):
|
|||
print cmd.encode('utf-8')
|
||||
os.system(cmd.encode('utf-8'))
|
||||
|
||||
|
||||
def removeTimeline(self):
|
||||
if exists(self.timelineFile):
|
||||
os.unlink(self.timelineFile)
|
||||
|
@ -582,3 +588,6 @@ class ArchiveFile(SQLObject):
|
|||
|
||||
def timeline(self):
|
||||
return cache.loadTimeline(self)
|
||||
|
||||
def posterStill(self, position):
|
||||
return cache.loadPosterStill(self, position)
|
||||
|
|
|
@ -220,6 +220,16 @@ def extract_frame(movie_file, timestamp, img_folder, width=128, offset = 0, redo
|
|||
print "update the cache %s missing" % movie_file
|
||||
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):
|
||||
subtitles = srt2dict(srt)
|
||||
|
|
108
oxdbarchive/tools/extract_poster_still.py
Normal file
108
oxdbarchive/tools/extract_poster_still.py
Normal 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)
|
Loading…
Reference in a new issue