diff options
author | Klaus Schmidinger <Klaus (dot) Schmidinger (at) tvdr (dot) de> | 2011-08-16 18:57:00 +0200 |
---|---|---|
committer | Dieter Hametner <dh (plus) vdr (at) gekrumbel (dot) de> | 2011-08-16 20:32:01 +0200 |
commit | 7df66b05874339d23c1ce35387a8d55579891a22 (patch) | |
tree | d93d4dadeefe0929817012be6786b39f916d7e72 | |
parent | bd61fee1e9328aec470c319494cccb90e53302c2 (diff) | |
download | vdr-patches-7df66b05874339d23c1ce35387a8d55579891a22.tar.gz vdr-patches-7df66b05874339d23c1ce35387a8d55579891a22.tar.bz2 |
Version 1.7.20
Original announce message:
VDR developer version 1.7.20 is now available at
ftp://ftp.tvdr.de/vdr/Developer/vdr-1.7.20.tar.bz2
A 'diff' against the previous version is available at
ftp://ftp.tvdr.de/vdr/Developer/vdr-1.7.19-1.7.20.diff
MD5 checksums:
eda2911fff1715ba5b1482b20ad18188 vdr-1.7.20.tar.bz2
a8f5bcaf3294cc9fce87283a618d5ce1 vdr-1.7.19-1.7.20.diff
WARNING:
========
This is a developer version. Even though I use it in my productive
environment. I strongly recommend that you only use it under controlled
conditions and for testing and debugging.
This version contains functions to determine the "signal strength"
and "signal quality" through cDevice. If you are using a DVB card that
contains an stb0899 frontend chip (like the TT-budget S2-3200) you may
want to apply the patches from
ftp://ftp.tvdr.de/vdr/Developer/Driver-Patches
to the LinuxDVB driver source in order to receive useful results from
that frontend.
From the HISTORY file:
- 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).
-rw-r--r-- | CONTRIBUTORS | 34 | ||||
-rw-r--r-- | HISTORY | 51 | ||||
-rw-r--r-- | MANUAL | 2 | ||||
-rw-r--r-- | PLUGINS/src/dvbhddevice/po/it_IT.po | 93 | ||||
-rw-r--r-- | PLUGINS/src/pictures/HISTORY | 10 | ||||
-rwxr-xr-x | PLUGINS/src/pictures/pic2mpg | 91 | ||||
-rwxr-xr-x | PLUGINS/src/pictures/pic2mpg-sd | 193 | ||||
-rw-r--r-- | channels.h | 14 | ||||
-rw-r--r-- | config.h | 10 | ||||
-rw-r--r-- | diseqc.c | 6 | ||||
-rw-r--r-- | dvbsubtitle.c | 20 | ||||
-rw-r--r-- | eitscan.c | 4 | ||||
-rw-r--r-- | epg.data | 0 | ||||
-rw-r--r-- | i18n.c | 4 | ||||
-rw-r--r-- | menu.c | 5 | ||||
-rw-r--r-- | menuitems.c | 9 | ||||
-rw-r--r-- | nit.c | 17 | ||||
-rw-r--r-- | osd.c | 6 | ||||
-rw-r--r-- | osd.h | 3 | ||||
-rw-r--r-- | recorder.c | 56 | ||||
-rw-r--r-- | recording.c | 142 | ||||
-rw-r--r-- | recording.h | 22 | ||||
-rw-r--r-- | remote.c | 4 | ||||
-rw-r--r-- | remux.c | 7 | ||||
-rw-r--r-- | skins.c | 6 | ||||
-rwxr-xr-x | svdrpsend.pl | 2 | ||||
-rw-r--r-- | timers.c | 15 | ||||
-rw-r--r-- | timers.h | 5 | ||||
-rw-r--r-- | tools.c | 24 | ||||
-rw-r--r-- | tools.h | 25 | ||||
-rw-r--r-- | vdr.1 | 16 | ||||
-rw-r--r-- | vdr.c | 31 |
32 files changed, 717 insertions, 210 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS index b9cc382..2aa2c21 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -678,6 +678,7 @@ Oliver Endriss <o.endriss@gmx.de> 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 @@ Rolf Ahrenberg <rahrenbe@cc.hut.fi> 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 @@ Reinhard Nissl <rnissl@gmx.de> 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 @@ Udo Richter <udo_richter@gmx.de> "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 @@ André Weidemann <Andre.Weidemann@web.de> 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 @@ Christoph Haubrich <christoph1.haubrich@arcor.de> 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 @@ Johan Schuring <johan.schuring@vetteblei.nl> 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 @@ Dirk Leber <dirk.leber@reel-multimedia.com> 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 @@ Johan Andersson <jna@jna.pp.se> 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 @@ -6305,7 +6305,7 @@ Video Disk Recorder Revision History 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 @@ Video Disk Recorder Revision History 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). @@ -822,7 +822,7 @@ Version 1.6 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 --git a/PLUGINS/src/dvbhddevice/po/it_IT.po b/PLUGINS/src/dvbhddevice/po/it_IT.po new file mode 100644 index 0000000..a328312 --- /dev/null +++ b/PLUGINS/src/dvbhddevice/po/it_IT.po @@ -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 --git a/PLUGINS/src/pictures/HISTORY b/PLUGINS/src/pictures/HISTORY index 332d77c..964ab2e 100644 --- a/PLUGINS/src/pictures/HISTORY +++ b/PLUGINS/src/pictures/HISTORY @@ -45,3 +45,13 @@ VDR Plugin 'pictures' Revision History 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 --git a/PLUGINS/src/pictures/pic2mpg b/PLUGINS/src/pictures/pic2mpg index d317510..190ec26 100755 --- a/PLUGINS/src/pictures/pic2mpg +++ b/PLUGINS/src/pictures/pic2mpg @@ -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; - -# Converter programs: - -%PNMCONV = ( - bmp => "bmptopnm", - gif => "giftopnm", - jpeg => "jpegtopnm", - jpg => "jpegtopnm", - png => "pngtopnm", - pnm => "cat", - tif => "tifftopnm", - tiff => "tifftopnm", +# Supported picture types: + +%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: 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]) { @@ -95,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) { @@ -145,29 +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); - 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 --git a/PLUGINS/src/pictures/pic2mpg-sd b/PLUGINS/src/pictures/pic2mpg-sd new file mode 100755 index 0000000..6213091 --- /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 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; +} @@ -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 @@ public: 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; @@ -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 @@ -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 @@ const char *cDiseqc::Codes(const char *s) const 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 --git a/dvbsubtitle.c b/dvbsubtitle.c index de1cd1c..43d072d 100644 --- a/dvbsubtitle.c +++ b/dvbsubtitle.c @@ -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 @@ void cDvbSubtitleConverter::Action(void) while (Running()) { int WaitMs = 100; if (!frozen) { + LOCK_THREAD; if (osd) { int NewSetupLevel = setupLevel; if (Timeout.TimedOut() || LastSetupLevel != NewSetupLevel) { @@ -833,7 +834,6 @@ void cDvbSubtitleConverter::Action(void) } 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 @@ void cDvbSubtitleConverter::Action(void) else bitmaps->Del(sb); } - Unlock(); } cCondWait::SleepMs(WaitMs); } @@ -902,6 +901,7 @@ void cDvbSubtitleConverter::SetOsdData(void) 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 @@ int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t 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 @@ void cDvbSubtitleConverter::FinishPage(cDvbSubtitlePage *Page) 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 @@ void cDvbSubtitleConverter::FinishPage(cDvbSubtitlePage *Page) 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); + } } } @@ -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 @@ void cEITScanner::Process(void) 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 --git a/epg.data b/epg.data new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/epg.data @@ -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 @@ const char *LanguageCodeList[] = { "slv,slo", "ita", "dut,nla,nld", - "por", + "prt", "fra,fre", "nor", "fin,suo", @@ -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 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause) else DELETENULL(recorder); } + else + timer->SetDeferred(DEFERTIMER); if (!Timer) { Timers.Del(timer); Timers.SetModified(); diff --git a/menuitems.c b/menuitems.c index bc04e72..e7797d6 100644 --- a/menuitems.c +++ b/menuitems.c @@ -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 @@ void cMenuEditChanItem::Set(void) 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) @@ -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 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length } 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 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length } 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 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length } 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 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length } 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 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length } 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 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length } 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); @@ -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::osdTop = 0; 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(int Left, int Top, uint Level) cOsd::~cOsd() { + cMutexLock MutexLock(&mutex); for (int i = 0; i < numBitmaps; i++) delete bitmaps[i]; delete savedBitmap; @@ -1944,6 +1947,7 @@ cOsdProvider::~cOsdProvider() 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) { @@ -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 @@ class cOsd { private: static int osdLeft, osdTop, osdWidth, osdHeight; static cVector<cOsd *> Osds; + static cMutex mutex; bool isTrueColor; cBitmap *savedBitmap; cBitmap *bitmaps[MAXOSDAREAS]; @@ -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::RunningLowOnDiskSpace(void) 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 @@ void cRecorder::Action(void) 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 @@ void cRecorder::Action(void) } 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 @@ void cRecorder::Action(void) 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 @@ void cRecorder::Action(void) t = time(NULL); } } + if (Buffer) { + free(Buffer); + dsyslog("frame type buffer used %d bytes", MaxBufferIndex); + } } diff --git a/recording.c b/recording.c index a8b40f2..4456bdd 100644 --- a/recording.c +++ b/recording.c @@ -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 @@ cIndexFile::cIndexFile(const char *FileName, bool Record, bool IsPesRecording) :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); - } - 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); + } + 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; } - 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 @@ cIndexFile::~cIndexFile() { 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 @@ bool cIndexFile::CatchUp(int Index) last = newLast; } else - LOG_ERROR_STR(fileName); + LOG_ERROR_STR(*fileName); } else { esyslog("ERROR: can't realloc() index"); @@ -1705,7 +1700,7 @@ bool cIndexFile::CatchUp(int Index) } } 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 @@ bool cIndexFile::Write(bool Independent, uint16_t FileNumber, off_t FileOffset) 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 @@ bool cIndexFile::IsStillRecording() 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 @@ void cIndexFile::Delete(void) } } +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 --git a/recording.h b/recording.h index 8ec7f49..578dd45 100644 --- a/recording.h +++ b/recording.h @@ -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 @@ public: 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 cIndexFileGenerator; 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 @@ public: 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 { @@ -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; @@ -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 @@ void TsSetTeiOnBrokenPackets(uchar *p, int l) 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; @@ -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 @@ bool cSkins::SetCurrent(const char *Name) 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 --git a/svdrpsend.pl b/svdrpsend.pl index 03d78fe..caf3b41 100755 --- a/svdrpsend.pl +++ b/svdrpsend.pl @@ -52,6 +52,6 @@ sub Error { print STDERR "@_\n"; close(SOCK); - exit 0; + exit 1; } @@ -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 @@ cTimer::cTimer(bool Instant, bool Pause, cChannel *Channel) { startTime = stopTime = 0; lastSetEvent = 0; + deferred = 0; recording = pending = inVpsMargin = false; flags = tfNone; if (Instant) @@ -62,6 +63,7 @@ cTimer::cTimer(const cEvent *Event) { startTime = stopTime = 0; lastSetEvent = 0; + deferred = 0; recording = pending = inVpsMargin = false; flags = tfActive; if (Event->Vps() && Setup.UseVps) @@ -118,6 +120,7 @@ cTimer& cTimer::operator= (const cTimer &Timer) startTime = Timer.startTime; stopTime = Timer.stopTime; lastSetEvent = 0; + deferred = 0; recording = Timer.recording; pending = Timer.pending; inVpsMargin = Timer.inVpsMargin; @@ -422,6 +425,10 @@ bool cTimer::Matches(time_t t, bool Directly, int Margin) const 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 @@ void cTimer::SetPriority(int Priority) 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; @@ -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 @@ class cTimer : public cListObject { 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 @@ public: 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 @@ public: 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); @@ -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 @@ int numdigits(int n) bool isnumber(const char *s) { - if (!*s) + if (!s || !*s) return false; do { if (!isdigit(*s)) @@ -270,6 +270,21 @@ bool isnumber(const char *s) 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 @@ time_t LastModifiedTime(const char *FileName) cTimeMs::cTimeMs(int Ms) { - Set(Ms); + if (Ms >= 0) + Set(Ms); + else + begin = 0; } uint64_t cTimeMs::Now(void) @@ -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 @@ extern int SysLogLevel; #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 endswith(const char *s, const char *p); 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 @@ private: 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 @@ inline int CompareStrings(const void *a, const void *b) 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); }; @@ -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 @@ Use \fB\-E\-\fR to disable this. 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 @@ more information. 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 @@ -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 @@ int main(int argc, char *argv[]) { "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 @@ int main(int argc, char *argv[]) { "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 @@ int main(int argc, char *argv[]) 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 @@ int main(int argc, char *argv[]) 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 @@ int main(int argc, char *argv[]) " '-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 @@ int main(int argc, char *argv[]) " (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 @@ int main(int argc, char *argv[]) "\n", DEFAULTCONFDIR, DEFAULTEPGDATAFILENAME, + MAXVIDEOFILESIZEDEFAULT, DEFAULTPLUGINDIR, LIRC_DEVICE, LOCDIR, @@ -704,12 +721,14 @@ int main(int argc, char *argv[]) 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); |