diff -ruN vdr-1.7.19/CONTRIBUTORS vdr-1.7.20/CONTRIBUTORS
--- vdr-1.7.19/CONTRIBUTORS	2011-06-15 23:29:03.000000000 +0200
+++ vdr-1.7.20/CONTRIBUTORS	2011-08-15 14:45:40.000000000 +0200
@@ -678,6 +678,7 @@
  for fixing the way the OSD size is determined on full featured DVB cards
  for his input on calculating the Aspect factor in GetOsdSize()
  for suggesting a better way of handling calls to realloc()
+ for making the cutter set the 'broken link' flag for MPEG2 TS recordings
 
 Reinhard Walter Buchner <rw.buchner@freenet.de>
  for adding some satellites to 'sources.conf'
@@ -1107,6 +1108,9 @@
  for adding an include of VDR's 'Make.global' to libsi's Makefile
  for adding handling of "ANSI/SCTE 57" descriptors
  for some input on how to use BER and UNC values to generate a "quality" value
+ for fixing some crashes in subtitle display
+ for reporting that DELETENULL() was not thread safe
+ for reporting a crash in subtitle display, related to cOsd::Osds
 
 Ralf Klueber <ralf.klueber@vodafone.com>
  for reporting a bug in cutting a recording if there is only a single editing mark
@@ -1273,6 +1277,8 @@
  for avoiding an unecessary call to Recordings.ResetResume()
  for debugging a problem in handling the bitmap color depth for scaled subtitles
  for making subtitle PIDs be decrypted
+ for making cEITScanner process new transponders before old ones, to make sure
+ transponder changes are recognized
 
 Richard Robson <richard_robson@beeb.net>
  for reporting freezing replay if a timer starts while in Transfer Mode from the
@@ -1700,6 +1706,8 @@
  "TITLE" or "EPISODE"
  for a patch to "Made updating the editing marks during replay react faster in case
  the marks file has just been written"
+ for suggesting a fix for a bug in handling DiSEqC codes
+ for fixing handling the channelID in cMenuEditChanItem
 
 Sven Kreiensen <svenk@kammer.uni-hannover.de>
  for his help in keeping 'channels.conf.terr' up to date
@@ -2147,6 +2155,7 @@
  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 <juergen_schilling@web.de>
  for reporting that color buttons were displayed in the recording info menu if it
@@ -2223,6 +2232,9 @@
  for suggesting to add a note to cTsToPes about all TS packets having to belong to
  the same PID
  for adding HD stream content identifiers to vdr.5
+ for reporting that Setup.InitialChannel was dereferenced without checking for NULL
+ for suggesting to implement a function to determine the length of a recording's
+ index file
 
 Pekka Mauno <pekka.mauno@iki.fi>
  for fixing cSchedule::GetFollowingEvent() in case there is currently no present
@@ -2509,6 +2521,8 @@
 
 Sundararaj Reel <sundararaj.reel@googlemail.com>
  for reporting a missing reset of maxNumber in cChannels::Renumber()
+ for reporting some missing 'const' in tChannelID
+ for suggesting to add optional case insensitive sorting to cStringList::Sort()
 
 Ales Jurik <ajurik@quick.cz>
  for reporting broken SI data on Czech/Slovak channels after changing the default
@@ -2718,6 +2732,7 @@
 
 Marco Göbenich <mg@needful.de>
  for reporting a problem with executing diseqc commands from different threads
+ for suggesting to implement command line option --filesize
 
 Johan Andersson <jna@jna.pp.se>
  for reporting a bug in detecting frames in case the Picture Start Code or Access Unit
@@ -2726,3 +2741,22 @@
 Dave Pickles <dave@pickles.me.uk>
  for adding support for "content identifier descriptor" and "default authority
  descriptor" to 'libsi'
+
+Holger Dengler <holger.dengler@gmx.de>
+ for making the isnumber() function check the given pointer for NULL
+
+Michael Eiler <eiler.mike@gmail.com>
+ - reporting a crash in case cSkins::Message() is called from a background thread
+
+Jonas Diemer <jonasdiemer@googlemail.com>
+ for fixing the return value of the svdrpsend.pl script in case of an error
+
+Jerome Lacarriere <lacarriere.j@gmail.com>
+ for increasing MAXCAIDS to 12
+
+Mark Hawes <MARK.HAWES@au.fujitsu.com>
+ for reporting a bug in handling DiSEqC codes
+
+Frank Niederwipper <f.niederwipper@gmail.com>
+ for reporting a problem in timer handling in case a recording directory can't
+ be created
diff -ruN vdr-1.7.19/HISTORY vdr-1.7.20/HISTORY
--- vdr-1.7.19/HISTORY	2011-06-19 11:53:58.000000000 +0200
+++ vdr-1.7.20/HISTORY	2011-08-15 15:44:16.000000000 +0200
@@ -6305,7 +6305,7 @@
   parameters, but rather the whole channel is handed down for processing. The old
   constructor of cReceiver is still available, but it is recommended to plugin authors
   that they switch to the new interface as soon as possible.
-  When replaying such a recording, the PCR packets are sent to PlayTsVideo()
+  When replaying such a recording, the PCR packets are sent to PlayTsVideo().
 - The files "commands.conf" and "reccmd.conf" can now contain nested lists of
   commands. See vdr.5 for information about the new file format.
   This obsoletes the CMDSUBMENU patch.
@@ -6649,3 +6649,52 @@
   Lars Bläser).
 - Added support for "content identifier descriptor" and "default authority descriptor"
   to 'libsi' (thanks to Dave Pickles).
+
+2011-08-15: 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
+  Dengler).
+- Now checking Setup.InitialChannel for NULL before using it (reported by
+  Christoph Haubrich).
+- cSkins::Message() now blocks calls from background threads (thanks to Michael
+  Eiler for reporting a crash in such a scenario).
+- Fixed the return value of the svdrpsend.pl script in case of an error (thanks to
+  Jonas Diemer).
+- Increased MAXCAIDS to 12 (thanks to Jerome Lacarriere).
+- Fixed handling DiSEqC codes (thanks to Mark Hawes for reporting the bug, and
+  Udo Richter for suggesting the fix).
+- Added a mechanism to defer timer handling in case of problems (reported by
+  Frank Niederwipper).
+- Fixed distortions that happened when splitting recording into several files
+  (was a side effect of "Fixed detecting frames in case the Picture Start Code or
+  Access Unit Delimiter extends over TS packet boundaries" in version 1.7.19).
+  cRecorder::Action() now buffers TS packets in case the frame type is
+  not yet known when a new payload starts. This adds no overhead for channels
+  that broadcast the frame type within the first TS packet of a payload; it only
+  kicks in if that information is not in the first TS packet.
+- Fixed handling the channelID in cMenuEditChanItem (thanks to Udo Richter).
+- cStringList::Sort() can now be called with a boolean parameter that controls
+  case insensitive sorting (suggested by Sundararaj Reel).
+- Now scanning new transponders before old ones, to make sure transponder changes
+  are recognized (thanks to Reinhard Nissl).
+- Implemented static cIndexFile::IndexFileName().
+- The length (as number of frames) of a recording's index file can now be determined
+  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.
+- Added a mutex to protect cOsd::Osds from simultaneous access from different threads
+  (reported by Rolf Ahrenberg).
+- The cutter now sets the 'broken link' flag for MPEG2 TS recordings (thanks to
+  Oliver Endriss).
+- Fixed language code entry for Portuguese.
+- The new command line options --filesize (suggested by Marco Göbenich) and --split
+  can be used together with --edit to set the maximum video file size and turn on
+  splitting edited files at the editing marks. These options must be given before
+  --edit to have an effect.
+- cTimeMs is no longer initialized to the current time if the value given to the
+  constructor is negative (avoids the "cTimeMs: using monotonic clock..." log message
+  before VDR's starting log message).
diff -ruN vdr-1.7.19/MANUAL vdr-1.7.20/MANUAL
--- vdr-1.7.19/MANUAL	2011-06-13 16:42:18.000000000 +0200
+++ vdr-1.7.20/MANUAL	2011-08-15 12:46:20.000000000 +0200
@@ -822,7 +822,7 @@
 
   Max. video file size = 2000
                          The maximum size of a single recorded video file in MB.
-                         The valid range is 100...2000. Default is 2000, but
+                         The valid range is 100...1048570. Default is 2000, but
                          you may want to use smaller values if you are planning
                          on archiving a recording to CD.
 
diff -ruN vdr-1.7.19/PLUGINS/src/dvbhddevice/po/it_IT.po vdr-1.7.20/PLUGINS/src/dvbhddevice/po/it_IT.po
--- vdr-1.7.19/PLUGINS/src/dvbhddevice/po/it_IT.po	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.20/PLUGINS/src/dvbhddevice/po/it_IT.po	2011-07-10 00:23:38.000000000 +0200
@@ -0,0 +1,93 @@
+# VDR plugin language source file
+# Copyright (C) 2011 Andreas Regel
+# This file is distributed under the same license as the dvbhddevice package.
+# Christoph Haubrich, 2011
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: VDR\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2011-05-05 20:34+0200\n"
+"PO-Revision-Date: 2011-07-10 00:23+0100\n"
+"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
+"Language-Team:  <see README>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: Italian\n"
+"X-Poedit-Country: ITALY\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+msgid "Automatic"
+msgstr "Automatica"
+
+msgid "Letterbox 16/9"
+msgstr "Letterbox 16:9"
+
+msgid "Letterbox 14/9"
+msgstr "Letterbox 14:9"
+
+msgid "Pillarbox"
+msgstr "Pillarbox"
+
+msgid "CentreCutOut"
+msgstr "CentreCutOut"
+
+msgid "Always 16/9"
+msgstr "Sempre 16:9"
+
+msgid "Disabled"
+msgstr "Disabilitata"
+
+msgid "Analogue only"
+msgstr "Solo analogica"
+
+msgid "Always"
+msgstr "Sempre"
+
+msgid "HDMI only"
+msgstr "Solo HDMI"
+
+msgid "Follow resolution"
+msgstr "Risoluzione seguente"
+
+msgid "none"
+msgstr "nessuna"
+
+msgid "Resolution"
+msgstr "Risoluzione"
+
+msgid "TV format"
+msgstr "Formato TV"
+
+msgid "Video Conversion"
+msgstr "Conversione video"
+
+msgid "Analogue Video"
+msgstr "Video analogico"
+
+msgid "Audio Delay (ms)"
+msgstr "Ritardo audio (ms)"
+
+msgid "Audio Downmix"
+msgstr "Scala Audio"
+
+msgid "OSD Size"
+msgstr "Dimensione OSD"
+
+msgid "HDMI CEC"
+msgstr "HDMI CEC"
+
+msgid "Remote Control Protocol"
+msgstr "Protocollo controllo remoto"
+
+msgid "Remote Control Address"
+msgstr "Indirizzo controllo remoto"
+
+msgid "High Level OSD"
+msgstr "OSD alto livello"
+
+msgid "Allow True Color OSD"
+msgstr "Permetti OSD True Color"
+
diff -ruN vdr-1.7.19/PLUGINS/src/pictures/HISTORY vdr-1.7.20/PLUGINS/src/pictures/HISTORY
--- vdr-1.7.19/PLUGINS/src/pictures/HISTORY	2011-02-20 17:50:57.000000000 +0100
+++ vdr-1.7.20/PLUGINS/src/pictures/HISTORY	2011-08-14 15:46:39.000000000 +0200
@@ -45,3 +45,13 @@
 2011-02-20: Version 0.1.0
 
 - Fixed reallocating memory (reported by Paul Menzel).
+
+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 -ruN vdr-1.7.19/PLUGINS/src/pictures/pic2mpg vdr-1.7.20/PLUGINS/src/pictures/pic2mpg
--- vdr-1.7.19/PLUGINS/src/pictures/pic2mpg	2008-02-29 15:34:22.000000000 +0100
+++ vdr-1.7.20/PLUGINS/src/pictures/pic2mpg	2011-08-14 15:34:15.000000000 +0200
@@ -7,62 +7,45 @@
 #
 # See the README file for copyright information and how to reach the author.
 #
-# $Id: pic2mpg 2.0 2008/02/29 14:34:22 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::Size;
+use Image::ExifTool qw(:Public);
 
 $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:
-
-$SW = $NTSC ? 720 : 720;
-$SH = $NTSC ? 480 : 576;
-
-$ScreenRatio = $Aspect ? 4 / 3 : 16 / 9;
+# Supported picture types:                                                                                                       
 
-# 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:
@@ -71,13 +54,6 @@
 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]) {
@@ -95,7 +71,7 @@
 
 chdir($PICDIR) || die "$PICDIR: $!\n";
 
-@Pictures = `find -type f`;
+@Pictures = `find -type f | sort`;
 chomp(@Pictures);
 
 for $pic (@Pictures) {
@@ -145,29 +121,18 @@
 {
   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;
+  return if (!defined $PICTYPES{$Type});
+  my $Exif = ImageInfo($Pict);
+  my $Orientation = $$Exif{"Orientation"};
+  my ($Degrees) = $Orientation =~ /Rotate ([0-9]+) /; 
+  my $Rotate = $Degrees ? "-rotate $Degrees" : "";
+  print "orientation = '$Orientation' -> rotation = $Rotate\n" if ($Detailed);
   $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";
+  print "$Pict -> $Mpeg $Rotate\n" if $ListFiles;
+  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 -ruN vdr-1.7.19/PLUGINS/src/pictures/pic2mpg-sd vdr-1.7.20/PLUGINS/src/pictures/pic2mpg-sd
--- vdr-1.7.19/PLUGINS/src/pictures/pic2mpg-sd	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.20/PLUGINS/src/pictures/pic2mpg-sd	2011-08-14 15:43:52.000000000 +0200
@@ -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 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;
+}
diff -ruN vdr-1.7.19/channels.h vdr-1.7.20/channels.h
--- vdr-1.7.19/channels.h	2010-06-05 15:12:54.000000000 +0200
+++ vdr-1.7.20/channels.h	2011-08-06 11:56:13.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: channels.h 2.12 2010/06/05 13:12:54 kls Exp $
+ * $Id: channels.h 2.14 2011/08/06 09:56:13 kls Exp $
  */
 
 #ifndef __CHANNELS_H
@@ -34,7 +34,7 @@
 #define MAXAPIDS 32 // audio
 #define MAXDPIDS 16 // dolby (AC3 + DTS)
 #define MAXSPIDS 32 // subtitles
-#define MAXCAIDS  8 // conditional access
+#define MAXCAIDS 12 // conditional access
 
 #define MAXLANGCODE1 4 // a 3 letter language code, zero terminated
 #define MAXLANGCODE2 8 // up to two 3 letter language codes, separated by '+' and zero terminated
@@ -61,11 +61,11 @@
   bool Valid(void) const { return (nid || tid) && sid; } // rid is optional and source may be 0//XXX source may not be 0???
   tChannelID &ClrRid(void) { rid = 0; return *this; }
   tChannelID &ClrPolarization(void);
-  int Source(void) { return source; }
-  int Nid(void) { return nid; }
-  int Tid(void) { return tid; }
-  int Sid(void) { return sid; }
-  int Rid(void) { return rid; }
+  int Source(void)  const { return source; }
+  int Nid(void)  const { return nid; }
+  int Tid(void)  const { return tid; }
+  int Sid(void)  const { return sid; }
+  int Rid(void)  const { return rid; }
   static tChannelID FromString(const char *s);
   cString ToString(void) const;
   static const tChannelID InvalidID;
diff -ruN vdr-1.7.19/config.h vdr-1.7.20/config.h
--- vdr-1.7.19/config.h	2011-06-13 16:24:40.000000000 +0200
+++ vdr-1.7.20/config.h	2011-06-21 23:43:01.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: config.h 2.32 2011/06/13 14:24:40 kls Exp $
+ * $Id: config.h 2.33 2011/06/21 21:43:01 kls Exp $
  */
 
 #ifndef __CONFIG_H
@@ -22,13 +22,13 @@
 
 // VDR's own version number:
 
-#define VDRVERSION  "1.7.19"
-#define VDRVERSNUM   10719  // Version * 10000 + Major * 100 + Minor
+#define VDRVERSION  "1.7.20"
+#define VDRVERSNUM   10720  // Version * 10000 + Major * 100 + Minor
 
 // The plugin API's version number:
 
-#define APIVERSION  "1.7.19"
-#define APIVERSNUM   10719  // Version * 10000 + Major * 100 + Minor
+#define APIVERSION  "1.7.20"
+#define APIVERSNUM   10720  // Version * 10000 + Major * 100 + Minor
 
 // When loading plugins, VDR searches them by their APIVERSION, which
 // may be smaller than VDRVERSION in case there have been no changes to
diff -ruN vdr-1.7.19/diseqc.c vdr-1.7.20/diseqc.c
--- vdr-1.7.19/diseqc.c	2011-05-22 12:36:12.000000000 +0200
+++ vdr-1.7.20/diseqc.c	2011-08-06 12:32:18.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: diseqc.c 2.4 2011/05/22 10:36:12 kls Exp $
+ * $Id: diseqc.c 2.5 2011/08/06 10:32:18 kls Exp $
  */
 
 #include "diseqc.h"
@@ -95,13 +95,13 @@
   if (e) {
      int NumCodes = 0;
      const char *t = s;
-     char *p;
      while (t < e) {
            if (NumCodes < MaxDiseqcCodes) {
               errno = 0;
+              char *p;
               int n = strtol(t, &p, 16);
               if (!errno && p != t && 0 <= n && n <= 255) {
-                 if (parsing) {
+                 if (!parsing) {
                     codes[NumCodes++] = uchar(n);
                     numCodes = NumCodes;
                     }
diff -ruN vdr-1.7.19/dvbsubtitle.c vdr-1.7.20/dvbsubtitle.c
--- vdr-1.7.19/dvbsubtitle.c	2011-04-17 16:34:05.000000000 +0200
+++ vdr-1.7.20/dvbsubtitle.c	2011-08-13 15:33:00.000000000 +0200
@@ -7,7 +7,7 @@
  * Original author: Marco Schlüßler <marco@lordzodiac.de>
  * With some input from the "subtitle plugin" by Pekka Virtanen <pekka.virtanen@sci.fi>
  *
- * $Id: dvbsubtitle.c 2.17 2011/04/17 14:34:05 kls Exp $
+ * $Id: dvbsubtitle.c 2.18 2011/08/13 13:33:00 kls Exp $
  */
 
 
@@ -826,6 +826,7 @@
   while (Running()) {
         int WaitMs = 100;
         if (!frozen) {
+           LOCK_THREAD;
            if (osd) {
               int NewSetupLevel = setupLevel;
               if (Timeout.TimedOut() || LastSetupLevel != NewSetupLevel) {
@@ -833,7 +834,6 @@
                  }
               LastSetupLevel = NewSetupLevel;
               }
-           Lock();
            if (cDvbSubtitleBitmaps *sb = bitmaps->First()) {
               int64_t STC = cDevice::PrimaryDevice()->GetSTC();
               int64_t Delta = LimitTo32Bit(sb->Pts()) - LimitTo32Bit(STC); // some devices only deliver 32 bits
@@ -858,7 +858,6 @@
               else
                  bitmaps->Del(sb);
               }
-           Unlock();
            }
         cCondWait::SleepMs(WaitMs);
         }
@@ -902,6 +901,7 @@
 
 bool cDvbSubtitleConverter::AssertOsd(void)
 {
+  LOCK_THREAD;
   return osd || (osd = cOsdProvider::NewOsd(int(round(osdFactorX * windowHorizontalOffset + osdDeltaX)), int(round(osdFactorY * windowVerticalOffset + osdDeltaY)) + Setup.SubtitleOffset, OSD_LEVEL_SUBTITLES));
 }
 
@@ -957,7 +957,11 @@
             region->SetVersion(regionVersion);
             bool regionFillFlag = (Data[6 + 1] & 0x08) >> 3;
             int regionWidth = (Data[6 + 2] << 8) | Data[6 + 3];
+            if (regionWidth < 1)
+               regionWidth = 1;
             int regionHeight = (Data[6 + 4] << 8) | Data[6 + 5];
+            if (regionHeight < 1)
+               regionHeight = 1;
             region->SetSize(regionWidth, regionHeight);
             region->SetLevel((Data[6 + 6] & 0xE0) >> 5);
             region->SetDepth((Data[6 + 6] & 0x1C) >> 2);
@@ -1103,7 +1107,7 @@
   int NumAreas = Page->regions.Count();
   int Bpp = 8;
   bool Reduced = false;
-  while (osd->CanHandleAreas(Areas, NumAreas) != oeOk) {
+  while (osd && osd->CanHandleAreas(Areas, NumAreas) != oeOk) {
         int HalfBpp = Bpp / 2;
         if (HalfBpp >= 2) {
            for (int i = 0; i < NumAreas; i++) {
@@ -1141,8 +1145,10 @@
   for (cSubtitleRegion *sr = Page->regions.First(); sr; sr = Page->regions.Next(sr)) {
       int posX = sr->HorizontalAddress();
       int posY = sr->VerticalAddress();
-      cBitmap *bm = new cBitmap(sr->Width(), sr->Height(), sr->Bpp(), posX, posY);
-      bm->DrawBitmap(posX, posY, *sr);
-      Bitmaps->AddBitmap(bm);
+      if (sr->Width() > 0 && sr->Height() > 0) {
+         cBitmap *bm = new cBitmap(sr->Width(), sr->Height(), sr->Bpp(), posX, posY);
+         bm->DrawBitmap(posX, posY, *sr);
+         Bitmaps->AddBitmap(bm);
+         }
       }
 }
diff -ruN vdr-1.7.19/eitscan.c vdr-1.7.20/eitscan.c
--- vdr-1.7.19/eitscan.c	2010-02-07 13:12:05.000000000 +0100
+++ vdr-1.7.20/eitscan.c	2011-08-12 16:18:04.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: eitscan.c 2.1 2010/02/07 12:12:05 kls Exp $
+ * $Id: eitscan.c 2.2 2011/08/12 14:18:04 kls Exp $
  */
 
 #include "eitscan.h"
@@ -133,12 +133,12 @@
         if (Channels.Lock(false, 10)) {
            if (!scanList) {
               scanList = new cScanList;
-              scanList->AddTransponders(&Channels);
               if (transponderList) {
                  scanList->AddTransponders(transponderList);
                  delete transponderList;
                  transponderList = NULL;
                  }
+              scanList->AddTransponders(&Channels);
               }
            bool AnyDeviceSwitched = false;
            for (int i = 0; i < cDevice::NumDevices(); i++) {
diff -ruN vdr-1.7.19/i18n.c vdr-1.7.20/i18n.c
--- vdr-1.7.19/i18n.c	2011-02-20 16:56:20.000000000 +0100
+++ vdr-1.7.20/i18n.c	2011-08-15 12:01:45.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: i18n.c 2.3 2011/02/20 15:56:20 kls Exp $
+ * $Id: i18n.c 2.4 2011/08/15 10:01:45 kls Exp $
  */
 
 /*
@@ -40,7 +40,7 @@
   "slv,slo",
   "ita",
   "dut,nla,nld",
-  "por",
+  "prt",
   "fra,fre",
   "nor",
   "fin,suo",
diff -ruN vdr-1.7.19/menu.c vdr-1.7.20/menu.c
--- vdr-1.7.19/menu.c	2011-02-27 13:37:48.000000000 +0100
+++ vdr-1.7.20/menu.c	2011-08-06 15:13:34.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: menu.c 2.28 2011/02/27 12:37:48 kls Exp $
+ * $Id: menu.c 2.29 2011/08/06 13:13:34 kls Exp $
  */
 
 #include "menu.h"
@@ -38,6 +38,7 @@
 #define NEWTIMERLIMIT   120 // seconds until the start time of a new timer created from the Schedule menu,
                             // within which it will go directly into the "Edit timer" menu to allow
                             // further parameter settings
+#define DEFERTIMER       60 // seconds by which a timer is deferred in case of problems
 
 #define MAXRECORDCONTROLS (MAXDEVICES * MAXRECEIVERS)
 #define MAXINSTANTRECTIME (24 * 60 - 1) // 23:59 hours
@@ -4134,6 +4135,8 @@
      else
         DELETENULL(recorder);
      }
+  else
+     timer->SetDeferred(DEFERTIMER);
   if (!Timer) {
      Timers.Del(timer);
      Timers.SetModified();
diff -ruN vdr-1.7.19/menuitems.c vdr-1.7.20/menuitems.c
--- vdr-1.7.19/menuitems.c	2011-06-13 16:48:41.000000000 +0200
+++ vdr-1.7.20/menuitems.c	2011-08-12 15:19:40.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: menuitems.c 2.9 2011/06/13 14:48:41 kls Exp $
+ * $Id: menuitems.c 2.10 2011/08/12 13:19:40 kls Exp $
  */
 
 #include "menuitems.h"
@@ -736,9 +736,14 @@
      cChannel *channel = Channels.GetByNumber(*value);
      snprintf(buf, sizeof(buf), "%d %s", *value, channel ? channel->Name() : "");
      SetValue(buf);
+     if (channelID)
+        *channelID = channel->GetChannelID().ToString();
      }
-  else if (noneString)
+  else if (noneString) {
      SetValue(noneString);
+     if (channelID)
+        *channelID = "";
+     }
 }
 
 eOSState cMenuEditChanItem::ProcessKey(eKeys Key)
diff -ruN vdr-1.7.19/nit.c vdr-1.7.20/nit.c
--- vdr-1.7.19/nit.c	2010-02-16 16:37:05.000000000 +0100
+++ vdr-1.7.20/nit.c	2011-08-12 16:27:31.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: nit.c 2.5 2010/02/16 15:37:05 kls Exp $
+ * $Id: nit.c 2.6 2011/08/12 14:27:31 kls Exp $
  */
 
 #include "nit.h"
@@ -150,6 +150,7 @@
                     }
                  if (Setup.UpdateChannels >= 5) {
                     bool found = false;
+                    bool forceTransponderUpdate = false;
                     for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
                         if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
                            int transponder = Channel->Transponder();
@@ -164,9 +165,11 @@
                               }
                            if (ISTRANSPONDER(cChannel::Transponder(Frequency, dtp.Polarization()), Transponder())) // only modify channels if we're actually receiving this transponder
                               Channel->SetTransponderData(Source, Frequency, SymbolRate, dtp.ToString('S'));
+                           else if (Channel->Srate() != SymbolRate || strcmp(Channel->Parameters(), dtp.ToString('S')))
+                              forceTransponderUpdate = true; // get us receiving this transponder
                            }
                         }
-                    if (!found) {
+                    if (!found || forceTransponderUpdate) {
                        for (int n = 0; n < NumFrequencies; n++) {
                            cChannel *Channel = new cChannel;
                            Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
@@ -202,6 +205,7 @@
                     }
                  if (Setup.UpdateChannels >= 5) {
                     bool found = false;
+                    bool forceTransponderUpdate = false;
                     for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
                         if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
                            int transponder = Channel->Transponder();
@@ -216,9 +220,11 @@
                               }
                            if (ISTRANSPONDER(Frequency / 1000, Transponder())) // only modify channels if we're actually receiving this transponder
                               Channel->SetTransponderData(Source, Frequency, SymbolRate, dtp.ToString('C'));
+                           else if (Channel->Srate() != SymbolRate || strcmp(Channel->Parameters(), dtp.ToString('C')))
+                              forceTransponderUpdate = true; // get us receiving this transponder
                            }
                         }
-                    if (!found) {
+                    if (!found || forceTransponderUpdate) {
                         for (int n = 0; n < NumFrequencies; n++) {
                            cChannel *Channel = new cChannel;
                            Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
@@ -261,6 +267,7 @@
                     }
                  if (Setup.UpdateChannels >= 5) {
                     bool found = false;
+                    bool forceTransponderUpdate = false;
                     for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
                         if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
                            int transponder = Channel->Transponder();
@@ -275,9 +282,11 @@
                               }
                            if (ISTRANSPONDER(Frequency / 1000000, Transponder())) // only modify channels if we're actually receiving this transponder
                               Channel->SetTransponderData(Source, Frequency, 0, dtp.ToString('T'));
+                           else if (strcmp(Channel->Parameters(), dtp.ToString('T')))
+                              forceTransponderUpdate = true; // get us receiving this transponder
                            }
                         }
-                    if (!found) {
+                    if (!found || forceTransponderUpdate) {
                        for (int n = 0; n < NumFrequencies; n++) {
                            cChannel *Channel = new cChannel;
                            Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
diff -ruN vdr-1.7.19/osd.c vdr-1.7.20/osd.c
--- vdr-1.7.19/osd.c	2011-06-02 14:00:17.000000000 +0200
+++ vdr-1.7.20/osd.c	2011-08-15 11:27:39.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.c 2.22 2011/06/02 12:00:17 kls Exp $
+ * $Id: osd.c 2.23 2011/08/15 09:27:39 kls Exp $
  */
 
 #include "osd.h"
@@ -1600,9 +1600,11 @@
 int cOsd::osdWidth = 0;
 int cOsd::osdHeight = 0;
 cVector<cOsd *> cOsd::Osds;
+cMutex cOsd::mutex;
 
 cOsd::cOsd(int Left, int Top, uint Level)
 {
+  cMutexLock MutexLock(&mutex);
   isTrueColor = false;
   savedBitmap = NULL;
   numBitmaps = 0;
@@ -1624,6 +1626,7 @@
 
 cOsd::~cOsd()
 {
+  cMutexLock MutexLock(&mutex);
   for (int i = 0; i < numBitmaps; i++)
       delete bitmaps[i];
   delete savedBitmap;
@@ -1944,6 +1947,7 @@
 
 cOsd *cOsdProvider::NewOsd(int Left, int Top, uint Level)
 {
+  cMutexLock MutexLock(&cOsd::mutex);
   if (Level == OSD_LEVEL_DEFAULT && cOsd::IsOpen())
      esyslog("ERROR: attempt to open OSD while it is already open - using dummy OSD!");
   else if (osdProvider) {
diff -ruN vdr-1.7.19/osd.h vdr-1.7.20/osd.h
--- vdr-1.7.19/osd.h	2011-04-17 16:24:32.000000000 +0200
+++ vdr-1.7.20/osd.h	2011-08-15 11:22:50.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.h 2.13 2011/04/17 14:24:32 kls Exp $
+ * $Id: osd.h 2.14 2011/08/15 09:22:50 kls Exp $
  */
 
 #ifndef __OSD_H
@@ -709,6 +709,7 @@
 private:
   static int osdLeft, osdTop, osdWidth, osdHeight;
   static cVector<cOsd *> Osds;
+  static cMutex mutex;
   bool isTrueColor;
   cBitmap *savedBitmap;
   cBitmap *bitmaps[MAXOSDAREAS];
diff -ruN vdr-1.7.19/recorder.c vdr-1.7.20/recorder.c
--- vdr-1.7.19/recorder.c	2011-06-12 16:16:45.000000000 +0200
+++ vdr-1.7.20/recorder.c	2011-08-13 16:56:36.000000000 +0200
@@ -4,13 +4,13 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recorder.c 2.11 2011/06/12 14:16:45 kls Exp $
+ * $Id: recorder.c 2.14 2011/08/13 14:56:36 kls Exp $
  */
 
 #include "recorder.h"
 #include "shutdown.h"
 
-#define RECORDERBUFSIZE  MEGABYTE(5)
+#define RECORDERBUFSIZE  (MEGABYTE(5) / TS_SIZE * TS_SIZE) // multiple of TS_SIZE
 
 // The maximum time we wait before assuming that a recorded video data stream
 // is broken:
@@ -88,7 +88,7 @@
 
 bool cRecorder::NextFile(void)
 {
-  if (recordFile && frameDetector->IndependentFrame()) { // every file shall start with an independent frame
+  if (recordFile) {
      if (fileSize > MEGABYTE(off_t(Setup.MaxVideoFileSize)) || RunningLowOnDiskSpace()) {
         recordFile = fileName->NextFile();
         fileSize = 0;
@@ -119,8 +119,11 @@
   time_t t = time(NULL);
   bool InfoWritten = false;
   bool FirstIframeSeen = false;
-  int FileNumber = 0;
-  off_t FrameOffset = -1;
+#define BUFFERSIZE (5 * TS_SIZE)
+  bool Buffering = false;
+  int BufferIndex = 0;
+  int MaxBufferIndex = 0;
+  uchar *Buffer = NULL;
   while (Running()) {
         int r;
         uchar *b = ringBuffer->Get(r);
@@ -141,16 +144,37 @@
                        }
                     InfoWritten = true;
                     }
-                 if (frameDetector->NewPayload()) {
-                    FileNumber = fileName->Number();
-                    FrameOffset = fileSize;
+                 if (frameDetector->NewPayload()) { // We're at the first TS packet of a new payload...
+                    if (Buffering)
+                       esyslog("ERROR: encountered new payload while buffering - dropping some data!");
+                    if (!frameDetector->NewFrame()) { // ...but the frame type is yet unknown, so we need to buffer packets until we see the frame type
+                       if (!Buffer) {
+                          dsyslog("frame type not in first packet of payload - buffering");
+                          if (!(Buffer = MALLOC(uchar, BUFFERSIZE))) {
+                             esyslog("ERROR: can't allocate frame type buffer");
+                             break;
+                             }
+                          }
+                       BufferIndex = 0;
+                       Buffering = true;
+                       }
                     }
-                 if (FirstIframeSeen || frameDetector->IndependentFrame()) {
+                 else if (frameDetector->NewFrame()) // now we know the frame type, so stop buffering
+                    Buffering = false;
+                 if (Buffering) {
+                    if (BufferIndex + Count <= BUFFERSIZE) {
+                       memcpy(Buffer + BufferIndex, b, Count);
+                       BufferIndex += Count;
+                       }
+                    else
+                       esyslog("ERROR: too many bytes for frame type buffer (%d > %d) - dropped %d bytes", BufferIndex + Count, int(BUFFERSIZE), Count);
+                    }
+                 else if (FirstIframeSeen || frameDetector->IndependentFrame()) {
                     FirstIframeSeen = true; // start recording with the first I-frame
-                    if (!NextFile())
+                    if (frameDetector->IndependentFrame() && !NextFile()) // every file shall start with an independent frame
                        break;
                     if (index && frameDetector->NewFrame())
-                       index->Write(frameDetector->IndependentFrame(), FileNumber, FrameOffset);
+                       index->Write(frameDetector->IndependentFrame(), fileName->Number(), fileSize);
                     if (frameDetector->IndependentFrame()) {
                        recordFile->Write(patPmtGenerator.GetPat(), TS_SIZE);
                        fileSize += TS_SIZE;
@@ -160,6 +184,12 @@
                              fileSize += TS_SIZE;
                              }
                        }
+                    if (BufferIndex) {
+                       recordFile->Write(Buffer, BufferIndex); // if an error occurs here, the next write below will catch and report it
+                       if (BufferIndex > MaxBufferIndex)
+                          MaxBufferIndex = BufferIndex;
+                       BufferIndex = 0;
+                       }
                     if (recordFile->Write(b, Count) < 0) {
                        LOG_ERROR_STR(fileName->Name());
                        break;
@@ -177,4 +207,8 @@
            t = time(NULL);
            }
         }
+  if (Buffer) {
+     free(Buffer);
+     dsyslog("frame type buffer used %d bytes", MaxBufferIndex);
+     }
 }
diff -ruN vdr-1.7.19/recording.c vdr-1.7.20/recording.c
--- vdr-1.7.19/recording.c	2011-06-12 15:04:28.000000000 +0200
+++ vdr-1.7.20/recording.c	2011-08-13 14:37:25.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recording.c 2.31 2011/06/12 13:04:28 kls Exp $
+ * $Id: recording.c 2.33 2011/08/13 12:37:25 kls Exp $
  */
 
 #include "recording.h"
@@ -1540,84 +1540,75 @@
 :resumeFile(FileName, IsPesRecording)
 {
   f = -1;
-  fileName = NULL;
   size = 0;
   last = -1;
   index = NULL;
   isPesRecording = IsPesRecording;
   indexFileGenerator = NULL;
   if (FileName) {
-     const char *Suffix = isPesRecording ? INDEXFILESUFFIX ".vdr" : INDEXFILESUFFIX;
-     fileName = MALLOC(char, strlen(FileName) + strlen(Suffix) + 1);
-     if (fileName) {
-        strcpy(fileName, FileName);
-        char *pFileExt = fileName + strlen(fileName);
-        strcpy(pFileExt, Suffix);
-        int delta = 0;
-        if (!Record && access(fileName, R_OK) != 0) {
-           // Index file doesn't exist, so try to regenerate it:
-           if (!isPesRecording) { // sorry, can only do this for TS recordings
-              resumeFile.Delete(); // just in case
-              indexFileGenerator = new cIndexFileGenerator(FileName);
-              // Wait until the index file exists:
-              time_t tmax = time(NULL) + MAXWAITFORINDEXFILE;
-              do {
-                 cCondWait::SleepMs(INDEXFILECHECKINTERVAL); // start with a sleep, to give it a head start
-                 } while (access(fileName, R_OK) != 0 && time(NULL) < tmax);
+     fileName = IndexFileName(FileName, isPesRecording);
+     int delta = 0;
+     if (!Record && access(fileName, R_OK) != 0) {
+        // Index file doesn't exist, so try to regenerate it:
+        if (!isPesRecording) { // sorry, can only do this for TS recordings
+           resumeFile.Delete(); // just in case
+           indexFileGenerator = new cIndexFileGenerator(FileName);
+           // Wait until the index file exists:
+           time_t tmax = time(NULL) + MAXWAITFORINDEXFILE;
+           do {
+              cCondWait::SleepMs(INDEXFILECHECKINTERVAL); // start with a sleep, to give it a head start
+              } while (access(fileName, R_OK) != 0 && time(NULL) < tmax);
+           }
+        }
+     if (access(fileName, R_OK) == 0) {
+        struct stat buf;
+        if (stat(fileName, &buf) == 0) {
+           delta = int(buf.st_size % sizeof(tIndexTs));
+           if (delta) {
+              delta = sizeof(tIndexTs) - delta;
+              esyslog("ERROR: invalid file size (%"PRId64") in '%s'", buf.st_size, *fileName);
               }
-           }
-        if (access(fileName, R_OK) == 0) {
-           struct stat buf;
-           if (stat(fileName, &buf) == 0) {
-              delta = int(buf.st_size % sizeof(tIndexTs));
-              if (delta) {
-                 delta = sizeof(tIndexTs) - delta;
-                 esyslog("ERROR: invalid file size (%"PRId64") in '%s'", buf.st_size, fileName);
-                 }
-              last = int((buf.st_size + delta) / sizeof(tIndexTs) - 1);
-              if (!Record && last >= 0) {
-                 size = last + 1;
-                 index = MALLOC(tIndexTs, size);
-                 if (index) {
-                    f = open(fileName, O_RDONLY);
-                    if (f >= 0) {
-                       if (safe_read(f, index, size_t(buf.st_size)) != buf.st_size) {
-                          esyslog("ERROR: can't read from file '%s'", fileName);
-                          free(index);
-                          index = NULL;
-                          close(f);
-                          f = -1;
-                          }
-                       // we don't close f here, see CatchUp()!
-                       else if (isPesRecording)
-                          ConvertFromPes(index, size);
+           last = int((buf.st_size + delta) / sizeof(tIndexTs) - 1);
+           if (!Record && last >= 0) {
+              size = last + 1;
+              index = MALLOC(tIndexTs, size);
+              if (index) {
+                 f = open(fileName, O_RDONLY);
+                 if (f >= 0) {
+                    if (safe_read(f, index, size_t(buf.st_size)) != buf.st_size) {
+                       esyslog("ERROR: can't read from file '%s'", *fileName);
+                       free(index);
+                       index = NULL;
+                       close(f);
+                       f = -1;
                        }
-                    else
-                       LOG_ERROR_STR(fileName);
+                    // we don't close f here, see CatchUp()!
+                    else if (isPesRecording)
+                       ConvertFromPes(index, size);
                     }
                  else
-                    esyslog("ERROR: can't allocate %zd bytes for index '%s'", size * sizeof(tIndexTs), fileName);
+                    LOG_ERROR_STR(*fileName);
                  }
+              else
+                 esyslog("ERROR: can't allocate %zd bytes for index '%s'", size * sizeof(tIndexTs), *fileName);
               }
-           else
-              LOG_ERROR;
            }
-        else if (!Record)
-           isyslog("missing index file %s", fileName);
-        if (Record) {
-           if ((f = open(fileName, O_WRONLY | O_CREAT | O_APPEND, DEFFILEMODE)) >= 0) {
-              if (delta) {
-                 esyslog("ERROR: padding index file with %d '0' bytes", delta);
-                 while (delta--)
-                       writechar(f, 0);
-                 }
+        else
+           LOG_ERROR;
+        }
+     else if (!Record)
+        isyslog("missing index file %s", *fileName);
+     if (Record) {
+        if ((f = open(fileName, O_WRONLY | O_CREAT | O_APPEND, DEFFILEMODE)) >= 0) {
+           if (delta) {
+              esyslog("ERROR: padding index file with %d '0' bytes", delta);
+              while (delta--)
+                    writechar(f, 0);
               }
-           else
-              LOG_ERROR_STR(fileName);
            }
+        else
+           LOG_ERROR_STR(*fileName);
         }
-     else
-        esyslog("ERROR: can't copy file name '%s'", FileName);
      }
 }
 
@@ -1625,11 +1616,15 @@
 {
   if (f >= 0)
      close(f);
-  free(fileName);
   free(index);
   delete indexFileGenerator;
 }
 
+cString cIndexFile::IndexFileName(const char *FileName, bool IsPesRecording)
+{
+  return cString::sprintf("%s%s", FileName, IsPesRecording ? INDEXFILESUFFIX ".vdr" : INDEXFILESUFFIX);
+}
+
 void cIndexFile::ConvertFromPes(tIndexTs *IndexTs, int Count)
 {
   tIndexPes IndexPes;
@@ -1696,7 +1691,7 @@
                      last = newLast;
                      }
                   else
-                     LOG_ERROR_STR(fileName);
+                     LOG_ERROR_STR(*fileName);
                   }
                else {
                   esyslog("ERROR: can't realloc() index");
@@ -1705,7 +1700,7 @@
                }
             }
          else
-            LOG_ERROR_STR(fileName);
+            LOG_ERROR_STR(*fileName);
          if (Index < last - (i ? 2 * INDEXSAFETYLIMIT : 0) || Index > 10 * INDEXSAFETYLIMIT) // keep off the end in case of "Pause live video"
             break;
          cCondWait::SleepMs(1000);
@@ -1721,7 +1716,7 @@
      if (isPesRecording)
         ConvertToPes(&i, 1);
      if (safe_write(f, &i, sizeof(i)) < 0) {
-        LOG_ERROR_STR(fileName);
+        LOG_ERROR_STR(*fileName);
         close(f);
         f = -1;
         return false;
@@ -1811,8 +1806,8 @@
 
 void cIndexFile::Delete(void)
 {
-  if (fileName) {
-     dsyslog("deleting index file '%s'", fileName);
+  if (*fileName) {
+     dsyslog("deleting index file '%s'", *fileName);
      if (f >= 0) {
         close(f);
         f = -1;
@@ -1821,6 +1816,15 @@
      }
 }
 
+int cIndexFile::GetLength(const char *FileName, bool IsPesRecording)
+{
+  struct stat buf;
+  cString s = IndexFileName(FileName, IsPesRecording);
+  if (*s && stat(s, &buf) == 0)
+     return buf.st_size / (IsPesRecording ? sizeof(tIndexTs) : sizeof(tIndexPes));
+  return -1;
+}
+
 bool GenerateIndex(const char *FileName) 
 {
   if (DirectoryOk(FileName)) {
diff -ruN vdr-1.7.19/recording.h vdr-1.7.20/recording.h
--- vdr-1.7.19/recording.h	2011-04-17 15:18:04.000000000 +0200
+++ vdr-1.7.20/recording.h	2011-08-13 14:51:23.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recording.h 2.19 2011/04/17 13:18:04 kls Exp $
+ * $Id: recording.h 2.22 2011/08/13 12:51:23 kls Exp $
  */
 
 #ifndef __RECORDING_H
@@ -120,15 +120,15 @@
   void ReadInfo(void);
   bool WriteInfo(void);
   bool Delete(void);
-       // Changes the file name so that it will no longer be visible in the "Recordings" menu
-       // Returns false in case of error
+       ///< Changes the file name so that it will no longer be visible in the "Recordings" menu
+       ///< Returns false in case of error
   bool Remove(void);
-       // Actually removes the file from the disk
-       // Returns false in case of error
+       ///< Actually removes the file from the disk
+       ///< Returns false in case of error
   bool Undelete(void);
-       // Changes the file name so that it will be visible in the "Recordings" menu again and
-       // not processed by cRemoveDeletedRecordingsThread.
-       // Returns false in case of error
+       ///< Changes the file name so that it will be visible in the "Recordings" menu again and
+       ///< not processed by cRemoveDeletedRecordingsThread.
+       ///< Returns false in case of error
   };
 
 class cRecordings : public cList<cRecording>, public cThread {
@@ -236,13 +236,14 @@
 class cIndexFile {
 private:
   int f;
-  char *fileName;
+  cString fileName;
   int size, last;
   tIndexTs *index;
   bool isPesRecording;
   cResumeFile resumeFile;
   cIndexFileGenerator *indexFileGenerator;
   cMutex mutex;
+  static cString IndexFileName(const char *FileName, bool IsPesRecording);
   void ConvertFromPes(tIndexTs *IndexTs, int Count);
   void ConvertToPes(tIndexTs *IndexTs, int Count);
   bool CatchUp(int Index = -1);
@@ -259,6 +260,9 @@
   bool StoreResume(int Index) { return resumeFile.Save(Index); }
   bool IsStillRecording(void);
   void Delete(void);
+  static int GetLength(const char *FileName, bool IsPesRecording = false);
+       ///< Calculates the recording length (numer of frames) without actually reading the index file.
+       ///< Returns -1 in case of error.
   };
 
 class cFileName {
diff -ruN vdr-1.7.19/remote.c vdr-1.7.20/remote.c
--- vdr-1.7.19/remote.c	2011-03-27 17:03:36.000000000 +0200
+++ vdr-1.7.20/remote.c	2011-08-15 15:41:40.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: remote.c 2.3 2011/03/27 15:03:36 kls Exp $
+ * $Id: remote.c 2.4 2011/08/15 13:41:40 kls Exp $
  */
 
 #include "remote.h"
@@ -26,7 +26,7 @@
 eKeys cRemote::keys[MaxKeys];
 int cRemote::in = 0;
 int cRemote::out = 0;
-cTimeMs cRemote::repeatTimeout;
+cTimeMs cRemote::repeatTimeout(-1);
 cRemote *cRemote::learning = NULL;
 char *cRemote::unknownCode = NULL;
 cMutex cRemote::mutex;
diff -ruN vdr-1.7.19/remux.c vdr-1.7.20/remux.c
--- vdr-1.7.19/remux.c	2011-06-12 16:24:09.000000000 +0200
+++ vdr-1.7.20/remux.c	2011-08-15 11:50:14.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: remux.c 2.57 2011/06/12 14:24:09 kls Exp $
+ * $Id: remux.c 2.58 2011/08/15 09:50:14 kls Exp $
  */
 
 #include "remux.h"
@@ -135,8 +135,11 @@
         if (!Processed[Pid]) {
            if (!TsPayloadStart(p))
               p[1] |= TS_ERROR;
-           else
+           else {
               Processed[Pid] = true;
+              int offs = TsPayloadOffset(p);
+              cRemux::SetBrokenLink(p + offs, TS_SIZE - offs);
+              }
            }
         l -= TS_SIZE;
         p += TS_SIZE;
diff -ruN vdr-1.7.19/skins.c vdr-1.7.20/skins.c
--- vdr-1.7.19/skins.c	2009-06-06 17:12:31.000000000 +0200
+++ vdr-1.7.20/skins.c	2011-08-06 11:41:57.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: skins.c 2.1 2009/06/06 15:12:31 kls Exp $
+ * $Id: skins.c 2.2 2011/08/06 09:41:57 kls Exp $
  */
 
 #include "skins.h"
@@ -223,6 +223,10 @@
 
 eKeys cSkins::Message(eMessageType Type, const char *s, int Seconds)
 {
+  if (!cThread::IsMainThread()) {
+     dsyslog("cSkins::Message() called from background thread - ignored! (Use cSkins::QueueMessage() instead)");
+     return kNone;
+     }
   switch (Type) {
     case mtInfo:    isyslog("info: %s", s); break;
     case mtWarning: isyslog("warning: %s", s); break;
diff -ruN vdr-1.7.19/svdrpsend.pl vdr-1.7.20/svdrpsend.pl
--- vdr-1.7.19/svdrpsend.pl	2010-04-02 14:22:01.000000000 +0200
+++ vdr-1.7.20/svdrpsend.pl	2011-08-06 11:48:37.000000000 +0200
@@ -52,6 +52,6 @@
 {
   print STDERR "@_\n";
   close(SOCK);
-  exit 0;
+  exit 1;
 }
 
diff -ruN vdr-1.7.19/timers.c vdr-1.7.20/timers.c
--- vdr-1.7.19/timers.c	2010-01-16 12:18:53.000000000 +0100
+++ vdr-1.7.20/timers.c	2011-08-06 15:13:54.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: timers.c 2.4 2010/01/16 11:18:53 kls Exp $
+ * $Id: timers.c 2.5 2011/08/06 13:13:54 kls Exp $
  */
 
 #include "timers.h"
@@ -29,6 +29,7 @@
 {
   startTime = stopTime = 0;
   lastSetEvent = 0;
+  deferred = 0;
   recording = pending = inVpsMargin = false;
   flags = tfNone;
   if (Instant)
@@ -62,6 +63,7 @@
 {
   startTime = stopTime = 0;
   lastSetEvent = 0;
+  deferred = 0;
   recording = pending = inVpsMargin = false;
   flags = tfActive;
   if (Event->Vps() && Setup.UseVps)
@@ -118,6 +120,7 @@
      startTime    = Timer.startTime;
      stopTime     = Timer.stopTime;
      lastSetEvent = 0;
+     deferred = 0;
      recording    = Timer.recording;
      pending      = Timer.pending;
      inVpsMargin  = Timer.inVpsMargin;
@@ -422,6 +425,10 @@
         day = 0;
      }
 
+  if (t < deferred)
+     return false;
+  deferred = 0;
+
   if (HasFlags(tfActive)) {
      if (HasFlags(tfVps) && event && event->Vps()) {
         if (Margin || !Directly) {
@@ -589,6 +596,12 @@
   priority = Priority;
 }
 
+void cTimer::SetDeferred(int Seconds)
+{
+  deferred = time(NULL) + Seconds;
+  isyslog("timer %s deferred for %d seconds", *ToDescr(), Seconds);
+}
+
 void cTimer::SetFlags(uint Flags)
 {
   flags |= Flags;
diff -ruN vdr-1.7.19/timers.h vdr-1.7.20/timers.h
--- vdr-1.7.19/timers.h	2008-02-16 15:33:23.000000000 +0100
+++ vdr-1.7.20/timers.h	2011-08-06 14:59:32.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: timers.h 2.0 2008/02/16 14:33:23 kls Exp $
+ * $Id: timers.h 2.1 2011/08/06 12:59:32 kls Exp $
  */
 
 #ifndef __TIMERS_H
@@ -29,6 +29,7 @@
 private:
   mutable time_t startTime, stopTime;
   time_t lastSetEvent;
+  mutable time_t deferred; ///< Matches(time_t, ...) will return false if the current time is before this value
   bool recording, pending, inVpsMargin;
   uint flags;
   cChannel *channel;
@@ -62,6 +63,7 @@
   const char *File(void) const { return file; }
   time_t FirstDay(void) const { return weekdays ? day : 0; }
   const char *Aux(void) const { return aux; }
+  time_t Deferred(void) const { return deferred; }
   cString ToText(bool UseChannelID = false) const;
   cString ToDescr(void) const;
   const cEvent *Event(void) const { return event; }
@@ -85,6 +87,7 @@
   void SetPending(bool Pending);
   void SetInVpsMargin(bool InVpsMargin);
   void SetPriority(int Priority);
+  void SetDeferred(int Seconds);
   void SetFlags(uint Flags);
   void ClrFlags(uint Flags);
   void InvFlags(uint Flags);
diff -ruN vdr-1.7.19/tools.c vdr-1.7.20/tools.c
--- vdr-1.7.19/tools.c	2011-04-29 16:51:14.000000000 +0200
+++ vdr-1.7.20/tools.c	2011-08-15 15:35:23.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: tools.c 2.14 2011/04/29 14:51:14 kls Exp $
+ * $Id: tools.c 2.17 2011/08/15 13:35:23 kls Exp $
  */
 
 #include "tools.h"
@@ -261,7 +261,7 @@
 
 bool isnumber(const char *s)
 {
-  if (!*s)
+  if (!s || !*s)
      return false;
   do {
      if (!isdigit(*s))
@@ -270,6 +270,21 @@
   return true;
 }
 
+int64_t StrToNum(const char *s)
+{
+  char *t = NULL;
+  int64_t n = strtoll(s, &t, 10);
+  if (t) {
+     switch (*t) {
+       case 'T': n *= 1024;
+       case 'G': n *= 1024;
+       case 'M': n *= 1024;
+       case 'K': n *= 1024;
+       }
+     }
+  return n;
+}
+
 cString AddDirectory(const char *DirName, const char *FileName)
 {
   return cString::sprintf("%s/%s", DirName && *DirName ? DirName : ".", FileName);
@@ -556,7 +571,10 @@
 
 cTimeMs::cTimeMs(int Ms)
 {
-  Set(Ms);
+  if (Ms >= 0)
+     Set(Ms);
+  else
+     begin = 0;
 }
 
 uint64_t cTimeMs::Now(void)
diff -ruN vdr-1.7.19/tools.h vdr-1.7.20/tools.h
--- vdr-1.7.19/tools.h	2011-02-25 16:05:58.000000000 +0100
+++ vdr-1.7.20/tools.h	2011-08-15 16:13:42.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: tools.h 2.7 2011/02/25 15:05:58 kls Exp $
+ * $Id: tools.h 2.11 2011/08/15 14:13:42 kls Exp $
  */
 
 #ifndef __TOOLS_H
@@ -45,7 +45,7 @@
 
 #define MALLOC(type, size)  (type *)malloc(sizeof(type) * (size))
 
-#define DELETENULL(p) (delete (p), p = NULL)
+template<class T> inline void DELETENULL(T *&p) { T *q = p; p = NULL; delete q; } 
 
 #define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls
 #define FATALERRNO (errno && errno != EAGAIN && errno != EINTR)
@@ -205,6 +205,12 @@
 bool isempty(const char *s);
 int numdigits(int n);
 bool isnumber(const char *s);
+int64_t StrToNum(const char *s);
+    ///< Converts the given string to a number.
+    ///< The numerical part of the string may be followed by one of the letters
+    ///< K, M, G or T to abbreviate Kilo-, Mega-, Giga- or Terabyte, respectively
+    ///< (based on 1024). Everything after the first non-numeric character is
+    ///< silently ignored, as are any characters other than the ones mentionend here.
 cString itoa(int n);
 cString AddDirectory(const char *DirName, const char *FileName);
 bool EntriesOnSameFileSystem(const char *File1, const char *File2);
@@ -266,6 +272,8 @@
 public:
   cTimeMs(int Ms = 0);
       ///< Creates a timer with ms resolution and an initial timeout of Ms.
+      ///< If Ms is negative the timer is not initialized with the current
+      ///< time.
   static uint64_t Now(void);
   void Set(int Ms = 0);
   bool TimedOut(void);
@@ -506,12 +514,23 @@
   return strcmp(*(const char **)a, *(const char **)b);
 }
 
+inline int CompareStringsIgnoreCase(const void *a, const void *b)
+{
+  return strcasecmp(*(const char **)a, *(const char **)b);
+}
+
 class cStringList : public cVector<char *> {
 public:
   cStringList(int Allocated = 10): cVector<char *>(Allocated) {}
   virtual ~cStringList();
   int Find(const char *s) const;
-  void Sort(void) { cVector<char *>::Sort(CompareStrings); }
+  void Sort(bool IgnoreCase = false)
+  {
+    if (IgnoreCase)
+       cVector<char *>::Sort(CompareStringsIgnoreCase);
+    else
+       cVector<char *>::Sort(CompareStrings);
+  }
   virtual void Clear(void);
   };
 
diff -ruN vdr-1.7.19/vdr.1 vdr-1.7.20/vdr.1
--- vdr-1.7.19/vdr.1	2010-04-02 14:22:08.000000000 +0200
+++ vdr-1.7.20/vdr.1	2011-08-15 14:28:54.000000000 +0200
@@ -8,7 +8,7 @@
 .\" License as specified in the file COPYING that comes with the
 .\" vdr distribution.
 .\"
-.\" $Id: vdr.1 2.5 2010/04/02 12:22:08 kls Exp $
+.\" $Id: vdr.1 2.6 2011/08/15 12:28:54 kls Exp $
 .\"
 .TH vdr 1 "10 Feb 2008" "1.6" "Video Disk Recorder"
 .SH NAME
@@ -66,6 +66,15 @@
 If \fIfile\fR is a directory, the file \fIepg.data\fR
 will be created in that directory.
 .TP
+.BI \-\-filesize= size
+Limit video files to \fIsize\fR bytes (default is 2000M).
+This option is only useful in conjunction with --edit, and must precede that
+option to have an effect.
+\fIsize\fR is an integer number and may be followed by one of the letters K, M, G or T
+to abbreviate Kilo-, Mega-, Giga- or Terabyte, respectively.
+The given value is silently limited to the program's internal minimum and
+maximum values.
+.TP
 .BI \-\-genindex= rec
 Generate the index file for the given recording.
 \fIrec\fR must be the full path name of an existing recording.
@@ -157,6 +166,11 @@
 Call \fIcmd\fR to shutdown the computer. See the file \fIINSTALL\fR for more
 information.
 .TP
+.BI \-\-split
+Split edited files at the editing marks.
+This option is only useful in conjunction with --edit, and must precede that
+option to have an effect.
+.TP
 .BI \-t\  tty ,\ \-\-terminal= tty
 Set the controlling terminal.
 .TP
diff -ruN vdr-1.7.19/vdr.c vdr-1.7.20/vdr.c
--- vdr-1.7.19/vdr.c	2011-06-13 16:40:12.000000000 +0200
+++ vdr-1.7.20/vdr.c	2011-08-15 14:42:39.000000000 +0200
@@ -22,7 +22,7 @@
  *
  * The project's page is at http://www.tvdr.de
  *
- * $Id: vdr.c 2.21 2011/06/13 14:40:12 kls Exp $
+ * $Id: vdr.c 2.23 2011/08/15 12:42:39 kls Exp $
  */
 
 #include <getopt.h>
@@ -223,6 +223,7 @@
       { "device",   required_argument, NULL, 'D' },
       { "edit",     required_argument, NULL, 'e' | 0x100 },
       { "epgfile",  required_argument, NULL, 'E' },
+      { "filesize", required_argument, NULL, 'f' | 0x100 },
       { "genindex", required_argument, NULL, 'g' | 0x100 },
       { "grab",     required_argument, NULL, 'g' },
       { "help",     no_argument,       NULL, 'h' },
@@ -238,6 +239,7 @@
       { "rcu",      optional_argument, NULL, 'r' | 0x100 },
       { "record",   required_argument, NULL, 'r' },
       { "shutdown", required_argument, NULL, 's' },
+      { "split",    no_argument,       NULL, 's' | 0x100 },
       { "terminal", required_argument, NULL, 't' },
       { "user",     required_argument, NULL, 'u' },
       { "userdump", no_argument,       NULL, 'u' | 0x100 },
@@ -270,6 +272,13 @@
                     return CutRecording(optarg) ? 0 : 2;
           case 'E': EpgDataFileName = (*optarg != '-' ? optarg : NULL);
                     break;
+          case 'f' | 0x100:
+                    Setup.MaxVideoFileSize = StrToNum(optarg) / MEGABYTE(1);
+                    if (Setup.MaxVideoFileSize < MINVIDEOFILESIZE)
+                       Setup.MaxVideoFileSize = MINVIDEOFILESIZE;
+                    if (Setup.MaxVideoFileSize > MAXVIDEOFILESIZETS)
+                       Setup.MaxVideoFileSize = MAXVIDEOFILESIZETS;
+                    break;
           case 'g' | 0x100:
                     return GenerateIndex(optarg) ? 0 : 2;
           case 'g': cSVDRP::SetGrabImageDir(*optarg != '-' ? optarg : NULL);
@@ -348,6 +357,9 @@
                     break;
           case 's': ShutdownHandler.SetShutdownCommand(optarg);
                     break;
+          case 's' | 0x100:
+                    Setup.SplitEditedFiles = 1;
+                    break;
           case 't': Terminal = optarg;
                     if (access(Terminal, R_OK | W_OK) < 0) {
                        fprintf(stderr, "vdr: can't access terminal: %s\n", Terminal);
@@ -419,6 +431,8 @@
                "                           '-E-' disables this\n"
                "                           if FILE is a directory, the default EPG file will be\n"
                "                           created in that directory\n"
+               "            --filesize=SIZE limit video files to SIZE bytes (default is %dM)\n"
+               "                           only useful in conjunction with --edit\n"
                "            --genindex=REC generate index for recording REC and exit\n"
                "  -g DIR,   --grab=DIR     write images from the SVDRP command GRAB into the\n"
                "                           given DIR; DIR must be the full path name of an\n"
@@ -445,6 +459,8 @@
                "                           (default: %s)\n"
                "  -r CMD,   --record=CMD   call CMD before and after a recording\n"
                "  -s CMD,   --shutdown=CMD call CMD to shutdown the computer\n"
+               "            --split        split edited files at the editing marks (only\n"
+               "                           useful in conjunction with --edit)\n"
                "  -t TTY,   --terminal=TTY controlling tty\n"
                "  -u USER,  --user=USER    run as user USER; only applicable if started as\n"
                "                           root\n"
@@ -458,6 +474,7 @@
                "\n",
                DEFAULTCONFDIR,
                DEFAULTEPGDATAFILENAME,
+               MAXVIDEOFILESIZEDEFAULT,
                DEFAULTPLUGINDIR,
                LIRC_DEVICE,
                LOCDIR,
@@ -704,12 +721,14 @@
 
   if (!cDevice::WaitForAllDevicesReady(DEVICEREADYTIMEOUT))
      dsyslog("not all devices ready after %d seconds", DEVICEREADYTIMEOUT);
-  if (isnumber(Setup.InitialChannel)) { // for compatibility with old setup.conf files
-     if (cChannel *Channel = Channels.GetByNumber(atoi(Setup.InitialChannel)))
-        Setup.InitialChannel = Channel->GetChannelID().ToString();
+  if (*Setup.InitialChannel) {
+     if (isnumber(Setup.InitialChannel)) { // for compatibility with old setup.conf files
+        if (cChannel *Channel = Channels.GetByNumber(atoi(Setup.InitialChannel)))
+           Setup.InitialChannel = Channel->GetChannelID().ToString();
+        }
+     if (cChannel *Channel = Channels.GetByChannelID(tChannelID::FromString(Setup.InitialChannel)))
+        Setup.CurrentChannel = Channel->Number();
      }
-  if (cChannel *Channel = Channels.GetByChannelID(tChannelID::FromString(Setup.InitialChannel)))
-     Setup.CurrentChannel = Channel->Number();
   if (Setup.InitialVolume >= 0)
      Setup.CurrentVolume = Setup.InitialVolume;
   Channels.SwitchTo(Setup.CurrentChannel);
