#!/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 instances 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_pathname\" -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 which will be our thumbnail $thumb_offset = int( $video_len * $thumb_offset_pct / 100 ); my $cmd = "mplayer -zoom -ss $thumb_offset -nosound -vo jpeg:outdir=/tmp -frames $num_frames -vf scale=250:-3 \"$video_pathname\" > /dev/null 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 ; close IMG;