125 lines
3.4 KiB
Python
125 lines
3.4 KiB
Python
# -*- encoding: utf-8 -*-
|
|
"""
|
|
django-videothumbs
|
|
"""
|
|
|
|
from six import StringIO
|
|
from django.conf.global_settings import FILE_UPLOAD_TEMP_DIR
|
|
import math
|
|
import os
|
|
import time
|
|
from PIL import Image
|
|
|
|
TMP_DIR = FILE_UPLOAD_TEMP_DIR or '/tmp/'
|
|
|
|
def generate_thumb(storage, video_path, thumb_size=None, format='jpg', frames=100):
|
|
histogram = []
|
|
|
|
http_status = 200
|
|
|
|
name = video_path
|
|
path = storage.path(video_path)
|
|
|
|
if not storage.exists(video_path):
|
|
return "", '404'
|
|
|
|
framemask = "%s%s%s%s" % (TMP_DIR,
|
|
name.split('/')[-1].split('.')[0] + str(time.time()),
|
|
'.%d.',
|
|
format)
|
|
# ffmpeg command for grabbing N number of frames
|
|
cmd = "/usr/bin/ffmpeg -y -t 00:00:05 -i '%s' '%s'" % (path, framemask)
|
|
|
|
# make sure that this command worked or return.
|
|
if os.system(cmd) != 0:
|
|
return "", '500'
|
|
|
|
# loop through the generated images, open, and generate the image histogram.
|
|
for i in range(1, frames + 1):
|
|
fname = framemask % i
|
|
|
|
if not os.path.exists(os.path.join(TMP_DIR, fname)):
|
|
break
|
|
|
|
image = Image.open(fname)
|
|
|
|
# Convert to RGB if necessary
|
|
if image.mode not in ('L', 'RGB'):
|
|
image = image.convert('RGB')
|
|
|
|
# The list of image historgrams
|
|
histogram.append(image.histogram())
|
|
|
|
n = len(histogram)
|
|
avg = []
|
|
|
|
# Get the image average of the first image
|
|
for c in range(len(histogram[0])):
|
|
ac = 0.0
|
|
for i in range(n):
|
|
ac = ac + (float(histogram[i][c]) / n)
|
|
avg.append(ac)
|
|
|
|
minn = -1
|
|
minRMSE = -1
|
|
|
|
# Compute the mean squared error
|
|
for i in range(1, n + 1):
|
|
results = 0.0
|
|
num = len(avg)
|
|
|
|
for j in range(num):
|
|
median_error = avg[j] - float(histogram[i - 1][j])
|
|
results += (median_error * median_error) / num
|
|
rmse = math.sqrt(results)
|
|
|
|
if minn == -1 or rmse < minRMSE:
|
|
minn = i
|
|
minRMSE = rmse
|
|
|
|
file_location = framemask % (minn)
|
|
image = Image.open(file_location)
|
|
|
|
# If you want to generate a square thumbnail
|
|
if not thumb_size is None:
|
|
thumb_w, thumb_h = thumb_size
|
|
|
|
if thumb_w == thumb_h:
|
|
# quad
|
|
xsize, ysize = image.size
|
|
# get minimum size
|
|
minsize = min(xsize, ysize)
|
|
# largest square possible in the image
|
|
xnewsize = (xsize - minsize) / 2
|
|
ynewsize = (ysize - minsize) / 2
|
|
# crop it
|
|
image2 = image.crop((xnewsize, ynewsize, xsize - xnewsize, ysize - ynewsize))
|
|
# load is necessary after crop
|
|
image2.load()
|
|
# thumbnail of the cropped image (with ANTIALIAS to make it look better)
|
|
image2.thumbnail(thumb_size, Image.ANTIALIAS)
|
|
else:
|
|
# not quad
|
|
image2 = image
|
|
image2.thumbnail(thumb_size, Image.ANTIALIAS)
|
|
else:
|
|
image2 = image
|
|
|
|
io = StringIO()
|
|
|
|
# PNG and GIF are the same, JPG is JPEG
|
|
if format.upper() == 'JPG':
|
|
format = 'JPEG'
|
|
|
|
image2.save(io, format)
|
|
|
|
# We don't know how many frames we capture. We just captured the first 5 seconds, so keep removing until not found
|
|
for i in range(1, 9999):
|
|
fname = framemask % i
|
|
try:
|
|
os.unlink(fname)
|
|
except OSError:
|
|
break
|
|
|
|
return io.getvalue(), http_status
|