1: #!/usr/bin/perl
  2: 
  3: use strict;
  4: use POSIX;
  5: 
  6: # Paths to stuff.
  7: my $path_convert   = '/usr/bin/convert';
  8: my $path_ffmpeg    = '/usr/bin/ffmpeg';
  9: my $path_midentify = '/usr/bin/midentify';
 10: my $path_montage   = '/usr/bin/montage';
 11: my $path_mplayer   = '/usr/bin/mplayer';
 12: 
 13: # Silly tests.
 14: die "This program cannot run if 00000001.png exists.\n" if (-e '00000001.png');
 15: die "This program cannot run if 00000002.png exists.\n" if (-e '00000002.png');
 16: die "This program cannot run if 00000001.gif exists.\n" if (-e '00000001.gif');
 17: 
 18: # Read command line options.
 19: my $file = shift @ARGV || die "Specify input file.\n";
 20: my $rows = shift @ARGV || 6;
 21: my $cols = shift @ARGV || 4;
 22: my $geom = shift @ARGV || '240x180+10+10';
 23: my $is_mpeg = 0;
 24: $is_mpeg = 1 if ($file =~ /\.mpe?g$/i && -e $path_ffmpeg);
 25: 
 26: # Other settings.
 27: my $text_font   = '@/usr/share/fonts/msttcorefonts/trebuc.ttf';
 28: my $text_colour = '#0080';
 29: my $text_bg     = 'AliceBlue';
 30: my $text_size   = '18';
 31: 
 32: # Create temporary directory.
 33: my $tmp_dir = $ENV{'TMPDIR'} || $ENV{'TMP'} || '/tmp';
 34: $tmp_dir .= '/dhyana-' . int(rand(100_000)) . '/';
 35: mkdir ($tmp_dir);
 36: 
 37: # Info about the video.
 38: my @info = split /\n/, `$path_midentify '$file'`;
 39: my %info;
 40: foreach (@info)
 41: {
 42:         my $k;
 43:         my $v;
 44:         chomp;
 45:         ($k, $v) = split /\=/;
 46:         $v =~ s/\\//g;
 47:         $info{$k} = $v;
 48: }
 49: @info = undef;
 50: 
 51: # Create image annotation
 52: my $annotation  = sprintf("Size: %.02f MB (%d bytes)\n",
 53:                         (-s $file)/(1024*1024),
 54:                         (-s $file))
 55:                 . sprintf("Length: %d:%02d:%02d\n",
 56:                         POSIX::floor($info{'ID_LENGTH'}/3600),
 57:                         POSIX::floor(($info{'ID_LENGTH'}%3600)/60),
 58:                         POSIX::floor($info{'ID_LENGTH'}%60) 
 59:                         )
 60:                 . 'Video: '.$info{'ID_VIDEO_WIDTH'} . 'x' . $info{'ID_VIDEO_HEIGHT'} 
 61:                 . ' (' . $info{'ID_VIDEO_FORMAT'} . ', '
 62:                 . int($info{'ID_VIDEO_FPS'}) . ' frames/sec, '
 63:                 . int($info{'ID_VIDEO_BITRATE'}/1000) . " kb/sec)\n"
 64:                 . 'Audio: '.$info{'ID_AUDIO_NCH'} . ' chan'
 65:                 . ' (' . $info{'ID_AUDIO_CODEC'} . ', '
 66:                 . int($info{'ID_AUDIO_RATE'}/1000) . ' kHz, '
 67:                 . int($info{'ID_AUDIO_BITRATE'}/1000) . " kb/sec)\n"
 68:                 ;
 69: 
 70: # Find out how long the video is and thus when we need to capture frames.
 71: my $n_frames = $rows * $cols;
 72: my $length = $info{'ID_LENGTH'};
 73: my $part_length = $length / ($n_frames - 1);
 74: my @times = (1);
 75: for (my $i=1; $i<$n_frames; $i++)
 76: {
 77:         push @times, int($i * $part_length)-1;
 78: }
 79: 
 80: # For each frame, capture it and save it to the temp directory.
 81: my $i = 1;
 82: foreach (@times)
 83: {
 84:         &debug("Capturing frame $i, at $_ seconds.");
 85:         if ($is_mpeg)
 86:         {
 87:                 &debug("Using FFMPEG instead of MPLAYER. (Slow.)");
 88:                 my $cmd = $path_ffmpeg . " -i '$file'"
 89:                         . ' -f image -img gif'
 90:                         . " -ss $_ -vframes 1"
 91:                         . " -y '%08d.gif'";
 92:                 my $cmd_out = `$cmd 2>&1`;
 93:                 system(sprintf("$path_convert '00000001.gif' '%s/frame-%06d.png'",
 94:                         $tmp_dir, $_));
 95:                 system("rm -f '00000001.gif'");
 96:         }
 97:         else
 98:         {
 99:                 my $cmd = $path_mplayer . ' -really-quiet -nosound'
100:                         . ' -vo png:z=3 -frames 2'
101:                         . " -ss $_ '$file'";
102:                 my $cmd_out = `$cmd 2>&1`;
103:                 system(sprintf("mv '00000002.png' '%s/frame-%06d.png'",
104:                         $tmp_dir, $_));
105:                 system("rm -f '00000001.png' '00000002.png'");
106:         }
107:         $i++;
108: }
109: 
110: # Creating montage.
111: &debug("Creating montage.");
112: my $cmd = $path_montage
113:         . " -geometry '$geom'"
114:         . " -background '$text_bg'"
115:         . " -fill '$text_colour'"
116:         . " -tile '".$cols."x".$rows."'"
117:         . " $tmp_dir/frame-*.png $tmp_dir/montage.png";
118: my $cmd_out = `$cmd 2>&1`;
119: die "Error creating montage!\n" unless (-e "$tmp_dir/montage.png");
120: 
121: # Annotating montage
122: &debug("Annotating montage.");
123: my $cmd = $path_convert
124:         . " -background '$text_bg'"
125:         . " -fill '$text_colour'"
126:         . " -font '$text_font'"
127:         . " -pointsize '$text_size'"
128:         . " -gravity North"
129:         . " -trim +repage"
130:         . " -bordercolor '$text_bg'"
131:         . " -border 20x20"
132:         . " text:- '$tmp_dir/annotation.png'";
133: open(CONVERT, "|$cmd");
134: print CONVERT "$file\n$annotation\n";
135: close(CONVERT);
136: system("$path_convert -background '$text_bg' '$tmp_dir/annotation.png' '$tmp_dir/montage.png' -append '$tmp_dir/final.png'");
137: 
138: # Finalising
139: &debug("Saving final file.");
140: my $file_out = $file;
141: $file_out =~ s/\.[^\.]+$/.jpeg/;
142: system("$path_convert -quality 90 '$tmp_dir/final.png' '$file_out'");
143: &debug("Cleaning up temporary files.");
144: system("rm -fr '$tmp_dir'");
145: 
146: # Debugging function.
147: sub debug
148: {
149:         my $x = shift @_;
150:         print "debug: $x\n";
151: }