PageRenderTime 90ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/vthumb.py

http://video4fuze.googlecode.com/
Python | 201 lines | 159 code | 6 blank | 36 comment | 5 complexity | 4963738455c9154db60e04d55e335289 MD5 | raw file
Possible License(s): GPL-3.0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # Video Thumbnail Extractor
  4. #
  5. # Requirements:
  6. # PIL 1.1.6 or later: http://www.pythonware.com/products/pil/index.htm
  7. # FFMPEG: http://ffmpeg.mplayerhq.hu/download.html
  8. #
  9. # @author Vadim Zaliva <lord@crocodile.org>
  10. #
  11. # Adapted for video4fuze by Adri??n Cereto <ssorgatem@gmail.com>
  12. # Enhanced by <russs.com@gmail.com>
  13. # ----------------------------------------------------------------------
  14. # LICENSE:
  15. #
  16. # Video Thumbnail Extractor
  17. # Copyright (C) 2006 Vadim Zaliva
  18. #
  19. # This program is free software; you can redistribute it and/or
  20. # modify it under the terms of the GNU General Public License
  21. # as published by the Free Software Foundation; either version 3
  22. # of the License, or (at your option) any later version.
  23. #
  24. # This program is distributed in the hope that it will be useful,
  25. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  27. # GNU General Public License for more details.
  28. #
  29. # You should have received a copy of the GNU General Public License
  30. # along with this program; if not, write to the Free Software
  31. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  32. #
  33. """
  34. This module implements video thumbnail creation using ffmpeg
  35. """
  36. import Image
  37. import sys, os, time, math, shutil, string, tempfile
  38. import getopt
  39. from subprocess import check_call
  40. NFRAMES=100
  41. #FFMPEG="ffmpeg"
  42. TMPDIR=tempfile.gettempdir()
  43. THUMB_SIZE = 224, 176
  44. def frame_rmse(hist, median):
  45. res = 0.0
  46. n = len(median)
  47. for j in range(n):
  48. err=median[j]-float(hist[j]);
  49. res+=(err*err)/n;
  50. return math.sqrt(res);
  51. def img_hist(im):
  52. return im.histogram()
  53. def copy_thumb(src, dst, thumb):
  54. if thumb:
  55. im = Image.open(src)
  56. im.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
  57. im.save(dst, "JPEG")
  58. else:
  59. shutil.copyfile(src, dst)
  60. def find_thumb_from_image (src, destthumb):
  61. try:
  62. srcthumb = ''
  63. #print "src =", src
  64. if os.path.isdir(src):
  65. if os.path.isfile (src + '/backdrop.jpg'):
  66. srcthumb = src + '/backdrop.jpg'
  67. elif os.path.isfile (src + '/folder.jpg'):
  68. srcthumb = src + '/folder.jpg'
  69. elif os.path.isfile (src + '/mymovies-front.jpg'):
  70. srcthumb = src + '/mymovies-front.jpg'
  71. elif os.path.isfile (src + '.jpg'):
  72. srcthumb = src + '.jpg'
  73. elif os.path.isfile(src):
  74. if os.path.isfile (os.path.splitext (src)[0] + '.jpg'):
  75. srcthumb = os.path.splitext (src)[0] + '.jpg'
  76. if srcthumb != '':
  77. print 'thumb from', srcthumb, 'to', destthumb
  78. copy_thumb (srcthumb, destthumb, True)
  79. return True
  80. except Exception, e:
  81. print e
  82. return False
  83. def find_thumb2(infile, outfile, startframe, nframes, alsosave, verbose, thumb, FFMPEG = "ffmpeg"):
  84. if verbose:
  85. infile = '\"' + infile + '\"'
  86. print "Processing %s" % infile
  87. print "Extracting frames"
  88. framemask = "frame" + str(time.time()) + ".%d.jpg"
  89. cmd = "%s -y -r 5 -vframes %d -i %s %s" % (FFMPEG, startframe+nframes-1, infile, framemask)
  90. print cmd
  91. if not verbose:
  92. cmd = cmd + " -v -1" #> /dev/null 2>&1"
  93. if os.system(cmd):
  94. print "Error invoking ffmpeg"
  95. return 10
  96. if verbose:
  97. print "Analyzing frames"
  98. hist=[]
  99. for i in range(startframe,startframe+nframes):
  100. fname = framemask % i
  101. if not os.path.exists(fname):
  102. break
  103. if verbose:
  104. print "\tProcessin frame %d" % i
  105. im = Image.open(fname).convert("RGB")
  106. if not im or im.mode == None:
  107. print "Error reading frame %d" % i
  108. return 20
  109. hist.append(img_hist(im))
  110. if i in alsosave:
  111. thumbfname = outfile + "."+str(i)+".thm"
  112. if thumb:
  113. im.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
  114. im.save(thumbfname, "JPEG")
  115. else:
  116. shutil.copyfile(fname, thumbfname)
  117. if verbose:
  118. print "Calculating averages"
  119. n=len(hist)
  120. avg=[]
  121. for c in range(len(hist[0])):
  122. ac = 0.0
  123. for i in range(n):
  124. ac = ac + (float(hist[i][c])/n)
  125. avg.append(ac)
  126. minn = -1
  127. minRMSE = -1
  128. for i in range(startframe,startframe+n):
  129. rmse = frame_rmse(hist[i-startframe], avg);
  130. if minn==-1 or rmse<minRMSE:
  131. minn = i
  132. minRMSE = rmse
  133. #print "Frame %d RMSE %f" % (i, rmse)
  134. if verbose:
  135. print "BEST Frame: %d" % minn
  136. rc = 0
  137. try:
  138. # Copy best
  139. copy_thumb(framemask % (minn), outfile, thumb)
  140. except:
  141. print "Error copying thumb file"
  142. rc = 100
  143. if verbose:
  144. print "Removing temp files"
  145. for i in range(1,n+1):
  146. fname = framemask % i
  147. os.unlink(fname)
  148. return rc
  149. def find_thumb(infile, outfile, nframes, alsosave, verbose, thumb, FFMPEG = "ffmpeg"):
  150. find_thumb2 (infile, outfile, 1, nframes, alsosave, verbose, thumb, FFMPEG)
  151. if __name__ == "__main__":
  152. from optparse import OptionParser
  153. parser = OptionParser()
  154. parser.usage = "%prog <file> [options]"
  155. parser.add_option("-f","--first", dest="firstframe", help="first frame to analyze in source file (default 1)", metavar="<n>", default=1)
  156. parser.add_option("-c","--count", dest="framecount", help="number of frames to analyze (default 100)", metavar="<n>", default=100)
  157. parser.add_option("-j","--jpg-only", action="store_true", dest="jpgonly", default=False, help="only generate thumb from jpg image")
  158. parser.add_option("-n","--no-jpg", action="store_true", dest="nojpg", default=False, help="don't generate thumb from jpg image")
  159. parser.add_option("-v","--verbose", action="store_true", dest="verbose", default=False, help="verbose")
  160. parser.add_option("-d","--dest", dest="dest", help="destination image (default same as source with .thm extension)", metavar="<file>", default='')
  161. options, args = parser.parse_args()
  162. if len (args) != 1:
  163. parser.error ("file not specified", len(args), args)
  164. file = args [0]
  165. if not file or (not os.path.isfile(file) and not os.path.isdir(file)):
  166. parser.error ("file not specified")
  167. if options.jpgonly and options.nojpg:
  168. parser.error ("can't specify both --jpg-only and --no-jpg")
  169. if options.dest == '':
  170. dest = os.path.splitext (file)[0] + '.thm'
  171. else:
  172. dest = options.dest
  173. if os.path.isdir (dest):
  174. dest = os.path.join (dest, os.path.splitext (os.path.split(file)[1])[0] + '_fuze.thm')
  175. print "Generating", dest
  176. done = False
  177. if not options.nojpg:
  178. done = find_thumb_from_image (os.path.splitext (file)[0], dest)
  179. if not done and not options.jpgonly:
  180. find_thumb2 (file, dest, int(options.firstframe), int(options.framecount), [], options.verbose, False, "ffmpeg")