From c13d6e6070d895dd33f82e80b5d045cbb417bc6c Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 14 Aug 2011 13:50:26 +0200 Subject: [PATCH] The pic2mpg script of the 'pictures' plugin now generates HD images --- CONTRIBUTORS | 1 + HISTORY | 5 +- PLUGINS/src/pictures/HISTORY | 6 + PLUGINS/src/pictures/pic2mpg | 88 ++++----------- PLUGINS/src/pictures/pic2mpg-sd | 193 ++++++++++++++++++++++++++++++++ 5 files changed, 225 insertions(+), 68 deletions(-) create mode 100755 PLUGINS/src/pictures/pic2mpg-sd diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 4764d5b3..eb47d58b 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -2153,6 +2153,7 @@ Andr recording if Setup.UseDolbyDigital is true for suggesting that the primary device should only be avoided for recording if it is an old SD full featured card + for his support in using convert/ffmpeg in the pic2mpg script of the 'pictures' plugin Jürgen Schilling for reporting that color buttons were displayed in the recording info menu if it diff --git a/HISTORY b/HISTORY index e52e7841..f1af119c 100644 --- a/HISTORY +++ b/HISTORY @@ -6650,7 +6650,7 @@ Video Disk Recorder Revision History - Added support for "content identifier descriptor" and "default authority descriptor" to 'libsi' (thanks to Dave Pickles). -2011-08-13: Version 1.7.20 +2011-08-14: Version 1.7.20 - Added some missing 'const' to tChannelID (reported by Sundararaj Reel). - The isnumber() function now checks the given pointer for NULL (thanks to Holger @@ -6683,3 +6683,6 @@ Video Disk Recorder Revision History by a call to cIndexFile::GetLength() (suggested by Christoph Haubrich). - Fixed some crashes in subtitle display (thanks to Rolf Ahrenberg). - Made DELETENULL() thread safe (reported by Rolf Ahrenberg). +- The pic2mpg script of the 'pictures' plugin now generates HD images (thanks to + Andre Weidemann for his support in using convert/ffmpeg). The old SD version is + still available as pic2mpg-sd. diff --git a/PLUGINS/src/pictures/HISTORY b/PLUGINS/src/pictures/HISTORY index b67bbaca..7e82a3c7 100644 --- a/PLUGINS/src/pictures/HISTORY +++ b/PLUGINS/src/pictures/HISTORY @@ -49,3 +49,9 @@ VDR Plugin 'pictures' Revision History 2011-07-23: - Now rotating images according to the EXIF 'Orientation' parameter. + +2011-08-14: + +- The pic2mpg script now generates HD images (thanks to Andre Weidemann for his + support in using convert/ffmpeg). The old SD version is still available as + pic2mpg-sd. diff --git a/PLUGINS/src/pictures/pic2mpg b/PLUGINS/src/pictures/pic2mpg index 6213091e..190ec260 100755 --- a/PLUGINS/src/pictures/pic2mpg +++ b/PLUGINS/src/pictures/pic2mpg @@ -7,63 +7,45 @@ # # See the README file for copyright information and how to reach the author. # -# $Id: pic2mpg 2.1 2011/07/23 14:23:59 kls Exp $ - -## TODO implement HDTV (1920 x 1080) +# $Id: pic2mpg 2.2 2011/08/14 13:34:15 kls Exp $ use File::Path; use File::Spec; use Getopt::Std; use Image::ExifTool qw(:Public); -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 +Options: -f Force conversion -h print Help - -i Ignore unknown file types - -n NTSC (default is PAL) + -s size Screen size (WIDTHxHEIGHT, default is 1920x1080) -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; +getopts("fhs:v:") || die $Usage; die $Usage if $opt_h; -$Aspect = $opt_a; $Force = $opt_f; -$Ignore = $opt_i; -$NTSC = $opt_n; +$Size = $opt_s || "1920x1080"; $Verbose = $opt_v; -$OverscanX = $opt_x; -$OverscanY = $opt_y; $ListFiles = $Verbose >= 1; $Detailed = $Verbose >= 2; -# Screen size: +# Supported picture types: -$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", +%PICTYPES = ( + bmp => 1, + gif => 1, + jpeg => 1, + jpg => 1, + png => 1, + pnm => 1, + tif => 1, + tiff => 1, ); # Command options: @@ -72,13 +54,6 @@ 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]) { @@ -96,7 +71,7 @@ $MPGDIR = File::Spec->rel2abs($ARGV[1]); chdir($PICDIR) || die "$PICDIR: $!\n"; -@Pictures = `find -type f`; +@Pictures = `find -type f | sort`; chomp(@Pictures); for $pic (@Pictures) { @@ -146,39 +121,18 @@ 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); + return if (!defined $PICTYPES{$Type}); my $Exif = ImageInfo($Pict); my $Orientation = $$Exif{"Orientation"}; my ($Degrees) = $Orientation =~ /Rotate ([0-9]+) /; - my $Rotate = "-null"; - $Rotate = "-cw" if $Degrees eq "90"; - $Rotate = "-ccw" if $Degrees eq "270"; - $Rotate = "-r180" if $Degrees eq "180"; + my $Rotate = $Degrees ? "-rotate $Degrees" : ""; print "orientation = '$Orientation' -> rotation = $Rotate\n" if ($Detailed); - ($w, $h) = ($h, $w) if ($Degrees eq "90" || $Degrees eq "270"); - 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 $Rotate\n" if $ListFiles; - my $Cmd = "$PNMCONV{$Type} $Pict 2> /dev/null |" - . "pamflip $verbose1 $Rotate |" - . "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"; + my $Cmd = "convert $Pict -background '#000000' $Rotate -resize $Size -gravity center -extent $Size ppm:- | " + . "ffmpeg -f image2pipe -vcodec ppm -i pipe:0 -an -vcodec libx264 -vpre baseline -s $Size -qscale 2 -f mpegts -y $Mpeg " + . ($Detailed ? "" : "2>/dev/null"); !system($Cmd) || die "$Cmd: $!\n"; $Cmd = "touch -r $Pict $Mpeg"; !system($Cmd) || die "$Cmd: $!\n"; diff --git a/PLUGINS/src/pictures/pic2mpg-sd b/PLUGINS/src/pictures/pic2mpg-sd new file mode 100755 index 00000000..15549dcd --- /dev/null +++ b/PLUGINS/src/pictures/pic2mpg-sd @@ -0,0 +1,193 @@ +#!/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-sd 2.1 2011/07/23 14:23:59 kls Exp $ + +## TODO implement HDTV (1920 x 1080) + +use File::Path; +use File::Spec; +use Getopt::Std; +use Image::ExifTool qw(:Public); +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); + my $Exif = ImageInfo($Pict); + my $Orientation = $$Exif{"Orientation"}; + my ($Degrees) = $Orientation =~ /Rotate ([0-9]+) /; + my $Rotate = "-null"; + $Rotate = "-cw" if $Degrees eq "90"; + $Rotate = "-ccw" if $Degrees eq "270"; + $Rotate = "-r180" if $Degrees eq "180"; + print "orientation = '$Orientation' -> rotation = $Rotate\n" if ($Detailed); + ($w, $h) = ($h, $w) if ($Degrees eq "90" || $Degrees eq "270"); + 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 $Rotate\n" if $ListFiles; + my $Cmd = "$PNMCONV{$Type} $Pict 2> /dev/null |" + . "pamflip $verbose1 $Rotate |" + . "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; +}