My collection of home movies consists of snippets of video ranging in length from 1 to 15 minutes. To keep track of them, I use a postgres SQL database with a custom, web-based front end. The interface looked a bit bland so I decided to spice it up a bit by adding a dynamically generated thumbnail for each video. The following is a CGI script that uses mplayer to extract a thumbnail from a video. The parameters are "dir" and "filename", which are local pathnames (not URLs) to the file. The script works quite well for my needs, but any feedback would be welcome.
#!/usr/bin/perl
use strict;
use warnings;
use POSIX qw/strftime/;
use CGI qw/:standard/;
sub handle_error($)
{
my $msg = shift or die;
print header(-type => 'text/plain'), $msg;
die;
}
my $num_frames = 7;
my $thumb_dir = '/tmp';
my $thumb_offset_pct = 15;
my $thumb_offset;
my $thumb_pathname;
my $video_pathname = param('dir') or die;
$video_pathname .= '/' . param('filename') or die;
# clean up from previous incarnations
# TODO make this multi-user capable, so that muliple simultaneous inst
+ances do not walk on each other
for (1..$num_frames+1)
{
$thumb_pathname = sprintf("%s/%8.8d.jpg", $thumb_dir, $_);
unlink $thumb_pathname or die if -f $thumb_pathname;
}
# determine the length of the video
my ($video_len) = grep(/^ID_LENGTH=/, (`mplayer -identify \"$video_pat
+hname\" -nosound -vc dummy -vo null`));
if ( $video_len !~ /^[^=]+=(.*)$/ )
{
die 'Unable to read video length';
}
$video_len = $1;
# this mplayer command will produce a series of JPEG images, one of wh
+ich will be our thumbnail
$thumb_offset = int( $video_len * $thumb_offset_pct / 100 );
my $cmd = "mplayer -zoom -ss $thumb_offset -nosound -vo jpeg:outdir=/t
+mp -frames $num_frames -vf scale=250:-3 \"$video_pathname\" > /dev/nu
+ll 2>&1";
my $retval = system($cmd);
#handle_error 'Command failed: ' . $cmd if $retval != 0;
binmode STDOUT;
# choose the highest numbered frame, since lower numbered
# frames tend to be incomplete.
my $frame = $num_frames + 1;
while ($frame ge 1)
{
$thumb_pathname = sprintf("%s/%8.8d.jpg", $thumb_dir, $frame);
last if -f $thumb_pathname;
$frame--;
}
handle_error 'No thumbnail created.' if ! -f $thumb_pathname;
# now we have chosen the right pathname
# get the last-modified timestamp for the video in question,
# so that we can set the HTTP last-modified header.
my @info = stat($video_pathname) or die 'Unable to stat() video
+';
my @ts = gmtime($info[9]);
my $timestamp = strftime("%a, %d %b %Y %H:%M:%S GMT", @ts);
open IMG, '<' . $thumb_pathname or die 'Unable to open thumbnail';
print header( -type => 'image/jpeg', -last_modified => $timestamp);
print <IMG>;
close IMG;