vdr/PLUGINS/src/pictures/pic2mpg

183 lines
4.5 KiB
Perl
Executable File

#!/usr/bin/perl
# pic2mpg: Convert picture files to MPEG still frames
#
# Converts either a single picture file or all files in a
# given directory (recursively) to MPEG still frames.
#
# See the README file for copyright information and how to reach the author.
#
# $Id: pic2mpg 1.4 2008/02/29 14:34:22 kls Exp $
## TODO implement HDTV (1920 x 1080)
use File::Path;
use File::Spec;
use Getopt::Std;
use Image::Size;
$Usage = qq{
Usage: $0 [options] picture-dir mpeg-dir
$0 [options] picture-file mpeg-file
Options: -a Aspect ratio 4:3 (default is 16:9)
-f Force conversion
-h print Help
-i Ignore unknown file types
-n NTSC (default is PAL)
-v num Verbose (0=none, 1=list files, 2=detailed)
-x percent X overscan in percent
-y percent Y overscan in percent
};
getopts("afhinv:x:y:") || die $Usage;
die $Usage if $opt_h;
$Aspect = $opt_a;
$Force = $opt_f;
$Ignore = $opt_i;
$NTSC = $opt_n;
$Verbose = $opt_v;
$OverscanX = $opt_x;
$OverscanY = $opt_y;
$ListFiles = $Verbose >= 1;
$Detailed = $Verbose >= 2;
# Screen size:
$SW = $NTSC ? 720 : 720;
$SH = $NTSC ? 480 : 576;
$ScreenRatio = $Aspect ? 4 / 3 : 16 / 9;
# Converter programs:
%PNMCONV = (
bmp => "bmptopnm",
gif => "giftopnm",
jpeg => "jpegtopnm",
jpg => "jpegtopnm",
png => "pngtopnm",
pnm => "cat",
tif => "tifftopnm",
tiff => "tifftopnm",
);
# Command options:
die "$0: missing parameter\n" unless $ARGV[0] && $ARGV[1];
die "$0: file or directory not found: $ARGV[0]\n" unless -e $ARGV[0];
die "$0: source and destination must be different\n" if $ARGV[0] eq $ARGV[1];
$verbose1 = $Detailed ? "--verbose" : "";
$verbose2 = $Detailed ? "-v 2" : "-v 0";
$system1 = $NTSC ? "" : "--pal";
$system2 = $NTSC ? "n" : "p";
$framerate = $NTSC ? "30000:1001" : "25:1";
$aspect = $Aspect ? "2" : "3";
# Convert a single file:
if (-f $ARGV[0]) {
die "$0: mixed file and directory ('$ARGV[0]' <-> '$ARGV[1]')\n" unless !-e $ARGV[1] || -f $ARGV[1];
ConvertFile($ARGV[0], $ARGV[1]);
exit;
}
die "$0: mixed directory and file ('$ARGV[0]' <-> '$ARGV[1]')\n" unless !-e $ARGV[1] || -d $ARGV[1];
$PICDIR = File::Spec->rel2abs($ARGV[0]);
$MPGDIR = File::Spec->rel2abs($ARGV[1]);
# Convert pictures to mpegs:
chdir($PICDIR) || die "$PICDIR: $!\n";
@Pictures = `find -type f`;
chomp(@Pictures);
for $pic (@Pictures) {
my $mpg = "$MPGDIR/$pic.mpg";
if ($Force || !-e $mpg || -M $mpg > -M $pic) {
(my $dir = $mpg) =~ s/\/[^\/]*$//;
mkpath($dir);
ConvertFile($pic, $mpg);
}
}
# Remove mpegs without pictures:
chdir($MPGDIR) || die "$MPGDIR: $!\n";
@Mpegs = `find -type f`;
chomp(@Mpegs);
for $mpg (@Mpegs) {
my $pic = "$PICDIR/$mpg";
$pic =~ s/\.mpg$//;
if (!-e $pic) {
print "removing $mpg\n";
unlink($mpg);
}
}
# Remove empty directories:
chdir($MPGDIR) || die "$MPGDIR: $!\n";
for ($i = 0; $i < 10; $i++) { # dirs might become empty when removing empty subdirs
@Dirs = `find -type d -empty`;
chomp(@Dirs);
last unless @Dirs;
for $dir (@Dirs) {
$dir = EscapeMeta($dir);
print "removing $dir\n";
!system("rm -rf $dir") || die "$dir: $!\n";
}
}
# Actual file conversion:
sub ConvertFile
{
my ($Pict, $Mpeg) = @_;
(my $Type) = lc($Pict) =~ /\.([^\.]*)$/;
if (!defined $PNMCONV{$Type}) {
return if ($Ignore);
die "unknown file type '$Type': '$Pict'\n";
}
my ($w, $h) = imgsize($Pict);
print "image size is $w x $h\n" if ($Detailed);
if ($w / $h <= $ScreenRatio) {
$w = $h * $ScreenRatio;
}
else {
$h = $w / $ScreenRatio;
}
my $ScaleW = $SW / $w * (100 - 2 * $OverscanX) / 100;
my $ScaleH = $SH / $h * (100 - 2 * $OverscanY) / 100;
$Pict = EscapeMeta($Pict);
$Mpeg = EscapeMeta($Mpeg);
print "$Pict -> $Mpeg\n" if $ListFiles;
my $Cmd = "$PNMCONV{$Type} $Pict 2> /dev/null |"
. "pnmscale $verbose1 --xscale=$ScaleW --yscale=$ScaleH |"
. "pnmpad $verbose1 --black --width $SW --height $SH |"
. "ppmntsc $verbose1 $system1 |"
. "ppmtoy4m $verbose2 -F $framerate -I p -S 420mpeg2 |"
. "mpeg2enc $verbose2 -f 3 -b 12500 -a $aspect -q 1 -n $system2 -o $Mpeg";
!system($Cmd) || die "$Cmd: $!\n";
$Cmd = "touch -r $Pict $Mpeg";
!system($Cmd) || die "$Cmd: $!\n";
}
sub EscapeMeta
{
my $META = ' !"#$%&\'()*;<>?[\\]`{|}~';
my $s = shift;
$s =~ s/([$META])/\\$1/g;
return $s;
}